form["x"] throws a KeyError - python

I'm working on an assignment and we are to create a HTML order form then execute the info by python to create a second customer receipt.
Here is the error msg:
Traceback (most recent call last):
File "F:\Assignment 3\page.py", line 17, in <module>
print "<p>Customer Name:", form["custName"].value, "</p>"
File "C:\Python27\lib\cgi.py", line 540, in __getitem__
raise KeyError, key
KeyError: 'custName'
THE HTML:
<form action="page.py">
<div class="personalinfohead">
<p>Personal Information:</p>
</div>
<div class="personalinfo">
<div>Full name:
<input type="text" name="custName" size="20" />
</div>
<div>Email address:
<input type="text" name="custEmail" size="50" />
</div>
<div>Street address:
<input type="text" name="custAdd" size="50" />
</div>
<div>City:
<input type="text" name="custCity" size="15" />
</div>
<div>Province:
<input type="text" name="custProv" size="2" maxlength="2" />
</div>
<div>Postal code:
<input type="text" name="custPostal" size="6" maxlength="6" />
</div>
</div>
PYTHON:
import cgi
form = cgi.FieldStorage()
# print HTTP/HTML header stuff
print """Content-type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head>
<title>Order Form</title>
</head><body>
"""
# print HTML body using form data
print "<h1>Kintoro Japanese Bar & Restaurant</h1>"
print "<h2>Customer Reciept</h2>"
print "<p>Customer Name:", form["custName"].value, "</p>"
print "<p>Customer Email Address:", form["custEmail"].value, "</p>"
print "<h2>Customer Address:</h2>"
print "<p>Street:", form["custAdd"].value, "</p>"
print "<p>City:", form["custCity"].value, "</p>"
print "<p>Province:", form["custProv"].value, "</p>"
print "<p>Postal Code:", form["custPostal"].value, "</p>"

Jack is correct, but there is a backstory and quick/dirty testing method for the future students.
Explanation first:
Originally, your KeyError said there was no Key with that name. After you've implicitly stated a key (the first part of a dict), it was then missing the Value for said key.
Dictionaries are a key-value pair, so both would need to be implicitly stated at the start of the script (in the scope the previous and following debugging-with-ease methods).
Slowing down the actions helps obtain clearer understanding;
Since this script is a fully loaded CGI that is told to start and finish by declaring variables for each key-value pair, you are seeing the end result of which - where python feeds text data to CGI, CGI then accepts and interprets said text, and gives some sort of response back to python (valid or not!), python can only give you the results of the results. Thusly, this error looks different than your standard (and excellent I may add) non-cgi / console error with followable tracebacks.
A quick/dirty test method:
Implicitly state an exact key-value pair before telling CGI to pass it back to python to use:
custName = { 'Name': 'John Smith' }
One would need to declare a default setting for each dict mentioned as values to have a fully operational loaded script ready to use, but the hint here is that custName would no longer present the error, but it would then complain about your next missing key-value pair.
Yeah, long answer and past classtime - I know. Hopefully, however, this will assist to understand the several parts of a 'single' issue than to solve it once for only a select few people.

Related

How do I accept post requests with a python script using cgi?

I want to submit text to an HTML form and send it to a Python script. When I press the submit button it takes me to an error page that says:
Error code: 501 Message: Unsupported method ('POST'). Error code explanation: HTTPStatus.NOT_IMPLEMENTED - Server does not support this operation.
I'm not exactly sure what the issue is. I've googled the error message and have looked through different documentation and watched some videos but they are seem to gloss over how to set up the server correctly.
I'm running Python 3.7.
<form action="www/cgi-bin/hello.py" method="post">
First Name:
<input type="text" name="first_name" placeholder="e.g. Barack" required="required"/>
Last Name:
<input type="text" name="last_name" placeholder="e.g. Obama" required="required"/>
<input type="submit" name="submitprompt" value="Submit"/>
</form>
#!/usr/bin/python
import cgi, cgitb
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')
print("Content-type:text/html")
print("")
print("")
print("Hello - Second CGI Program")
print("")
print("")
print(" Hello %s %s" % (first_name, last_name))
print("")
print("")
I'm expecting to be taken a page that has the text: Hello first_name last_name. Instead, I receive the aforementioned error.
Using the command "python3 -m http.server --cgi 8000" and configuring from there solved my issue.

