Could The App Engine Python 2.7 Tutorial Be Broken?

209 views
Skip to first unread message

woolwit

unread,
Jul 12, 2012, 3:18:59 AM7/12/12
to google-a...@googlegroups.com
I was doing fine until I hit 'Using Templates'. Might anything have changed in App Engine SDK 1.7.0 (for Mac, Python 2.7) that would break the tutorial?

ERROR    2012-07-12 07:13:05,784 wsgi.py:189]
Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 187, in Handle
    handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 225, in _LoadHandler
    handler = __import__(path[0])
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 676, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 1858, in load_module
    return self.FindAndLoadModule(submodule, fullname, search_path)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 676, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 1722, in FindAndLoadModule
    description)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 676, in Decorate
    return func(self, *args, **kwargs)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/tools/dev_appserver_import_hook.py", line 1665, in LoadModuleRestricted
    description)
  File "/Applications/MAMP/htdocs/cs253/helloworld/helloworld.py", line 27, in <module>
    class MainPage(webapp2.RequestHandler):
  File "/Applications/MAMP/htdocs/cs253/helloworld/helloworld.py", line 59, in MainPage
    guestbook_key(guestbook_name))
NameError: name 'guestbook_name' is not defined
INFO     2012-07-12 07:13:05,796 dev_appserver.py:2952] "GET / HTTP/1.1" 500 -
Message has been deleted

woolwit

unread,
Jul 14, 2012, 2:35:26 AM7/14/12
to google-a...@googlegroups.com
Hi Jason, and Thank You for taking time to help a noob out. I've gone over everything again and I guess I'm not understanding where to define the guestbook name.
In a previous part of the tutorial I did add comments to a guestbook called 'Guestbook', so there should be data to retrieve from what I thought was the default guestbook
name. The tutorial doesn't say anything about adding to or changing the code presented. I think it's meant to be idiot proof, but once again I seem to have proven them
(makers of coding tutorials) wrong.  Here's my code which returns the same error as outlined before.

import jinja2
import os

jinja_environment = jinja2.Environment(
    loader=jinja2.
FileSystemLoader(os.path.dirname(__file__)))
   
import cgi
import datetime
import urllib
import webapp2

from google.appengine.ext import db
from google.appengine.api import users


class Greeting(db.Model):
  """Models an individual Guestbook entry with an author, content, and date."""
  author = db.StringProperty()
  content = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)


def guestbook_key(guestbook_name=None):
  """Constructs a Datastore key for a Guestbook entity with guestbook_name."""
  return db.Key.from_path('Guestbook', guestbook_name or 'default_guestbook')


class MainPage(webapp2.RequestHandler):
    def get(self):
        guestbook_name=self.request.get('guestbook_name')
        greetings_query = Greeting.all().ancestor(
            guestbook_key(guestbook_name)).order('-date')
        greetings = greetings_query.fetch(10)

        if users.get_current_user():
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template_values = {
            'greetings': greetings,
            'url': url,
            'url_linktext': url_linktext,
        }

        template = jinja_environment.get_template('index.html')
        self.response.out.write(template.render(template_values))

    # Ancestor Queries, as shown here, are strongly consistent with the High
    # Replication Datastore. Queries that span entity groups are eventually
    # consistent. If we omitted the ancestor from this query there would be a
    # slight chance that Greeting that had just been written would not show up
    # in a query.
    greetings = db.GqlQuery("SELECT * "
                            "FROM Greeting "
                            "WHERE ANCESTOR IS :1 "
                            "ORDER BY date DESC LIMIT 10",
                            guestbook_key(guestbook_name))

    for greeting in greetings:
      if greeting.author:
        self.response.out.write(
            '<b>%s</b> wrote:' % greeting.author)
      else:
        self.response.out.write('An anonymous person wrote:')
      self.response.out.write('<blockquote>%s</blockquote>' %
                              cgi.escape(greeting.content))

    self.response.out.write("""
          <form action="/sign?%s" method="post">
            <div><textarea name="content" rows="3" cols="60"></textarea></div>
            <div><input type="submit" value="Sign Guestbook"></div>
          </form>
          <hr>
          <form>Guestbook name: <input value="%s" name="guestbook_name">
          <input type="submit" value="switch"></form>
        </body>
      </html>""" % (urllib.urlencode({'guestbook_name': guestbook_name}),
                          cgi.escape(guestbook_name)))


class Guestbook(webapp2.RequestHandler):
  def post(self):
    # We set the same parent key on the 'Greeting' to ensure each greeting is in
    # the same entity group. Queries across the single entity group will be
    # consistent. However, the write rate to a single entity group should
    # be limited to ~1/second.
    guestbook_name = self.request.get('guestbook_name')
    greeting = Greeting(parent=guestbook_key(guestbook_name))

    if users.get_current_user():
      greeting.author = users.get_current_user().nickname()

    greeting.content = self.request.get('content')
    greeting.put()
    self.redirect('/?' + urllib.urlencode({'guestbook_name': guestbook_name}))


app = webapp2.WSGIApplication([('/', MainPage),
                               ('/sign', Guestbook)],
                              debug=True)

Additionally there is the yaml file:
application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /.*
  script: helloworld.app

libraries:
- name: jinja2
  version: 2.6

And an index.html

<html>
  <body>
    {% for greeting in greetings %}
      {% if greeting.author %}
        <b>{{ greeting.author }}</b> wrote:
      {% else %}
        An anonymous person wrote:
      {% endif %}
      <blockquote>{{ greeting.content|escape }}</blockquote>
    {% endfor %}

    <form action="/sign" method="post">
      <div><textarea name="content" rows="3" cols="60"></textarea></div>
      <div><input type="submit" value="Sign Guestbook"></div>
    </form>

    <a href="{{ url }}">{{ url_linktext }}</a>

  </body>
</html>


On Friday, July 13, 2012 3:18:12 PM UTC-7, Jason Elbourne wrote:

I have not run the code in the tutorial but it looks fine to me. The error you have received leads me to think you do not have the variable assigned for 'guestbook_name'
    guestbook_name=self.request.get('guestbook_name')
this will give you 'None' or the actual name if it has been passed.

The error occurred during the function call for guestbook_key()

So make sure you have that function in your code:

def guestbook_key(guestbook_name=None):
 
"""Constructs a Datastore key for a Guestbook entity with guestbook_name."""
 
return db.Key.from_path('Guestbook', guestbook_name or 'default_guestbook')

And if all of that is in your code then I am not sure what else it could be without seeing all the code.

Jason Elbourne

unread,
Jul 14, 2012, 9:16:09 PM7/14/12
to google-a...@googlegroups.com
Not sure if this would be the issue or just the way the last meesage was typed but the code block of:
IS not indented properly.
 in fact this should not be there any more...the next part in the tutorial was to replace that section with the new one. If you delete the code block as I have shown it in this message...it should all start to work.

Hope this helps.



woolwit

unread,
Jul 17, 2012, 12:43:18 AM7/17/12
to google-a...@googlegroups.com
Thank You Jason!
When the tutorial asked me to replace the MainPage handler, I didn't realize how much of what was there
needed to be replaced, and I left a bunch of the old handler in. All better now. Thanks so much. Going to do
the tutorial again now that I know I have all the ingredients together. And then, back to Udacity CS253 I go.
Reply all
Reply to author
Forward
0 new messages