Multiple variables (regex groups) on Tornado web application path - python

I'm switching from Bottle to Tornado. On Bottle I can easily define paths that has multiple variable parts. Like this:
#app.get('/api/applications/<resource>/running_actions/<action_id>')
def get_application_running_action(resource, action_id):
# Return running action(<action_id>) of the application (<resource>)
On Tornado I would like to have something like this:
app = tornado.web.Application([
(r"/api", ApiRootHandler),
(r"/api/applications/(.*)", ApiApplicationHandler),
(r"/api/applications/(.*)/running_actions/(.*)", ApiRunningActionsHandler),
])
Then ApiRunningActionsHandler would search the application and running actions for the application. But on ApiRunningActionsHandler Get() there is only one path parameter. Is there any way to do this on Tornado or do I just need to parse the path again on ApiRunningActionsHandler? Which actually might not even be possible because I want to direct requests to /api/applications/(.*) to another handler.

I figured it out. Main problem was that my regex was catching everything. So
r"/api/applications/(.*)/running_actions/(.*)"
actually results only one group. Thus action_id argument wasn't set.
Second issue was that most descriptive path must be defined first.
This works:
class ApiRootHandler(tornado.web.RequestHandler):
def get(self):
pass
class ApiApplicationHandler(tornado.web.RequestHandler):
def get(self, action_name):
pass
class ApiRunningActionsHandler(tornado.web.RequestHandler):
def get(self, action_name, action_id):
self.write("action_name: " + action_name + ", action_id: " + action_id)
app = tornado.web.Application([
(r"/api/applications/(\w+)/running_actions/([0-9]+)", ApiRunningActionsHandler),
(r"/api/(\w+)", ApiApplicationHandler),
(r"/api/", ApiRootHandler),
])
app.listen(8888)
tornado.ioloop.IOLoop.current().start()

Just make the second argument to ApiApplicationHandler.get optional:
class ApiApplicationHandler(RequestHandler):
def get(self, resource, action_id=None):
pass

Related

How to pass arguments to a page class with web.py?

I have several classes in my program.
The main one called WebServer creates the web.py application itself, and calls to other classes for the webpages. Can I pass self.var1 for example to the search class __init__? Because I thought of just creating a method in the index class like set_var1 or something like that, then I don't know how to access the specific instance of this class the the web application creates.
The class:
import sys
import os
import web
from pages.search import search
from pages.index import index
class WebServer:
def __init__(self):
self.var1 = "test"
self.urls = (
'/', 'index',
'/search', 'search'
)
self.app = web.application(self.urls, globals())
self.app.run()
if __name__ == "__main__":
w = WebServer()
Not really, no. Specific instances of search and index are created by web.py in response to an incoming request. There are better / easier ways.
Also, putting this initialization in a WebServer class, while possible, isn't the common way of doing it with web.py. There's no need for the class to do this: it's a singleton and this file is essentially a startup / configuration file.
To have application-wide information available to your "response" classes (search, index, etc.), make that information either global, or hook it into web.config which is a web.Storage(). For example:
app = web.application(urs, globals())
web.config.update({"var1" : "test"})
app.run()
Which is then available to you responses. For example:
class search(object):
def GET(self):
if web.config.var1 == 'test':
return do_test_search()
return do_regular_search()

How to use correctly importlib in a flask controller?

I am trying to load a module according to some settings. I have found a working solution but I need a confirmation from an advanced python developer that this solution is the best performance wise as the API endpoint which will use it will be under heavy load.
The idea is to change the working of an endpoint based on parameters from the user and other systems configuration. I am loading the correct handler class based on these settings. The goal is to be able to easily create new handlers without having to modify the code calling the handlers.
This is a working example :
./run.py :
from flask import Flask, abort
import importlib
import handlers
app = Flask(__name__)
#app.route('/')
def api_endpoint():
try:
endpoint = "simple" # Custom logic to choose the right handler
handlerClass = getattr(importlib.import_module('.'+str(endpoint), 'handlers'), 'Handler')
handler = handlerClass()
except Exception as e:
print(e)
abort(404)
print(handlerClass, handler, handler.value, handler.name())
# Handler processing. Not yet implemented
return "Hello World"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080, debug=True)
One "simple" handler example. A handler is a module which needs to define an Handler class :
./handlers/simple.py :
import os
class Handler:
def __init__(self):
self.value = os.urandom(5)
def name(self):
return "simple"
If I understand correctly, the import is done on each query to the endpoint. It means IO in the filesystem with lookup for the modules, ...
Is it the correct/"pythonic" way to implement this strategy ?
Question moved to codereview. Thanks all for your help : https://codereview.stackexchange.com/questions/96533/extension-pattern-in-a-flask-controller-using-importlib
I am closing this thread.

