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

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()

Related

Multiple variables (regex groups) on Tornado web application path

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

Python and nesting classes for structure

I am having a bit of trouble with nesting classes in python.
Mind you my code below is a simplified example showing what I want to do, but basically I want to use nested classes to make my code more structured and make sure I don't run into name clashes for certain functions.
See here my example code:
class Chrome:
def __init__(self, url='http://localhost:4723/wd/hub'):
# Capabilities
capabilities = Capabilities.chrome()
# Start session
self.driver = webdriver.Remote(url, capabilities)
def get_url(self, url):
# Go to URL
self.driver.get(url)
class actions:
#staticmethod
def browse_url(url):
# Go to url
Chrome.get_url(url)
if __name__ == '__main__':
browser = Chrome()
browser.actions.browse_url('https://www.google.com')
The goal as you can see in if __name__ == '__main__' is to be able to start a browser instance, and then call functions in a structured way.
However I have no clue on how to correctly achieve the browser.actions.browse_url('https://www.google.com') concept.
How is this done correctly ?
You should call get_url from an instance of Chrome and not the class itself, since it's an instance method and not a static one:
...
#staticmethod
def browse_url(url):
Chrome().get_url(url)
...
if __name__ == '__main__':
Chrome.actions.browse_url('https://www.google.com')

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 can i move python functions into different .py file?

i want to move functions because of lot of files, into separate python files.
But if i do it, it dont work.
I tried:
File: server.py:
import os, cherrypy, json
from customers.py import *
class application(object):
def get_webpage(self):
....
def get_data(self):
....
File: customers.py:
import os, cherrypy, json
def get_customer_data(self):
....
I use the python as server,
the data in the function: get_customer_data is in this case not processed, get a 404 Not Found,
means the function is not included in main file (server.py)
I removed the self from get_webpages() because it was not indented, which means it was not part of the class.
application.py:
class application(object):
def __init__(self):
pass
def get_webpage():
print('From application')
customers.py:
from application import *
get_webpage() # From application
You could indent get_webpages() and make it part of the class. The way you call it would change. (I put the self back and capitalized the name of the class.)
application.py:
class Application(object):
def __init__(self):
pass
def get_webpage(self):
print('From application')
customers.py:
from application import *
a = Application()
a.get_webpage() # From application

what's better way to share connection pool between inside RequestHandler and outside RequestHandler in tornado

What's the better way to share a connection_pool in both Application/Handler and other place outside Handler like a test file, or a model file?
in main.py, I define a db_pool in Application, I could use it in any RequestHandler, what if I want to use it outside RequestHandler?
What's the better practice?
code in main.py
import tornado.web
class Application(tornado.web.Application):
"""
自定义的Application
"""
def __init__(self):
# I have a db_pool here
init_dict = {
'db_pool': PooledDB.PooledDB(MySQLdb, **db_server)
}
super(Application, self).__init__(
[(r'/', IndexHandler, init_dict)],
**settings)
code in test.py
from main import Application
# I want to get db_pool here
code in dao.py
def get_config(user):
# I want to get db_pool in main
db = db_pool.connection()
return
Could you help me?
I would store the connection pool inside the Application class, instead of passing it to your Handlers. Then, you could access the application inside your handler by calling self.application inside your GET/POST methods.
class Application(tornado.web.Application):
def __init__(self):
self.db = PooledDB.PooledDB(MySQLdb, **db_server)
super(Application, self).__init__([(r'/', IndexHandler)], **settings)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.application.db.<put a valid method here>()

Categories