How to map a route to a function in Tornado? - python

I want to set more than one get route in a class. Or simply map a route to a function.
This is what I've done:
class TestRoute1(tornado.web.RequestHandler):
def get(self):
self.write("I have done something.")
class TestRoute2(tornado.web.RequestHandler):
def get(self):
self.write("This is something else.")
application = tornado.web.Application([
(r"/test1", TestRoute1),
(r"/test2", TestRoute2),
])
application.listen(8080)
And this is what I think should be possible to do:
class TestRoute(tornado.web.RequestHandler):
def func1(self):
self.write("I have done something.")
def func2(self):
self.write("This is something else.")
application = tornado.web.Application([
(r"/test1", TestRoute.func1),
(r"/test2", TestRoute.func2),
])
application.listen(8080)
Or something like this. Is it possible? If it is not, what is the alternatives to one I use?

In general, the idiomatic way to do this in Tornado is to use two separate classes as you've done in your first example, and use a common base class to contain any code that needs to be shared between them.
There are, however, two ways to pass additional information from the routing table into the handler. First, if there are capturing groups in the routing regex, the substrings they capture will be passed to the get/post/etc methods. Second, you may pass an additional dictionary in the routing table (as a third element of the tuple); this dictionary will become keyword arguments to the handler's initialize() method.

This is against Tornado creators' original intent, but you can use function decorators to route requests.
Basically you can use use decorator to create inner class and use setattr() to replace get method with your own.
Take a look at this article I wrote that provides Tornado function router.

Related

How to avoid parameter type in function's name?

I have a function foo that takes a parameter stuff
Stuff can be something in a database and I'd like to create a function that takes a stuff_id, get the stuff from the db, execute foo.
Here's my attempt to solve it:
1/ Create a second function with suffix from_stuff_id
def foo(stuff):
do something
def foo_from_stuff_id(stuff_id):
stuff = get_stuff(stuff_id)
foo(stuff)
2/ Modify the first function
def foo(stuff=None, stuff_id=None):
if stuff_id:
stuff = get_stuff(stuff_id)
do something
I don't like both ways.
What's the most pythonic way to do it ?
Assuming foo is the main component of your application, your first way. Each function should have a different purpose. The moment you combine multiple purposes into a single function, you can easily get lost in long streams of code.
If, however, some other function can also provide stuff, then go with the second.
The only thing I would add is make sure you add docstrings (PEP-257) to each function to explain in words the role of the function. If necessary, you can also add comments to your code.
I'm not a big fan of type overloading in Python, but this is one of the cases where I might go for it if there's really a need:
def foo(stuff):
if isinstance(stuff, int):
stuff = get_stuff(stuff)
...
With type annotations it would look like this:
def foo(stuff: Union[int, Stuff]):
if isinstance(stuff, int):
stuff = get_stuff(stuff)
...
It basically depends on how you've defined all these functions. If you're importing get_stuff from another module the second approach is more Pythonic, because from an OOP perspective you create functions for doing one particular purpose and in this case when you've already defined the get_stuff you don't need to call it within another function.
If get_stuff it's not defined in another module, then it depends on whether you are using classes or not. If you're using a class and you want to use all these modules together you can use a method for either accessing or connecting to the data base and use that method within other methods like foo.
Example:
from some module import get_stuff
MyClass:
def __init__(self, *args, **kwargs):
# ...
self.stuff_id = kwargs['stuff_id']
def foo(self):
stuff = get_stuff(self.stuff_id)
# do stuff
Or if the functionality of foo depends on the existence of stuff you can have a global stuff and simply check for its validation :
MyClass:
def __init__(self, *args, **kwargs):
# ...
_stuff_id = kwargs['stuff_id']
self.stuff = get_stuff(_stuff_id) # can return None
def foo(self):
if self.stuff:
# do stuff
else:
# do other stuff
Or another neat design pattern for such situations might be using a dispatcher function (or method in class) that delegates the execution to different functions based on the state of stuff.
def delegator(stff, stuff_id):
if stuff: # or other condition
foo(stuff)
else:
get_stuff(stuff_id)

Get URL parameter inside prepare() function, instead of get() / post()

I am using tornado and I declared a RequestHandler with a single parameter like this:
class StuffHandler(RequestHandler):
def get(self, stuff_name):
...
app = Application([
(r'/stuff/(.*)/public', StuffHandler)
])
Now I added another handler for '/stuff/(.*)/private', which requires the user to be authenticated:
class PrivateStuffHandler(RequestHandler):
#tornado.web.authenticated
def get(self, stuff_name):
...
This of course will cause get_current_user() to be called before get(). The problem is that, in order for get_current_user() to run, I need to know the stuff_name parameter.
So I thought that I may use the prepare() or the initialize() method, which is called before get_current_user(). However, I can't seem to access stuff_name from those methods. I tried putting stuff_name as a parameter but it didn't work, then I tried calling self.get_argument("stuff_name") but it didn't work either.
How do I access an URL parameter from the prepare() method?
I think you can use self.request.path to get the full path, then achieve the value in path which you need.
In the end, I asked straight to Tornado developers and a helpful user made me notice that there's self.path_args and self.path_kwargs available from anywhere in the class.
So, from the prepare() method (or even the get_current_user() method), I can do:
stuff_name = self.path_args[0]

Python, executing extra code at method definition

