Processing mod_wsgi.input - python

I am newbie in python and mod_wsgi development. When I want to get data from POST i read envron['wsgi.input'] and as a result I get name=username&fullname=name&pass=password. Now my question is how to split it to get that input as array. For example to read like name = arraypost[0]?

You could split the data and pass it into dict() to create a dictionary of key, value pairs:
post_dict = dict([item.split('=') for item in envron['wsgi.input'].split('&')])
print post_dict['name']
print post_dict['fullname']
print post_dict['pass']

Here I'm demonstrating how to do it in Python 3. Using urllib.parse.parse_qs converts it to a dictionary of lists.
import urllib.parse
post = urllib.parse.parse_qs(environ['QUERY_STRING'])
# get value of first instance of POST var 'foo'
print(post.get(b'foo',[''])[0])
Note the use of get() above. The first argument is a byte string, the second argument is a default value. As I said, it's a dictionary of lists, and since we're immediately fetching from index 0, we want at least a zero-length string there so we don't go out-of-bounds.

Related

Dictionary that doesn't exist returning name of string, how to skip this Python

I have a dictionary that holds different value and id's.
The first index in the dictionary does not hold the 'id' dictionary, but the second index does
The problem I am having is when I print:
return[0]['values']['id']
It returns
'id'
Because there is no such dictionary in the first index
The second index
return[1]['values']['id']
The 'id' dictionary does exist so returns
[{"id": "4651234", "type":"instant"}]
I'm trying to create a list of only the id values that exist, how do I get it to skip the all the indexes where the 'id' dictionary does not exist? Rather than stop the program and print the string 'id'.
You can just loop and use a if statement to check if the id exists or not :
id_list = []
for key in return:
if return[key]['values']['id'] != 'id':
id_list.append(return[key]['values']['id'])
(Btw you should avoid naming your variables with name like return or any other keyword that can have a signification for the language)
you can if the returned value it is a list or a string
if isinstance(return[0]['values']['id'],list):
#process the data
elif isinstance(return[0]['values']['id'],str):
#do nothing
Having said that, a couple of recommendations: I assume that you wrote it as an example but, just in case, is not possible to have "return" as the name of the variable since it is a reserved word.
Another point is that if the same call returns different things (i.e. the first returns a str, the second a list with a dictionary in it, etc), it may be an indication that the data needs some cleaning before trying to access it. Otherwise you may end up with nasty results and you won't know where they are coming from.

Processing multiple values sent to Flask request.args.get

I would like to submit and process multiple form values separated by spaces to a Flask route. But I don't have a full understanding request.args.get() works. Here's my code:
#app.route('/rsr')
def rsr():
outval = request.args.get('value',0, type=str)
outvalsplit = outval.split()
for val in outvalsplit:
......
I am expecting split() to separate each value and then iterate through each one. It seems as if the string is processed as one long string rather than separate values.
Your current code iterates over the original query argument string character by character:
for val in outval:
To iterate over the list of split() items:
for val in outvalsplit:
So you're sending a GET-request to http://yourserver.tld/rsr?value=foo or http://yourserver.tld/rsr?value=more than one value?
Then the string more than one value gets probably URL-encoded to more%20than%20one%20value. It's just an assumption. Could you check that? If that's the case then you should probably URL-decode the value prior to splitting or split at each %20.

How to get result from a dictionary with lists as the values

I have a JSON file with n number of dictionaries as listed below in the snippet. I am trying to fetch the value against the key but it fails in my code when the value is defined as a list like in the below example for key affected_packages. I tried to check why my code fails, so it looks like it pulls no data out of it this fails. I just see two brackets [] as output instead of "thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"
{"bugzilla_description":"CVE-2021-23992 Mozilla: A crafted OpenPGP key with an invalid user ID could be used to confuse the user","cvss_score":null,"cvss_scoring_vector":null,"CWE":"CWE-347","affected_packages":["thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"],"resource_url":"https://access.redhat.com/hydra/rest/securitydata/cve/CVE-2021-23992.json","cvss3_scoring_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L","cvss3_score":"4.3"}
I am doing like below in my code as I need to prepare a worksheet. Sample snippet:
for i in range(offs):
ws.cell(row=r+1+i,column=2).value = v['current'][i]
if 'affected_packages' in list(tmp1.keys()):
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages']
print("affected_packages done")
if 'advisories' in list(tmp1.keys()):
ws.cell(row=r+1+index2,column=13).value = tmp1['advisories']
print("advisories done")
Is there a way I can pull the value correctly for those defined as a list in the dictionary? I need a way so that it won't hamper my existing logic to pull value for normal key: value since while looking up into my JSON file.
So need something which can fulfil both whether my value in the dictionary is as a list or not as a list and I can get value against the keys in my json file.
As mentioned in the other answers, you can test the type of a variable using
if type(some_variable) == list:
# do what you need to do
You do mention that your code breaks, and I guess it's because inserting into a cell expects a String, not the list you pass in the line
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages']
So how do we get a string out of a list of strings? It's pretty easy using the join method.
my_list = ["thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"]
as_one_string = ", ".join(my_list)
print(as_one_string)
# Prints out 'thunderbird-0:78.9.1-1.el8_1, thunderbird-0:78.9.1-1.el8_2, thunderbird-0:78.9.1-1.el8_3, thunderbird-0:78.9.1-1.el7_9'
So combining the two ideas:
if 'affected_packages' in list(tmp1.keys()):
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages'] if type(tmp1['affected_packages']) != list else ", ".join(tmp1['affected_packages'])
print("affected_packages done")
Quick feedback because I can't comment yet: Please always include an error message and/or the output you get when running your code when you ask a question
If I understand it correctly, you just need to determine if a value in dict is list. You can do that as below:
for i in d.items(): # gets key, value as a tuple.
if isinstance(i[1],list):
print('its a list, process it accordingly')
else:
print('Not a list')
Regarding your second problem, when you don't know if it is a list or something else, you can just check the type, maybe like this:
if type(tmp1['affected_packages']) == list:
# process the list
else:
# process other types
Since you don't know the data type, having this explicit type check seems necessary.

