When I run this code in the dev_appserver it gives me the "Invalid syntax" error at line 22, where the HugAPanda class is initialized. Does anybody know why this would happen? Here's the code:
import wsgiref.handlers
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
class PandasHugs(db.Model):
message = db.IntegerProperty()
class MainPage(webapp.RequestHandler):
def get(self):
ListOfHugs = db.GqlQuery("SELECT * FROM PandasHugs")
Adder = 0
for PandasHugs in ListOfHugs:
Adder = Adder + 1
self.response.out.write('<html><body>')
self.response.out.write('<h6>Panda has ' + str(Adder) + ' hugs!</h6>')
self.response.out.write("<form action=\"/HugPanda\" method=\"post\"><div><input type=\"text\" name=\"PandaMessage\" value=\"A message for a panda.\"></div><div><input type=\"submit\" value=\"Hug a panda?\"></div></form></body></html>">
class HugAPanda(webapp.RequestHandler):
def post(self):
HugForAPanda = PandaHugs()
HugForAPanda.message = self.request.get('PandaMessage')
HugForAPanda.put()
self.redirect('/main')
application = webapp.WSGIApplication(
[('/', MainPage), ('/main', MainPage), ('/HugPanda', HugAPanda)],
debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
Thanks again!
-Neil
You have invalid syntax in a line above. (Line 15 it looks like)
self.response.out.write("<form action=\"/HugPanda\" method=\"post\"><div><input type=\"text\" name=\"PandaMessage\" value=\"A message for a panda.\"></div><div><input type=\"submit\" value=\"Hug a panda?\"></div></form></body></html>">
Extra '>' at the end should be replace with ')'.
This is a very good reason to follow python convention and limit line length to 79 characters. I won't argue with going up to 120 if that is standard at your organization, but it certainly should not be written the way it's presented here :)
In this case I'd recommend writing readable html code (ie. properly indented) in triple quotes. In your case I would use single triple quotes so you do not have to escape every ". I just recommend the single quotes here to avoid confusion, but I believe """ will also work in this case.
ie.
self.response.out.write('''<html>
<body>
<h6>Panda has %s hugs!</h6>
<form action="/HugPanda" method="post">
<div>
<input type="text" name="PandaMessage" value=
"A message for a panda.">
</div>
<div>
<input type="submit" value="Hug a panda?">
</div>
</form>
</body>
</html>''' % Adder)
Just noticed some errors in the html after rewriting your code should have '/>' to close your input tags. Good style can go a long way in avoiding errors without the use of any tools!
http://www.python.org/dev/peps/pep-0008/
The end of your line
self.response.out.write("<form....da?\"></div></form></body></html>">
should be replaced with.
self.response.out.write("<form....da?\"></div></form></body></html>")
Parenthesis are unbalanced. Also, although that's not syntactically wrong, but you need to reconsider the indentation to 4-spaces uniformly in whole file.
Happy Coding.
Related
I'm maintaining someone else's old CherryPy code, and have an interesting situation I'm trying to understand. Consider this code which demonstrates it:
import cherrypy
class HelloWorld(object):
def index(self, name):
html = """<form method="post">
<input type="text" name="name" value="%s" /></form>
Hello %s!""" % (name, name)
return html
index.exposed = True
cherrypy.quickstart(HelloWorld())
Run it with python hello.py and go to http://127.0.0.1:8080/?name=foo. The output is a text input box with "foo" followed by "Hello foo!".
But if I edit the text in the box and replace it with "bar" and hit enter (submitting the form), the result is not "bar" in the input box and "Hello bar!" below but (apologies for ascii art input box):
+---------------------+
| [u'foo', u'bar'] |
+---------------------+
Hello [u'foo', u'bar']!
It seems that CherryPy is combining the URL querystring "name" argument value with the form "name" value submitted in the body of the POST request and providing a list with the two values to the exposed index() method.
From what I can tell of the code I'm maintaining, it didn't always work this way. So that leads to my two questions:
Did CherryPy change how it handles this situation in some version prior to 3.7.0 (which is what I'm testing with)?
Can I configure CherryPy to revert to that old behavior, or at least to have the POST value override the querystring value?
(I'm not intimately familiar with the CherryPy documentation, but I couldn't find the answer there.)
I've found the answer to question 1 I posed.
The behavior changed with the release of CherryPy 3.2. The actual change was made in git commit e05feef4fee7df1ee5d25d11393f872c9ef12510 (hg:3b92b5aa76f9) on 31 May 2009, which was when the _cpreqbody module was switched in in place of the old process_body() method.
The code used to do this (where self.params is a dict, already containing the params from the query string):
self.body_params = p = httputil.params_from_CGI_form(forms)
self.params.update(p)
From 3.2, it now does this (where key and value are from the POST body being processed):
if key in params:
if not isinstance(params[key], list):
params[key] = [params[key]]
params[key].append(value)
else:
params[key] = value
It looks like there's no easy answer to my question 2, so I'll have to use cherrypy.request.body_params when I know that's where the value I'm after will be found.
I don't think it was the change in 3.x series. You can directly access GET and POST params like in the following snippet. However using unique names is more advised and less error-prone way.
import urlparse
import cherrypy
class HelloWorld:
#cherrypy.expose
def index(self, name):
postParams = cherrypy.request.body.params
getParams = urlparse.parse_qs(cherrypy.request.query_string)
print(postParams, getParams)
# ({u'name': u'bar'}, {'name': ['foo']})
Update
Good research #TimB. By skipping through the codebase I couldn't find where the thing happens. And yes CherryPy 3.2+ is like the series on its own.
CherryPy is quite configurable, and your case is not an exception, when you're able to deal with its notions. Specifically you can write a CherryPy tool to override the mixed request params with POST params. It's just a few lines.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urlparse
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
},
'/' : {
'tools.postoverride.on' : True,
}
}
def postOverride():
cherrypy.request.params.update(cherrypy.request.body.params)
cherrypy.tools.postoverride = cherrypy.Tool('before_handler', postOverride)
class HelloWorld:
#cherrypy.expose
def index(self, name):
html = """<form method="post">
<input type="text" name="name" value="%s" /></form>
Hello %s!""" % (name, name)
return html
if __name__ == '__main__':
cherrypy.quickstart(HelloWorld(), '/', config)
I do get your expected result. I imagine there is something wrong with your code.
In particular you use
% (name, name)
Which CANNOT resolve to two different values.
So, I'm trying to learn TDD for Flask, by translating this code to Flask. I've been trying to find how to render a template to a string for a while now. Here is what I have tried:
render_template(...)
render_template_string(...)
make_response(render_template(...)).data
and none of them seem to work.
The error in each case seems to be
"...templating.py", line 126, in render_template
ctx.app.update_template_context(context)
AttributeError: 'NoneType' object has no attribute 'app'
in templating.py's render_template function.
My test code is as follows:
def test_home_page_can_save_POST_request(self):
with lists.app.test_client() as c:
c.get('/')
rv = c.post('/', data = {'item_text':"A new list item"})
# This test works
self.assertIn("A new list item", rv.data)
# This test doesn't
self.assertEqual(rv.data,flask.make_response(flask.render_template('home.html',new_item_text='A new list item')).data)
with home.html as follows:
<html>
<body>
<h1>Your To-Do list</h1>
<form method="POST">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
</form>
<table id="id_list_table">
<tr><td>{{ new_item_text }}</td></tr>
</table>
</body>
</html>
Edit: I've added more files, because the error may be unrelated to the actual function used. I'm using exactly what Celeo has suggested in his answer.
Celeo is correct, but there are two additional things to consider (one of which is peculiar to the render_template function):
First, it looks like you have an indentation problem in your revised function. It looks like you're calling rv.data outside of the "with" statement. The "assertEqual" statement should be within the same block/indentation-level as the "assertIn" statement. (It looks like you've placed it outside of the block at the moment.)
Second -- and more importantly -- the render_template function in flask adds newline characters at the beginning and end of the outputted HTML. (You can verify this from the python interactive shell by printing the following command to stdout:
flask.render_template('home.html',new_item_text='A new list item').data # adds '\n' at start & end
The output you'll get will have newline characters ("\n") at the beginning and end of the output.
Therefore, you should try stripping the output with the strip() function as shown below:
def test_home_page_can_save_POST_request(self):
with lists.app.test_client() as c:
c.get('/')
rv = c.post('/', data = {'item_text':"A new list item"})
self.assertIn("A new list item", rv.data)
# Suggested Revision
self.assertEqual(rv.data,flask.make_response(flask.render_template('home.html',new_item_text='A new list item')).data.strip())
That should hopefully do the trick.
You're on the right path with make_response:
response = make_response(render_template_string('<h2>{{ message }}</h2>', message='hello world'))
Then,
response.data
is
<h2>hello world</h2>
That response object is documented here.
update 0:
There is a subtle, but serious, error in my code and in my explanation below because I cannot only compare the name on the template with the hiddenname on the template (that much only tells me that the user has made a change like a checkbox change would tell me, but purposely there are no checkboxes), I also need to compare name to the status of name in the datastore of reservations to see if someone else has already reserved the time slot. So I cannot use javascript and I have to rewrite some of the code below to make the correct comparison, too. And may original question remains as suggested by the Title of this question. (In one of the comments I erroneously said that javascript would work.)
update 0:
I am trying to write a sort of "alert" in the way that this code suggests where I use the Trans model and the gae datastore (further below) to communicate between my main app and the "alert template". I have a few problems.
Initially I had my need for this alert in an another part of my code in an else: clause, not in an elif: clause. When I tried to use the simpler version of my alert in the elif code, python seemed to ignore the self.response.out.write(template.render(path, template_values)) and just went on to this code which ended my conditionals: return webapp2.redirect("/read/%s" % location_id). So, as you can see in my code I have commented out the ignored former code line and attempted to replace it with something more like the latter code line, but with that latter line directed to unexpected instead of read. You can see from my code it is still a mix between the two approaches and I could use help sorting that out. Is there really something different about else: and elif: regarding this?
Originally I had not anticipated my desire to call the same html template and Trans model from so many places in my code, so I did not design a key or ID or key_name into the design of using Trans. And now I am having trouble implementing a version with such detail.
I have been looking for an example of how such "alert templates" can be made in python. They are so easy in javascript, but I am trying to do the user input validation in my python code. Any pointers to examples or docs would be greatly appreciated.
weekday_key = db.Key.from_path('Locations',location_id,'Courts', court_id,'Days',weekday)
if name == hiddenname:
pass
elif name != hiddenname and hiddenname == "":
reservation = Reservations.get_or_insert(time[2],parent=weekday_key)
reservation.hour = time[0]
reservation.minute = time[1]
reservation.year = int(year)
reservation.nowmonth = int(nowmonth)
reservation.day = int(day)
reservation.nowweekday = int(nowweekday)
reservation.name = name
reservation.put()
elif name != hiddenname and name!="":
reservation = Reservations.get_by_key_name(time[2],parent=weekday_key)
reservation.hour = time[0]
reservation.minute = time[1]
reservation.year = int(year)
reservation.nowmonth = int(nowmonth)
reservation.day = int(day)
reservation.nowweekday = int(nowweekday)
reservation.name = name
reservation.put()
reason='This was in that time slot already: '
trans = Trans(parent=reservation.key().name()) #this line is iffy
trans.reason=reason
trans.name=hiddenname
trans.put()
iden = trans.key().id() # this is part of the iffy just above
template_values = {'trans':trans}
path = os.path.join(TEMPLATE_DIR, 'unexpected.html')
#self.response.out.write(template.render(path, template_values))
return webapp2.redirect("/unexpected/%s/%d" % (time[2],iden) #more iffy
else:
pass
My model for Trans in next.
class Trans(db.Model):
reason = db.StringProperty()
name = db.StringProperty()
My jinja2 equipped unexpected.html template is as follows.
{% extends "base.html" %}
{% block content %}
This unexpected result occurred. {{ trans.reason }}:<emph style="font-weight: bold">{{ trans.name }}</emph>
<br /><br />
<div id="inputdata">
<label>Click the "Ok" button to go back to the previous page so you can elect to edit your entry, or not.
</label>
<button onclick="window.history.back()">Ok</button>
</div>
{% endblock content %}
This question is answered here. It could have been answered in this question, but apparently there was too much information given and no one saw the answer.
Which is the best/easiest way to translate the messages from strftime like "time data '2012' does not match format '%d.%m.%Y'" or "day is out of range for month"?
I ask because i have written an application with Flask, Flask-WTForms and Fields from type DateField. For the other messages i used Flask-Babel/gettext, but this error messages seems to be direct from strftime which doesn't use gettext.
Thanks!
2012-07-24: Adding some sample code (please try it with dates like "2012-2-30"):
from flask import Flask, render_template
from flask.ext.wtf import Form, DateField
class DateForm(Form):
date = DateField(u"Date")
DEBUG = True
SECRET_KEY = 'secret'
app = Flask(__name__)
app.config.from_object(__name__)
#app.route("/", methods=("GET", "POST",))
def index():
form = DateForm()
if form.validate_on_submit():
pass
return render_template("simple.html", form=form)
if __name__ == "__main__":
app.run()
Template "simple.html":
<!DOCTYPE html>
<html>
<body>
<form method="POST" enctype="multipart/form-data">
{% if form.date.errors %}
{{ form.errors }}
{% endif %}
{{ form.hidden_tag() }}
{{ form.date.label }}
{{ form.date|safe }}
<input type="submit" value="Submit">
</form>
</body>
</html>
The short version: you should not: exceptions are meant to be acted upon, not translated.
There is conceptually a difference between a message intended for the user and a message intended for the developer (like runtime exceptions).
Translating exceptions would make as much sense as translating if ... then ... else constructs: the developer is supposed to know the programming language, not to need a translation of it.
While in the majority of the cases exceptions are caused by bugs (and therefore should not be there in deployed code), in some cases they might signal a condition that is physiological for the program. If this condition requires an action from the user, the code should catch the exception in question and present the user with a message that is meaningful for her/him. An example:
Knowing that:
>>> int('text')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'text'
You could write a program like this (of course using messages for the user in your favourite human language):
>>> while True:
... n = raw_input('What do you want to multiply 10 for? ')
... try:
... print 'The result is: %d' % (10 * int(n))
... except ValueError:
... print 'You should provide an integer number...'
Note that we are catching only ValueError, as this is the only "physiological" case for our software. Any other exception would crash the program, as it would represent a condition the developer did not account for.
A word on validation though: if your scenario is that of a user having to insert a date in a specific format, it would be probably better to validate its input prior to try processing it. The above example should then become:
>>> while True:
... n = raw_input('What do you want to multiply 10 for? ')
... if not all((c in '0123456789' for c in n)):
... print 'You should provide an integer number...'
... continue
... print 'The result is: %d' % (10 * int(n))
While in python it is mostly a matter of style whether to catch the exception or to validate the input (in other languages it might not be the case, as sometimes exceptions are much slower to process than checking for a condition), in web development is customary to also (i.e. additionally to check the input server-side, which you should always do) validate the input client-side with javascript, as this saves time to the user and CPU to the provider, eliminating a request/response cycle.
HTH!
syntax error:
msg = "keyword can't be an expression"
offset = None
print_file_and_line = None
text = 'data = data(name and mood=self.request.POST)\n'
I'm posting much of the code here as even though my Datastore has a "Visitor" Entity with name, mood, date properties (the index.yaml file is working apparently), form data is not being submitted to Datastore as evident in Console query:
SELECT name FROM Visitor
^ SyntaxError: invalid syntax
The last section of the following is me guessing what to do from modified Google tutorial. I know it's wrong but hope you see what I'm trying to do:
class Visitor(db.Model):
name = db.StringProperty(required=1)
mood = db.StringProperty(choices=["Good","Bad","Fair"]) # this is Radio button
date = db.DateTimeProperty(auto_now_add=True)
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write("""<html><body>
<form action="/" method="post">
<p>First Name: <input type="text" name="name"/></p> # text
<p><input type="radio" name="mood" value="good">Good</p> # radio button v
<p><input type="radio" name="mood" value="bad">Bad</p>
<p><input type="radio" name="mood" value="fair">Fair</p>
<p><input type="submit"value="Process"></p>
</form></body></html>""")
def post(self):
name = self.request.get("name")
mood = self.request.get("mood")
data = data(name and mood=self.request.POST) # < < ^ ^ PROBLEM(S)
if data.is_valid():
Visitor = data.save(commit=False)
Visitor.put()
thanks in advance for help to attain desired goal.
Your problem is at this line as you've pointed out
data = data(name and mood=self.request.POST)
The syntax error is because you're trying to do assignment in an expression.
mood=self.request.POST
#"name and mood" is a logical expression which will return
#"mood" if bool(name) is True and bool(mood) is True
#Otherwise it returns the first False value.
data=data(name and mood)
Of course, this is funny too because data is presumably a callable which you're replacing with it's result...
Also, data isn't defined anywhere (that we can see)...So while we've gotten rid of one syntax error, there are (likely) other problems lurking in your script.