0

Can I use context manager inside a Request Handler to manage the flow of my variables from the URL to the template?

I started from this example here

I was thinking to use it to create a class instance at the top of the handler, to run all the code I need for calculation, to close the context and to pass all the variables calculated by the class to a dictionary of parameters and finally pass them to the template. Like:

URL>>> http://domain.xx/param1/param2/

class Handler(webapp2.RequestHandler):
 def get(self, param1, param2)
  URLparams = [param1,param2]
  TEMPparams = {}
  with Foo(URLparams) as foo:
     TEMPparams['obj'] = foo.obj
     TEMPparams['obj1'] = foo.obj1
     ... 
  self.response.out.write(template, TEMPparams)

class Foo(object):
  def __init__(self, URLparams):
      ...
      ...
  def __enter__ ... :
      ... make a db query ...
  def __exit__ ... :
      ... 

What's the best implementation considering I have to perform a datastore query and some memcache set/get inside the class? For what I understood about ContextManager until now, the with statement let you make 'procedural' the execution of a class through the context methods, isn't it? I mean, the magic methods __init__() >> __enter__() >> __exit__() used with with seem to me to describe a flow. If I initialize the variables as I need, I make the query in enter() and then I delete the class' instance at __exit__(), it seems to me to simulate a procedure inside an OO paradigm.

I tested a thing like this:

class Test(webapp2.RequestHandler):
  def get(self):
    r = []
    p = {}      
    foo = Foo(r)
    with foo:
        p['obj'] = [foo, foo.bar, r]

    self.response.out.write(p)

class Foo(object):

  def __init__(self, r):
    self.bar = None
    self.r = r

  def __enter__(self):
    if self.bar != 'open':
      r = self.r
      r.append('opening the bar')
      self.bar = 'open'
    return self # this is bound to the `as` part

  def close(self):
    if self.bar != 'closed':
      r = self.r
      r.append('closing the bar')
      self.bar = 'close'

  def __exit__(self, *err):
    self.close()
    return self.r  

The foo variable is not printed on the template, even trying to convert if into a string before passing it to the template (this is not a big problem though, I would only like to know why). The result on page is:

{'obj': [, 'open', ['opening the bar', 'closing the bar']]}

Is there something wrong in this approach? Any caveat or things to take care of? Is it a correct approach to use it this way into an handler?

Community
  • 1
  • 1
tuned
  • 1,085
  • 10
  • 14
  • 2
    The first thing you should ask your self is what value a ContextManager would add in this instance. If there is no specific value add why add the complexity? For instance it might make some sense wrapping some URLFetch activity, but I really don't see it for your example. – Tim Hoffman Jan 08 '14 at 06:23
  • I don't understand the use case here. What do you mean by "you make 'procedural' the execution of a class"? – Ezequiel Muns Jan 08 '14 at 08:49
  • Ezequiel: the magic methods __init__() >> __enter__() >> __exit__() used with *with* seem to me to describe a flow. If I initialize the variables a I need, I make the query in __enter__() and then I delete the class' instance at __exit__(), it seems to me to simulate a procedure inside an OO paradigm. @TimHoffman There are some side functions (json conversion, string processing, memcache, etc) that will be running inside the context. What could be this *added value* in your opinion? Please submit an answer if you have some references or ideas about. – tuned Jan 08 '14 at 12:50
  • 1
    In my opinion, with what you are doing there, I don't see any value at all in using a context manager. At no point have you any state/service you need to clean up. I feel you are over complicating the solution. Now if you are just trying out context managers as a learning exercise then that's a different store. – Tim Hoffman Jan 08 '14 at 13:49
  • @TimHoffman yeah, thanks, it's mainly for learning purpose. But also to encapsulate some logic to be reusable with other handlers. Does it make any sense in your opinion? which solution you would go for instead to make all my methods into a class to be reusable in other cases? – tuned Jan 08 '14 at 15:55
  • 1
    In most appengine projects, I find factories (classmethod of the model) tend to be useful if you need to do a lot of entity specific stuff when creating entitites. Otherwise use functions, or mixin's in the handler if multiple handlers will share the code. A lot of time much of what you do is entity instance specific, in which case it's method's of the entity, or classmethods where it's model specific like queries. – Tim Hoffman Jan 08 '14 at 23:47

1 Answers1

0

The best solution I could find in these days is to build a custom class to create a generic object for the tasks required in the handlers, then create an instance into the __init__() in each request handler, like:

class GenericalObject(object):
    def initialize(self, URIparams):
       # init all the self.attribute needed by my handlers

    def getDataFromDB():
       # return the DB data into a dictionary


class FirstHandler(webapp2.RequestHandler):
    def __init__(self, request, response):
       self.initialize(request, response)
       self.instance = GenericalObject()

    def get(self, URIparams1, URIparams2)
       URIparams = [URIparams1, URIparams2]
       instance = self.instance
       instance.initialize(URIparams)
       params = instance.__dict__

       data = getDataFromDB()
       params['data'] = data
       del instance

       return self.render_template('template.html', params)

class SecondHandler(webapp2.RequestHandler):
    # same initialization but different implementation of the get() and post()

Thanks to @TimHoffman

Hope this will help somebody to apply some OO to their App Engine projects.

tuned
  • 1,085
  • 10
  • 14