Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python/GAE Attribute Error - webapp2

I am using Nick Johnsons Webapp & Templates application as a base for what I am trying to do. I am getting a "AttributeError: 'NoneType' object has no attribute 'write'" when I try to call the render_template. I know it is because when I instantiate the object "Capture" as X, it doesn't have a response property. I have looked everywhere to find a solution but I cannot find one anywhere.

NOTE: There are other ways to do this, but I need it to work as closely to how I have it setup!

Traceback:

Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 1102, in __call__
    return handler.dispatch()
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "/Users/userx/Documents/_FRESHCUTZ MEDIA/Google/GAE - Test web form 1 /testwebform1/main.py", line 41, in post
    x.calculateYear(name, age)
  File "/Users/userx/Documents/_FRESHCUTZ MEDIA/Google/GAE - Test web form 1 /testwebform1/main.py", line 49, in calculateYear
    self.response.write(self.render_template('index.html', **template_args))
AttributeError: 'NoneType' object has no attribute 'write'

MAIN.PY

import os
import webapp2
from webapp2_extras import jinja2

class BaseHandler(webapp2.RequestHandler):
  @webapp2.cached_property
  def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

  def render_template(self, filename, **template_args):
        self.response.write(self.jinja2.render_template(filename, **template_args))

class MainPage(BaseHandler):
  def get(self):
    template_args = {}
    self.render_template('index.html', **template_args)

class CaptureDetails(BaseHandler):
  def post(self):
    name = self.request.get("name").strip()
    age = self.request.get("age").strip()

    x = Calculate()
    x.calculateYear(name, age)

class Calculate(BaseHandler):
    def calculateYear(self, name, age):
       template_args = {"age": age} 
       self.render_template('name.html', **template_args) 

app = webapp2.WSGIApplication([
      ('/', MainPage),
      ('/capture', CaptureDetails),
      ('/age', Calculate)
    ], debug=True)

What am I doing wrong? Any help/suggestions are greatly appreciated!

like image 459
user1904916 Avatar asked Sep 13 '26 14:09

user1904916


2 Answers

Does it fit your criteria if you make calculateYear a function of your BaseHandler class (or elsewhere if more applicable)? As you guessed, your x isn't being treated as a proper response. When you invoke a webapp2.RequestHandler handler, it calls the method associated with the type of request (so in your case, since you are posting a form, it will call post(), as you know). When you instantiate x and call calculateYear, you aren't specifying a particular method (def get(self), def post(self), etc.), so there is no preparation of a response (when I have a chance I'll dig a little to confirm that this is actually the case - I could be mistaken :) ).

Can't test this right now, but assuming you need to call calculateYear from more than just the CaptureDetails handler, would this work? Here you would be referencing self in the context of your post method, which would invoke the response handling:

class BaseHandler(webapp2.RequestHandler):
  @webapp2.cached_property
  def jinja2(self):
      return jinja2.get_jinja2(app=self.app)

  def render_template(self, filename, **template_args):
      self.response.write(self.jinja2.render_template(filename, **template_args))

  def calculateYear(self, name, age):
      template_args = {"age": age} 
      self.render_template('name.html', **template_args)

Which you could then call from your CaptureDetails handler like:

class CaptureDetails(BaseHandler):
  def post(self):
    name = self.request.get("name").strip()
    age = self.request.get("age").strip()

    # Call the function and write the response
    self.calculateYear(name, age)
like image 121
RocketDonkey Avatar answered Sep 16 '26 04:09

RocketDonkey


By instantiating Calculate yourself in your CaptureDetails.post method you're not creating it in the same way that WSGIApplication does, so the properties aren't available. Specifically, you're not passing a response to it, so not surprisingly trying to reference it doesn't work.

In this case, I'd copy the contents of calculateYear into your post method - you're not really saving anything by having to create the instance and then call the method on it. If calculateYear gets more complicated, and you don't want the duplication, then I'd introduce a new method that could be called by both of your hander methods. (It's not really clear from this example though why the Calculate class exists - it doesn't have a 'get' method, so mapping it to /age as you have done isn't going to work.)

like image 31
Greg Avatar answered Sep 16 '26 05:09

Greg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!