use python requests to post a html form to a server and save the reponse to a file

I have exactly the same problem as this post
Python submitting webform using requests
but your answers do not solve it. When I execute this HTML file called api.htm in the browser, then for a second or so I see its page.
Then the browser shows the data I want with the URL https://api.someserver.com/api/ as as per the action below. But I want the data written to a file so I try the Python 2.7 script below.
But all I get is the source code of api.htm Please put me on the right track!
<html>
<body>
<form id="ID" method="post" action="https://api.someserver.com/api/ ">
<input type="hidden" name="key" value="passkey">
<input type="text" name="start" value ="2015-05-01">
<input type="text" name="end" value ="2015-05-31">
<input type="submit" value ="Submit">
</form>
<script type="text/javascript">
document.getElementById("ID").submit();
</script>
</body>
</html>
The code:
import urllib
import requests
def main():
try:
values = {'start' : '2015-05-01',
'end' : '2015-05-31'}
req=requests.post("http://my-api-page.com/api.htm",
data=urllib.urlencode(values))
filename = "datafile.csv"
output = open(filename,'wb')
output.write(req.text)
output.close()
return
main()
I can see several problems:
Your post target URL is incorrect. The form action attribute tells you where to post to:
<form id="ID" method="post" action="https://api.someserver.com/api/ ">
You are not including all the fields; type=hidden fields need to be posted too, but you are ignoring this one:
<input type="hidden" name="key" value="passkey">
Do not URL-encode your POST variables yourself; leave this to requests to do for you. By encoding yourself requests won't recognise that you are using an application/x-www-form-urlencoded content type as the body. Just pass in the dictionary as the data parameters and it'll be encoded for you and the header will be set.
You can also stream the response straight to a file object; this is helpful when the response is large. Switch on response streaming, make sure the underlying raw urllib3 file-like object decodes from transfer encoding and use shutil.copyfileobj to write to disk:
import requests
import shutil
def main():
values = {
'start': '2015-05-01',
'end': '2015-05-31',
'key': 'passkey',
}
req = requests.post("http://my-api-page.com/api.htm",
data=values, stream=True)
if req.status_code == 200:
with open("datafile.csv", 'wb') as output:
req.raw.decode_content = True
shutil.copyfileobj(req.raw, output)
There may still be issues with that key value however; perhaps the server sets a new value for each session, coupled with a cookie, for example. In that case you'd have to use a Session() object to preserve cookies, first do a GET request to the api.htm page, parse out the key hidden field value and only then post. If that is the case then using a tool like robobrowser might just be easier.

KeyError in Python

This is my code:
print """\
<form method="post">
Please enter Viewer Type:<br />
<table>
"""
#Viewer Type
print "<tr><td>Viewer Type<select name=""ViewerType"">"
print """\
<option value="C">Crowd Funding
<option value="P">Premium
"""
#do it button
print """\
<input type="submit" value="OK" />
"""
print """\
</form>
</body>
<html>
"""
ViewerType=form['ViewerType'].value
And, when I serve it to a browser, this is the error:
Traceback (most recent call last): File "/home/nandres/dbsys/mywork/James/mywork/ViewerForm.py", >line 42, in ViewerType=form['ViewerType'].value File "/usr/lib/python2.7/cgi.py", line 541, in >getitem raise KeyError, key KeyError: 'ViewerType'
And line 42 is the last line of my code.
The error isn't actually affecting functionality, and everything works fine, but I don't really want it popping up. Any advice/insight would be appreciated.
Btw, I have this at the top of my code:
import cgi
form = cgi.FieldStorage()
When your script is first called to render the page, the form dict is empty. The dict will only get filled when the user actually submits the form. So changing your HTML to
<option value="C" selected>Crowd Funding
won't help.
So you need to test the dict before you attempt to access it. Eg,
#! /usr/bin/env python
import cgi
form = cgi.FieldStorage()
print 'Content-type: text/html\n\n'
print "<html><body>"
print """\
<form method="post">
Please enter Viewer Type:<br />
<table>
"""
#Viewer Type
print "<tr><td>Viewer Type<select name=""ViewerType"">"
print """\
<option value="C">Crowd Funding
<option value="P">Premium
"""
#do it button
print """\
<input type="submit" value="OK" />
"""
print "</table></form>"
if len(form) > 0:
ViewerType = form['ViewerType'].value
print '<p>Viewer Type=' + ViewerType + '</p>'
else:
print '<p>No Viewer Type selected yet</p>'
print "</body></html>"
Simple solution if you don't want it popping:
try:
ViewerType=form['ViewerType'].value
except KeyError:
pass
It'll work but I would recommend you to debug your code and find out why you are getting KeyError. From https://wiki.python.org/moin/KeyError,
Python raises a KeyError whenever a dict() object is requested (using the format a = adict[key]) and the key is not in the dictionary.