I am writing a python API/server to allow an external device (microcontroller) to remotely call methods of an object by sending a string with the name of the method. These methods would be stored in a dictionary. e.g. :
class Server:
...
functions = {}
def register(self, func):
self.functions[func.__name__] = func
def call(self, func_name, args):
self.functions[func_name](*args)
...
I know that I could define functions externally to the class definition and register them manually, but I would really like that the registering step would be done automatically. Consider the following class:
class MyServer(Server):
...
def add(self,a,b):
print a+b
def sub(self,a,b):
print a-b
...
It would work by subclassing a server class and by defining methods to be called. How could I get the methods to be automatically registered in the functions dictionary?
One way that I thought it could be done is with a metaclass that look at a pattern in the methods name add if a match is found, add that methods to the functions dictionary. It seems overkill...
Would it be possible to decorate the methods to be registered? Can someone give me a hint to the simplest solution to this problem?
There is no need to construct a dictionary, just use the getattr() built-in function:
def call(self, func_name, args):
getattr(self, func_name)(*args)
Python actually uses a dictionary to access attributes on objects anyway (it's called __dict__, - but using getattr() is better than accessing it directly).
If you really want to construct that dict for some reason, then look at the inspect module:
def __init__(self, ...):
self.functions = dict(inspect.getmembers(self, inspect.ismethod))
If you want to pick specific methods, you could use a decorator to do that, but as BrenBarn points out, the instance doesn't exist at the time the methods are decorated, so you need to use the mark and recapture technique to do what you want.

Using #ndb.tasklet or #ndb.synctasklet in Google App Engine

I have a POST method which calls a few tasklets. These tasklets do have yields in them, and I do have some x.put_async() in my code. So I don't want it to return before all the async stuff is done. So I decorated all my tasklets, which are just small functions with #ndb.tasklet. Also, on top of my POST method, I have:
#ndb.toplevel
def post(self):
However, in the documentation it states:
But if a handler method uses yield, that method still needs to be
wrapped in another decorator, #ndb.synctasklet; otherwise, it will
stop executing at the yield and not finish.
Indeed my method has a yield. It's already wrapped in #ndb.tasklet. Do I replace this with #ndb.synctasklet or do I use both (if so how would I use both)?
Also, see this thread which has some relevance. I too noticed an issue where my request would return without any output, but is un-reproducible. It happens every 15 minutes or so of constant use. I had app = ndb.toplevel(webapp2.WSGIApplication([..]) only, but now I've added #ndb.toplevel to the main POST methods, but the issue still persists.
Should I put #ndb.tasklet on top of methods that have just put_async()'s too? (Should I put it on top of every method just to be safe? What are the downsides to this?)
Regarding the handler and using #ndb.toplevel and #ndb.synctasklet:
The way I understood it was that you need to use both #ndb.synctasklet and #ndb.toplevel on the handler. All the sub-tasklets only need the #ndb.tasklet decorator. e.g.
class Foo(ndb.Model):
name = ndb.StringProperty()
#ndb.tasklet
def my_async(self):
....
#do something else that yields
raise ndb.Return("some result")
#ndb.toplevel
#ndb.synctasklet
def post(self):
foo = Foo(name="baz")
yield foo.put_async()
yield foo.my_async()
....
However. looking at the source, it appears that #ndb.toplevel is actually a synctasklet anyway:
def toplevel(func):
"""A sync tasklet that sets a fresh default Context.
Use this for toplevel view functions such as
webapp.RequestHandler.get() or Django view functions.
"""
Running a small test with yields in the handler and decorated with #ndb.toplevel still seems to work, and appears that you can remove #ndb.synctasklet from the handler.
Regarding whether you should include #ndb.tasklet on methods that call put_async():
If you're not yielding on the put_async(), then you don't need to include #ndb.tasklet on the surrounding method (#ndb.toplevel will handle getting the results from the put_async())

Is it better to have standalone functions in globals or group them in a class?

I have inherited code in which there are standalone functions, one per country code. E.g.
def validate_fr(param):
pass
def validate_uk(param):
pass
My idea is to create a class to group them together and consolidate the code into one method. Unfortunately that breaks cohesion. Another option is to dispatch to instance methods ?
class Validator(object):
def validate(param, country_code):
# dispatch
Alas, python does not have a switch statement.
UPDATE: I am still not convinced why I should leave them as global functions in my module. Lumping them as class methods seems cleaner.
I would keep the functions at module level -- no need for a class if you don't want to instantiate it anyway. The switch statement can easily be simulated using a dicitonary:
def validate_fr(param):
pass
def validate_uk(param)
pass
validators = {"fr": validate_fr,
"uk": validate_uk}
def validate(country_code, param):
return validators[country_code](param)
Given the naming scheme, you could also do it without the dictionary:
def validate(country_code, param):
return gloabls()["validate_" + country_code](param)
You do not need a switch statement for this.
validators = {
'fr': Validator(...),
'uk': Validator(...),
...
}
...
validators['uk'](foo)
Classes are not meant to group functions together, modules are. Functions in a class should be either methods that operate on the object itself (changing it's state, emitting information about the state, etc.) or class methods that do the same, but for the class itself (classes in Python are also objects). There's not even a need for static methods in Python, since you can always have functions at module level. As they say: Flat is better than nested.
If you want to have a set of functions place them in separate module.

Categories

Resources