Why is this an index error?

This is my first post, so I apologize if this has been answered previously. I have tried to look through the Python 3 documentation on string formatting and lists, and reviewed similar formatting questions here on SO.
I want to take the string (data1), break it into a list (bigData), and print out a statement using the list items. Eventually, the idea would be to read in a csv file, break it up, and print out a response, but I've tried to simplify the process since there's an error.
"Hello, John Doe. Your current balance is $53.44."
However, I'm not sure why the following code is throwing an IndexError, much less a tuple index.
data1 = "John,Doe,53.44"
bigData = data1.split(",")
bigData[-1] = float(bigData[-1])
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is ${}."
print(greeting.format(bigData))
My guess is that bigData is heterogeneous, which implies a tuple. If I substitute a string value instead of 53.44 (so data1 and bigData are homogeneous), it throws the same error.
data1 = "John,Doe,random"
bigData = data1.split(",")
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is {}."
print(greeting.format(bigData))
However, if I convert the original to Python 2.x string formatting, it formats correctly without an error.
data1 = "John,Doe,53.44"
bigData = data1.split(",")
bigData[-1] = float(bigData[-1])
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, %s %s. Your current balance is $%.2f."
print(greeting % tuple(bigData))
Why is it converting my string to a tuple?
How do I write this work in Python 3?
Thank you.
Use the splat (*) to unpack your arguments (your format string wants three arguments but you only give it one, a list containter).
print(greeting.format(*bigData))
Also, you may want:
bigData[-1] = str(round(float(bigData[-1]), 2))
The str.format method takes positional arguments, not a single list. You need to unpack your list bigData using the * operator:
data1 = "John,Doe,random"
bigData = data1.split(",")
print(bigData) # test - []'s indicate a list, not tuple?
greeting = "Hello, {} {}. Your current balance is {}."
print(greeting.format(*bigData)) # here's the change
You're correct that bigData is a list, not a tuple, str.split returns a list.
The str.split() method returns a list, by definition.
I think you've misunderstood something you've read - heterogeneous vs. homogeneous refer to typical use cases of tuples vs. lists. Having the types of all the elements match or not does not magically cause the container to change to the other type!
I can see how this is surprising, though what surprises me is that the traceback doesn't show that the exception occurs in the format call.
Python's lists can be heterogenous just like tuples; this is because the common type they store is object references, which all things in Python are. The tuple is actually the argument list to the format method, in this case (bigData,). It ran out of arguments when looking for things to format, since you had three {} placeholders but only one argument (the list bigData). You can use greeting.format(*bigData) to unpack the list and use its contents as arguments.
The % formatting doesn't encounter this error because it actually expects a tuple (or one item) in the right operand.
A more idiomatic and legible approach might actually be to go to the csv module already:
import csv, io
data1 = "John,Doe,random"
for row in csv.DictReader(io.StringIO(data1),
"givenname surname balance".split()):
greeting = "Hello, {givenname} {surname}. Your current balance is {balance}."
print(greeting.format(**row))
This lets us assign meaningful names to the columns, including reordering them in the format string if needed. I've left out the float conversion, and by the way, decimal.Decimal may be better for that use.

Python for loop over json data throws 'TypeError: string indices must be integers' only when a single element of data

I've inherited the following code which is working great, apart from when only a single data item is return from the original xml. When that occurs the following error is thrown: 'TypeError: string indices must be integers'
result = xmltodict.parse(get_xml())
latest_result = result['Response']['Items']['Item']
myJsonData = json.dumps(latest_result)
j= json.loads(myJason)
print type(j)
for item in j:
print (item['Id'])
print (item['OrderId'])
I have narrowed the change in behaviour to a difference in datatype here:
print type(j)
When only a single ['Item'] is returned from the source XML the datatype of j is a 'dict', whilst the rest of the time (greater than one ['Item']) its a 'list'.
Hope someone can help.
Encoding to JSON then decoding again has nothing to do with your question. It is a red herring, you can use latest_result and still get the same error.
The result['Response']['Items']['Item'] can evidently be either a list of dictionaries, or a single dictionary. When iterating over a list, you'll get contained elements, while iteration over a dictionary gives you the keys. So your item elements are strings (each a key in the dictionary) and you can't address elements in that string with 'Id' or 'OrderId'.
Test for the type or use exception handling:
if isinstance(latest_result, dict):
# just one result, wrap it in a single-element list
latest_result = [latest_result]
Alternatively, fix up the xmltodict code (which you didn't share or otherwise identify) to always return lists for elements, even when there is just a single one.
This is a common xmltodict module usage problem. When there is a single child, by default, it makes a dict out of it and not a list with a single item. Relevant github issue:
xml containing 1 child
To workaround it, one option would be to set the dict_constructor argument:
from collections import defaultdict
xmltodict.parse(xml, dict_constructor=lambda *args, **kwargs: defaultdict(list, *args, **kwargs))

Categories

Resources