SL4A _R6 / Python4android_R4 webViewShow NullPointerException on simple example code

I'm trying to get a HTML Gui on my simple SL4A Python app. the only thing I need to perform is ask the user for 1 input string at the start of my app.
For debugging purposes I started of simple. Unfortunately even this won't function.
Any idea's what's wrong here? (I've tried several pieces of code like this and all have the same issue)
Python code:
import android
loop = True
droid = android.Android()
droid.webViewShow('/sdcard/sl4a/scripts/screen.html')
while loop:
res = droid.waitForEvent('data')
if res:
print str(res)
HTML code
<html>
<head>
<script>
var droid = new Android();
var fiets = function() {
droid.postEvent("data", document.getElementById("gsm").value);
}
</script>
</head>
<body onload:"fiets()">
<form onsubmit="fiets(); return false;">
<label for="say">What would you like to say?</label>
<input type="text" id="gsm" value="99999999" />
<input type="submit" value="Store" />
</form>
</body>
</html>
the error message is repeatedly (the number 3114 is incremental):
java.lang.NullPointerException
Result(id=3114, result=None, error=u'java.lang.NullPointerException')
update:
http://www.mithril.com.au/android/doc/EventFacade.html
As we go I read waitForEvent is deprecated in r4. I should use eventWaitFor instead.
This takes the error away but doesn't make the example function. Python script prints nothing.
update2:
droid.postEvent should become droid.eventPost
droid.waitForEvent('data') should become droid.waitForEvent('data')
In javascript and python.
Problem Solved

Python Pass List into Form and Retrieve as List

What is the best way to pass List via form in python (cgi).
ListStr = ['State1', 'State2', 'State3']
TrVListStr = '##'.join(ListStr)
print """
<form method="post">
<input type=hidden name="state_carry" value="""+TrVListStr+"""><br />
<input type="submit" value="Submit" />
</form>
"""
After submission I should have list as it was before submission.
I can do split (based on ## rule) form['state_carry].value again to fetch that. but I think it is not good way.
Is there any way to pass Python List via form and retrieve them later.
Thanks.
You could use the python cgi module. The documentation specifically covers the case where you have multiple values for a certain field name.
The basic idea is that you can have multiple fields in your html form with the same name, and the value for each field is one of the values from the list. You can then use the getlist() method to retrieve all the values as a list. For example:
print "<form method=\"post\">"
for s in ListStr:
print "<input type=hidden name=\"state_carry\" value=\"" + s + "\"><br />"
print "<input type=\"submit\" value=\"Submit\" />"
print "</form>"
Then in your CGI script you'll have something like:
MyList = form.getlist("state_carry")
In python I would do.
###In the form page.
import cgi
#Convert list of values to string before passing them to action page.
ListStr=','.join(['State1', 'State2', 'State3'])
print "<input type=hidden name=\"state_carry\" value=\""+ListStr+"\"><br />"
###In the action page
import cgi
#Return the string passed in the user interaction page and transform it back to a list.
ListStr=cgi.FieldStorage().getvalue('state_carry').split(',')

Categories

Resources