How do you break Python Flask controller flow when calling return inside a function?

I'm using Python Flask and I got defined the following function:
def verify_session():
if not 'logged_in' in session:
flash("You are not logged in.<br/>Please, log in to use our application.", "warning")
return redirect(url_for('login_path'))
This is meant to be called in every controller. I know that I could use #app.before_request but on some places I dont want this function to be called (in the same Login page, for example) and I really dont want the function to check the excluded paths.
My problem is this: inside any Flask controller for each of the paths the first lines look like this:
#app.route('/web/account', methods=["GET"], endpoint="account_path")
def account():
verify_session()
return render_template('account')
But, despite I get the "You need to login" flashed message, it still returns the Account page, because the return inside verify_session just returns for this function.
What I need is something like return verify_session() but that doesn't end the controller flow unless it actually is necessary to return it.
Maybe this problem is only Python/Programming specific rather than Flask so I excuse myself and ask moderators to edit my Question accordingly. I mention Flask because it's the enviroment where I'm having the trouble.
IF more information is needed I'm willing to update. Thank you in advance.
result = verify_session()
if not result:
result = render_template("account")
return result
but really you should be using a decorator for this
def verify_session(fn):
def inner(*args,**kwargs):
if not 'logged_in' in session:
flash("You are not logged in.<br/>Please, log in to use our application.", "warning")
return redirect(url_for('login_path'))
return fn(*args,**kwargs)
return inner
then you would use it like
#app.route('/web/account', methods=["GET"], endpoint="account_path")
#verify_session #make sure to use any decorators after the route decorator
def account():
return render_template('account')
lastly ... I hope you are aware that you are reinventing the wheel and you should probably just use flask-login to manage this stuff(unless you have a pretty compelling reason not to)
To add to Joran's excellent answer. Instead of using #app.before_request, you can put your login required routes in a blueprint and then use #blueprint.before_request:
account = Blueprint('account', __name__)
#account.before_request
def verify_session():
...
#account.route('/')
def index():
...
Then in your app:
app = Flask(__name__)
app.register_blueprint(account, url_prefix='/web/account')

Calling another view in Pyramid

