In my Flask app I am setting a number of local variables that have come in via an API call, using the
from flask import request
.
.
submission_id = request.args.get('submission_id')
grader = request.args.get('grader')
grading_factor = float(request.args.get('grading_factor'))
answer_key = request.args.get('answer_key')
submission_key = request.args.get('submission_key')
What is a less repetitive or otherwise more Pythonic way of setting these 5 variables?
As I suggested in the comments, you could come up with a decorator that would map the request arguments to the corresponding function parameters, such as:
def map_args(func):
#functools.wraps(func)
def wrapper(**kwargs):
all_args = dict(request.args, **kwargs)
return func(**all_args)
return wrapper
Then:
#app.route('/mypath')
#map_args
def handler(submission_id, grader, grading_factor, ...):
"""the remaining logic"""
That's similar to what Flask does with the view_args, except that it does not do any type conversions, which this margin is too narrow to contain.
from flask import Flask, request
app = Flask(__name__)
class DotDict(object):
def __init__(self, inner):
self._inner = inner
def __getattr__(self, item):
return self._inner.get(item)
def get(self, item, default=None):
return self._inner.get(item, default)
class LazyAttribute(object):
def __init__(self, obj, attr):
self.obj = obj
self.attr = attr
def __getattribute__(self, item):
return getattr(getattr(object.__getattribute__(self, 'obj'),
object.__getattribute__(self, 'attr')),
item)
rargs = DotDict(LazyAttribute(request, 'args'))
#app.route("/")
def hello():
print rargs.a, rargs.c, rargs.get('d', 3)
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
Accessing http://localhost:5000/?a=1 prints 1 None 3 in the terminal.
The LazyAttribute class is because calling just DotDict(request.args) outside of a request context throws an error. The alternative is to make a function:
def rargs():
return DotDict(request.args)
but I wanted to make usage as smooth as possible.
Firstly, I don't think there's anything wrong with the way you're doing it. But, there are a couple of different approaches you could take; the first being to the call to get the argument from request:
from flask import request
# ...
def getRequestArg(name, *args):
return request.args.get(name, *args)
submission_id = getRequestArg('submission_id')
grader = getRequestArg('grader')
grading_factor = float(getRequestArg('grading_factor'))
answer_key = getRequestArg('answer_key')
submission_key = getRequestArg('submission_key')
If you don't need each of these to be separate local variables, you could store them all in a dict:
from flask import request
# ...
args = {}
arg_names = ('submission_id', 'grader', 'grading_factor', 'answer_key', 'submission_key')
for arg in arg_names:
args[arg] = request.args.get(arg)
Related
How can I pass the arguments val and code to the group get
Code so far
import fire
class Get:
def __init__(self, val="no", code=""):
self.val = val
self.code = code
def get(self):
return f"called get {self.val} {self.code}"
def get_many(self):
return f"called get many {self.val}"
class Pipeline:
def __init__(self,):
self.get = Get()
def main():
fire.Fire(Pipeline)
The error I Got
$> my_p get --code="test" --val="yes" get
ERROR: Could not consume arg: --code=test
Usage: my_p get get <command>
according to https://github.com/google/python-fire/blob/master/docs/guide.md#version-4-firefireclass
you need to change :
self.get = Get
Besides, I recommend to not use the same name in "get" function in class Get. It is confusing.
import fire
class Get(object):
def __init__(self, attr):
self.attr = attr
def get(self):
return f"called get {self.attr.val} {self.attr.code}"
def get_many(self):
return f"called get many {self.attr.val}"
class Pipeline(object):
def __init__(self, **kwargs):
for key, val in kwargs.items():
self.__dict__[key] = kwargs.get(key, val)
self.get = Get(self)
if __name__ == "__main__":
fire.Fire(Pipeline)
output
python my_p.py get --code="test" --val="yes" get
called get yes test
I have this class:
class SomeMixin:
permissions = (SomePermission,)
methods = ('GET',)
#list_route(methods=methods, url_path='en', permission_classes=permissions)
def en_list(self):
return get_translated_objects(self, 'en')
#list_route(methods=methods, url_path='ru', permission_classes=permissions)
def ru_list(self):
return get_translated_objects(self, 'ru')
#detail_route(methods=methods, url_path='en', permission_classes=permissions)
def en_detail(self):
return get_translated_object(self.get_object(), 'en')
#detail_route(methods=methods, url_path='ru', permission_classes=permissions)
def ru_detail(self):
return get_translated_object(self.get_object(), 'ru')
I can have more languages in the future and it's not a good solution.
I thought to create loop of languages list and add methods to the class with setattr(self, func_name, func), like:
langs = ('en', 'ru')
for lang in langs:
setattr(self, func.__name__, func)
But I should add decorators to every method, how can I do it?
I believe you should be able to patch the contents of this example into your code. That being said, it seems like a better approach to detect the language from the http header and return an appropriate response.
This approach though functional is not the cleanest.
# This decorator is meant to simulate the decorator exposed by django
def route(url, language, method):
def wrapper(func):
def inner(*args, **kwargs):
print('url => {0}'.format(url))
print('language => {0}'.format(language))
print('method => {0}'.format(method))
func(*args, **kwargs)
return inner
return wrapper
# This class is analogous to your SomeMixin class
class foo(object):
def __init__(self):
method = 'GET'
# fields holds the parameters that will change for each method like url
# and language
fields = (('en', '/en', 'en_list'), ('ru', '/ru', 'ru_list'))
for lang, url, func_name in fields:
setattr(self, func_name, route(url=url, language=lang, method=method)(self.func_creator(lang)))
def func_creator(self, language):
def inner():
print('hello in {0}'.format(language))
return inner
def main():
foo_instance = foo()
print('Calling foo.en_list()')
foo_instance.en_list()
print()
print('Calling foo.ru_list()')
foo_instance.ru_list()
if __name__ == '__main__':
main()
I'll start by saying, I have a suspicion this is a solution that could be solved with a functional programming approach, but I don't know nearly enough of the concepts (but have been trying).
I've based my current solution on:
https://pythonconquerstheuniverse.wordpress.com/2012/04/29/python-decorators/
http://www.brianholdefehr.com/decorators-and-functional-python
https://github.com/mitsuhiko/click/blob/master/click/decorators.py
In the interest of learning (that's all this is!) how to build decorators, I decided to make a simple cache decorator.
But I get stuck in a loop where, I try to encapsulate the function I'm wrapping in a class, but every time I call the function I've wrapped, I call __call__ in wrapping class and so on ad infinitum.
I think I could have a nest of closures between the chain decorators, but I don't know how to collect all my variables in one scope.
I appreciate I could put all my arguments in a single decorator call, but my intention here is to learn how to chain decorators and store state between them.
Can anyone suggest a way (or ammend my way) to store state between chained decorators?
My intended design was:
# main.py
import http.client
from cache import cache
#cache.keys('domain', 'url')
#cache.lifetime(3600)
def make_http_request(domain,url='/'):
conn = httplib.HTTPConnection(domain)
conn.request("GET",url)
return conn.getresponse()
if __name__ == '__main__':
print(make_http_request('http://example.com/'))
with cache.py looking like
import hashlib
import os
import inspect
__author__ = 'drews'
def expand(path):
return os.path.abspath(os.path.expanduser(path))
class CacheManager():
"""Decorator to take the result and store it in a a file. If the result is needed again, then the file result is returned"""
def __init__(self, function, function_arg_name):
self.lifetime = 3600
self.cache_keys = None
self.cache_path = '~/.decorator_cache/'
self.f = function
self.arg_names = function_arg_name
def __call__(self, *args, **kwargs):
if len(args) > 0:
arg_names = self.arg_names
if 'self' in arg_names:
arg_names.remove('self')
key_args = dict(zip(arg_names, args))
key_args.update(kwargs)
else:
key_args = kwargs
self._initialise(cache_path=expand(self.cache_path))
key = self._build_key(key_args)
if self.key_exists(key):
result = self.get_key(key)
else:
result = self.f()
self.set_key(key, result)
return result
def _build_key(self, key_elements):
m = hashlib.md5()
for key in self.cache_keys:
m.update(key_elements[key].encode('utf-8'))
return m.hexdigest()
def _initialise(self, cache_path):
def initialise_path(path):
if not os.path.isdir(path):
(head, tail) = os.path.split(path)
if not os.path.isdir(head):
initialise_path(head)
os.mkdir(path)
initialise_path(cache_path)
def key_exists(self, key):
path = os.path.join(expand(self.cache_path), key)
return os.path.exists(path)
class CacheDefinitionDecorator(object):
def __init__(self, *args, **kwargs):
self.d_args = args
class CacheKeyDefinitionDecorator(CacheDefinitionDecorator):
def __call__(self, func, *args, **kwargs):
if not isinstance(func, CacheManager):
func = CacheManager(func,inspect.getargspec(func)[0])
func.cache_keys = self.d_args
return func
class CacheLifetimeDefintionDecorator(CacheDefinitionDecorator):
def __call__(self, func, *args, **kwargs):
if not isinstance(func, CacheManager):
func = CacheManager(func,inspect.getargspec(func)[0])
func.lifetime = self.d_args[0]
return func
class CacheStruct(object):
def __init__(self, **kwargs):
for item in kwargs:
setattr(self, item, kwargs[item])
cache = CacheStruct(
keys=CacheKeyDefinitionDecorator,
lifetime=CacheLifetimeDefintionDecorator
)
I've done some coding with Bottle. It's really simple and fits my needs. However, I got stick when I tried to wrap the application into a class :
import bottle
app = bottle
class App():
def __init__(self,param):
self.param = param
# Doesn't work
#app.route("/1")
def index1(self):
return("I'm 1 | self.param = %s" % self.param)
# Doesn't work
#app.route("/2")
def index2(self):
return("I'm 2")
# Works fine
#app.route("/3")
def index3():
return("I'm 3")
Is it possible to use methods instead of functions in Bottle?
Your code does not work because you are trying to route to non-bound methods. Non-bound methods do not have a reference to self, how could they, if instance of App has not been created?
If you want to route to class methods, you first have to initialize your class and then bottle.route() to methods on that object like so:
import bottle
class App(object):
def __init__(self,param):
self.param = param
def index1(self):
return("I'm 1 | self.param = %s" % self.param)
myapp = App(param='some param')
bottle.route("/1")(myapp.index1)
If you want to stick routes definitions near the handlers, you can do something like this:
def routeapp(obj):
for kw in dir(app):
attr = getattr(app, kw)
if hasattr(attr, 'route'):
bottle.route(attr.route)(attr)
class App(object):
def __init__(self, config):
self.config = config
def index(self):
pass
index.route = '/index/'
app = App({'config':1})
routeapp(app)
Don't do the bottle.route() part in App.__init__(), because you won't be able to create two instances of App class.
If you like the syntax of decorators more than setting attribute index.route=, you can write a simple decorator:
def methodroute(route):
def decorator(f):
f.route = route
return f
return decorator
class App(object):
#methodroute('/index/')
def index(self):
pass
You have to extend the Bottle class. It's instances are WSGI web applications.
from bottle import Bottle
class MyApp(Bottle):
def __init__(self, name):
super(MyApp, self).__init__()
self.name = name
self.route('/', callback=self.index)
def index(self):
return "Hello, my name is " + self.name
app = MyApp('OOBottle')
app.run(host='localhost', port=8080)
What most examples out there are doing, including the answers previously provided to this question, are all reusing the "default app", not creating their own, and not using the convenience of object orientation and inheritance.
Below works nicely for me :)
Quite object orientated and easy to follow.
from bottle import Bottle, template
class Server:
def __init__(self, host, port):
self._host = host
self._port = port
self._app = Bottle()
self._route()
def _route(self):
self._app.route('/', method="GET", callback=self._index)
self._app.route('/hello/<name>', callback=self._hello)
def start(self):
self._app.run(host=self._host, port=self._port)
def _index(self):
return 'Welcome'
def _hello(self, name="Guest"):
return template('Hello {{name}}, how are you?', name=name)
server = Server(host='localhost', port=8090)
server.start()
I took #Skirmantas answer and modified it a bit to allow for keyword arguments in the decorator, like method, skip, etc:
def routemethod(route, **kwargs):
def decorator(f):
f.route = route
for arg in kwargs:
setattr(f, arg, kwargs[arg])
return f
return decorator
def routeapp(obj):
for kw in dir(obj):
attr = getattr(obj, kw)
if hasattr(attr, "route"):
if hasattr(attr, "method"):
method = getattr(attr, "method")
else:
method = "GET"
if hasattr(attr, "callback"):
callback = getattr(attr, "callback")
else:
callback = None
if hasattr(attr, "name"):
name = getattr(attr, "name")
else:
name = None
if hasattr(attr, "apply"):
aply = getattr(attr, "apply")
else:
aply = None
if hasattr(attr, "skip"):
skip = getattr(attr, "skip")
else:
skip = None
bottle.route(attr.route, method, callback, name, aply, skip)(attr)
try this, worked for me, documentation is also pretty decent to get started with ...
https://github.com/techchunks/bottleCBV
I know this question is quite old, but it is useful.
I am currently refactoring a Bottle application code into class. I am thinking about using something like:
import bottle
class App:
def __init__(self, port=80):
self.app = bottle.Bottle()
self.port = port
def setup_routes(self):
#self.app.route("/foo")
def foo():
return("foo")
#self.app.route("/bar")
def bar():
return("bar")
def start(self):
self.app.run(port=self.port)
a = App()
a.setup_routes()
a.start()
Does it work for your applications too? Feel free to comment, I am interested about this.
Notes from the creator of Bottle: https://github.com/bottlepy/bottle/issues/1224#issuecomment-619344849
I've done some coding with Bottle. It's really simple and fits my needs. However, I got stick when I tried to wrap the application into a class :
import bottle
app = bottle
class App():
def __init__(self,param):
self.param = param
# Doesn't work
#app.route("/1")
def index1(self):
return("I'm 1 | self.param = %s" % self.param)
# Doesn't work
#app.route("/2")
def index2(self):
return("I'm 2")
# Works fine
#app.route("/3")
def index3():
return("I'm 3")
Is it possible to use methods instead of functions in Bottle?
Your code does not work because you are trying to route to non-bound methods. Non-bound methods do not have a reference to self, how could they, if instance of App has not been created?
If you want to route to class methods, you first have to initialize your class and then bottle.route() to methods on that object like so:
import bottle
class App(object):
def __init__(self,param):
self.param = param
def index1(self):
return("I'm 1 | self.param = %s" % self.param)
myapp = App(param='some param')
bottle.route("/1")(myapp.index1)
If you want to stick routes definitions near the handlers, you can do something like this:
def routeapp(obj):
for kw in dir(app):
attr = getattr(app, kw)
if hasattr(attr, 'route'):
bottle.route(attr.route)(attr)
class App(object):
def __init__(self, config):
self.config = config
def index(self):
pass
index.route = '/index/'
app = App({'config':1})
routeapp(app)
Don't do the bottle.route() part in App.__init__(), because you won't be able to create two instances of App class.
If you like the syntax of decorators more than setting attribute index.route=, you can write a simple decorator:
def methodroute(route):
def decorator(f):
f.route = route
return f
return decorator
class App(object):
#methodroute('/index/')
def index(self):
pass
You have to extend the Bottle class. It's instances are WSGI web applications.
from bottle import Bottle
class MyApp(Bottle):
def __init__(self, name):
super(MyApp, self).__init__()
self.name = name
self.route('/', callback=self.index)
def index(self):
return "Hello, my name is " + self.name
app = MyApp('OOBottle')
app.run(host='localhost', port=8080)
What most examples out there are doing, including the answers previously provided to this question, are all reusing the "default app", not creating their own, and not using the convenience of object orientation and inheritance.
Below works nicely for me :)
Quite object orientated and easy to follow.
from bottle import Bottle, template
class Server:
def __init__(self, host, port):
self._host = host
self._port = port
self._app = Bottle()
self._route()
def _route(self):
self._app.route('/', method="GET", callback=self._index)
self._app.route('/hello/<name>', callback=self._hello)
def start(self):
self._app.run(host=self._host, port=self._port)
def _index(self):
return 'Welcome'
def _hello(self, name="Guest"):
return template('Hello {{name}}, how are you?', name=name)
server = Server(host='localhost', port=8090)
server.start()
I took #Skirmantas answer and modified it a bit to allow for keyword arguments in the decorator, like method, skip, etc:
def routemethod(route, **kwargs):
def decorator(f):
f.route = route
for arg in kwargs:
setattr(f, arg, kwargs[arg])
return f
return decorator
def routeapp(obj):
for kw in dir(obj):
attr = getattr(obj, kw)
if hasattr(attr, "route"):
if hasattr(attr, "method"):
method = getattr(attr, "method")
else:
method = "GET"
if hasattr(attr, "callback"):
callback = getattr(attr, "callback")
else:
callback = None
if hasattr(attr, "name"):
name = getattr(attr, "name")
else:
name = None
if hasattr(attr, "apply"):
aply = getattr(attr, "apply")
else:
aply = None
if hasattr(attr, "skip"):
skip = getattr(attr, "skip")
else:
skip = None
bottle.route(attr.route, method, callback, name, aply, skip)(attr)
try this, worked for me, documentation is also pretty decent to get started with ...
https://github.com/techchunks/bottleCBV
I know this question is quite old, but it is useful.
I am currently refactoring a Bottle application code into class. I am thinking about using something like:
import bottle
class App:
def __init__(self, port=80):
self.app = bottle.Bottle()
self.port = port
def setup_routes(self):
#self.app.route("/foo")
def foo():
return("foo")
#self.app.route("/bar")
def bar():
return("bar")
def start(self):
self.app.run(port=self.port)
a = App()
a.setup_routes()
a.start()
Does it work for your applications too? Feel free to comment, I am interested about this.
Notes from the creator of Bottle: https://github.com/bottlepy/bottle/issues/1224#issuecomment-619344849