My goal: In Pyramid, to call another view-callable, and to get a Response object back without knowing any details about that view-callable.
In my Pyramid application, say I have a view "foo" which is defined using a view_config decorator:
#view_config(route_name="foo",
renderer="foo.jinja2")
def foo_view(request):
return {"whereami" : "foo!"}
Now say that I want to route "bar" to a view that does the same thing for the time being, so it internally calls foo_view and returns its Response:
#view_config(route_name="bar")
def bar_view(request):
return foo_view(request)
...but wait! That doesn't work, since foo_view doesn't return a Response, its renderer does.
So, this will work:
#view_config(route_name="bar",
renderer="foo.jinja2")
def bar_view(request):
return foo_view(request)
as it will apply the same renderer as foo_view did. But this is bad, as I now must repeat myself by copying the renderer value AND having to know the renderer of the view being called.
So, I am going to hope that there is some function available in Pyramid that allows calling another view-callable and getting a Response object back without knowing or caring how it was rendered:
#view_config(route_name="bar")
def bar_view(request):
response = some_function_that_renders_a_view_callable(foo_view, request)
return response
What would some_function_that_renders_a_view_callable be?
pyramid.views.render_view appears to search for a view by name; I don't want to give my views names.
(Note: Returning HTTPFound to cause the client to redirect to the target route is what I am trying avoid. I want to "internally" redirect).
Yep. There is some concerns
doesn't return a Response
predicates/renderer
permissions
request properties associated to old request
Thats why you should not call view from view as function, unless you know what you doing
Pyramid creators did awesome tool for server side redirect - http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/subrequest.html
You can invoking a view with using request.invoke_subrequest:
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.request import Request
def view_one(request):
subreq = Request.blank('/view_two')
response = request.invoke_subrequest(subreq)
return response
def view_two(request):
request.response.body = 'This came from view_two'
return request.response
if __name__ == '__main__':
config = Configurator()
config.add_route('one', '/view_one')
config.add_route('two', '/view_two')
config.add_view(view_one, route_name='one')
config.add_view(view_two, route_name='two')
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()`
When /view_one is visted in a browser, the text printed in the
browser pane will be "This came from view_two". The view_one view
used the pyramid.request.Request.invoke_subrequest() API to obtain a
response from another view (view_two) within the same application
when it executed. It did so by constructing a new request that had a
URL that it knew would match the view_two view registration, and
passed that new request along to
pyramid.request.Request.invoke_subrequest(). The view_two view
callable was invoked, and it returned a response. The view_one view
callable then simply returned the response it obtained from the
view_two view callable.
I was struggling with this as well. I have a solution using the render_to_response method, though I'm sure there's a "more correct" way to do it. Until someone posts it, however, here is how I handled this:
from pyramid.renderers import render_to_response
#view_config(route_name="foo", renderer="foo.mak")
def foo_view(request):
return {'stuff':'things', '_renderer':'foo.mak')
def bar_view(request):
values = foo_view(request)
renderer = values['_renderer']
return render_to_response(renderer,values)
(Pyramid 1.3)
This requires a renderer to be used, but by declaring that renderer in the original view's return values, you can retrieve it in another view without knowing what it is. I'm suspecting the need to do this isn't easily findable because there's other, better methods for accomplishing tasks solved by this solution.
Another shortcoming is that it relies on direct import of the view callable. It would be nice if it could be looked up directly by route.
The Pyramid documentation here indicates that leaving the name key word argument out of view_config will cause the view to be registered by the function itself (rather than a string):
Such a registration... implies that the view name will be *my_view*
So, in your case you should be able to use pyramid.view.render_view or pyramid.view.render_view_to_response referencing foo_view directly:
#view_config(route_name="bar")
def bar_view(request):
return pyramid.views.render_view_to_response(None, request, name=foo_view)
Update:
Yep, your right, passing the view function does not work.
It's interesting, but taking your example code and applying the route_name to the config
did not work for me. However, the following example, just giving the view a name sets the route url
and gives the view a name. In this fashion render_view_to_response works as advertised. Naming,
your views may not be what you want, but this configuration accomplishes the same thing as your
example code without added configuration.
#view_config(name="foo")
def foo_view(request):
# returning a response here, in lieu of having
# declared a renderer to delegate to...
return Response('Where am i? `{0[whereami]}'.format({"whereami" : "foo!"}))
#view_config(name="bar")
def bar_view(request):
# handles the response if bar_view has a renderer
return render_view_to_response(None, request, name='foo')
#view_config(name="baz")
def baz_view(request):
# presumably this would not work if foo_view was
# not returning a Response object directly, as it
# skips over the rendering part. I think you would
# have to declare a renderer on this view in that case.
return foo_view(request)
if __name__ == '__main__':
config = Configurator()
config.scan()
app = config.make_wsgi_app()
serve(app, host='127.0.0.1', port='5000')
Not the precise solution you asked for, but a solution to the problem you describe:
Create a view class, of which both foo and bar are methods. Then bar can call self.foo()
Common view_configuration, such as the template name can be applied to the class, and then you can decorate each method with just the view name.
In short, the following should meet your needs, if I understand the problem correctly.
#view_defaults(renderer="foo.jinja2")
class WhereaboutsAreFoo(object):
#view_config(route-name="foo")
def foo_view(self):
return {"whereami" : "foo!"}
#view_config(route-name="bar")
def bar_view(self):
return self.foo_view()
can't you do something like that:
#view_config(name="baz")
def baz_view(request):
return HTTPFound(location=self.request.route_path('foo'))

using a colon in a string in python

i am using python 2.6.5 to develop an app for google app engine - i am not too familiar with python, but i'm learning.
i am trying to put a url into a string so variable = "string http://domain.name"
then i print the string out. the problem is, if the colon (after http) is in the string, i don't get any output and i don't know why.
i've tried escaping the string with:
"""http://domain.name"""
r"http://domain.name"
"http\://domain.name"
"http\://domain.name"
"http\\://domain.name"
"http:://domain.name"
none of them seem to work and i'm not sure what else to try
The context is like so
variables.py is:
...
HOST_URL = "http://domain.name"
...
example logout.py
import variables
import sys
...
class Logout(webapp.RequestHandler):
""" RequestHandler for when a user wishes to logout from the system."""
def post(self):
self.get()
def get(self):
print(variables.HOST_URL)
print('hi')
self.redirect(variables.HOST_URL)
sys.exit()
or
in file functions.py
import variables
import sys
...
def sendhome(requesthandler)
print 'go to '+variables.HOST_URL
requesthandler.redirect(variables.HOST_URL)
sys.exit()
called from a context like:
from functions import sendhome
...
class Logout(webapp.RequestHandler):
""" RequestHandler for when a user wishes to logout from the system."""
def post(self):
self.get()
def get(self):
sendhome(self)
any help would be appreciated
thanks
If I'm not terrible mistaken, GAE uses WSGI, you do not simply print things, you are supposed to return a proper HTTP response object (it is not PHP).
I guess that if you access the page using firefox+firebug and look at the network->header you will see that the browser is taking http: as an HTTP header with value "//domain.name".
Edited: By the way, should not you be using "self.response.out.write" instead of "print"?
The problem was the sys.exit() after the call to print or redirect

Categories