How to use class methods instead of functions in Bottle microframework? - python

I am trying to use methods of my own class instead of funcons.
But ths code fails due to "syntax error". What am i doing wrong?
from bottle import route, run, template
class controller():
def test(self):
return ("<h1>Its a main page!</h1>")
def hello(self,name):
return "Hello {0}".format(name)
sc = controller()
#route('/test')
sc.test()
#route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
#route('/')
def indexFunc():
return ('<h1>Hello on first App!!</h1>!')
run(host='localhost', port=8080)

sc.test() returns a string. You can't decorate a string. So the first problem is, you are calling that method (and therefore trying to decorate its result) instead of decorating the method itself.
The second problem is that the # decorator syntax must be followed by a function definition, i.e., a def keyword. You could write a function that does nothing but call sc.test(), as shown by llyas. Or you can take advantage of the fact that the # is simply syntactic sugar for a function call, and just write:
route('/test')(sc.test)

You cannot decorate a function call, you decorate a function definition.
Try replacing this line:
sc.test()
wiith this:
#route('/test')
def view():
return sc.test()

Related

How can I use the same parameters in a decorator with that in the functions in Python?

I want use a same param in decorater and function like:
def outer(deco_param):
def decorator(func):
print("param:%s" % deco_param)
return func
return decorator
#outer(deco_param=s) # problems here: 's' is unreferenced
def test(s):
print("test:%s" % s)
I got this idea when using Flask but I didn't know how did they make it, which supports using a param of view function in its decorater like:
app.route(rule="/user/<int:uid>")
def access_user(uid): # if I use any other name except from 'uid', IDE would raise a tip
...
What's more, Flask seems to make a static check. If I miss uid argument or use any other name, IDE(pycharm) would raise a tip of "Function 'access_user` doesn't have a parameter 'int:uid'". That's the effect I want.
Can anyone please give me some advice? Thanks
You don't need to pass the same parameter to both the outer function and the inner function. To call the parameters via decorator, you should add a wrapper function to pass the parameters (*args) from inner one to outer one.
You can write like this:
def outer():
def decorator(func):
def wrapper(*args):
print("param:%s" % func.__param__)
return func(*args)
return wrapper
return decorator
#outer
def test(s):
print("test:%s" % s)

How to group decorators in Python

In Flask I'm using a set of decorators for each route, but the code is "ugly":
#app.route("/first")
#auth.login_required
#crossdomain(origin='*')
#nocache
def first_page:
....
#app.route("/second")
#auth.login_required
#crossdomain(origin='*')
#nocache
def second_page:
....
I would prefer to have a declaration that groups all of them with a single decorator:
#nice_decorator("/first")
def first_page:
....
#nice_decorator("/second")
def second_page:
....
I tried to follow the answer at Can I combine two decorators into a single one in Python? but I cannot make it working:
def composed(*decs):
def deco(f):
for dec in reversed(decs):
f = dec(f)
return f
return deco
def nice_decorator(route):
composed(app.route(route),
auth.login_required,
crossdomain(origin="*"),
nocache)
#nice_decorator("/first")
def first_page:
....
because of this error that I don't understand:
#nice_decorator("/first")
TypeError: 'NoneType' object is not callable
Following one of the comments I defined it with another form that works but without the possibility to specify the route parameter:
new_decorator2 = composed(app.route("/first"),
auth.login_required,
crossdomain(origin="*"),
nocache)
Is it possible to define a single decorator with parameters?
You're not defining the composition correctly. You need to change the definition of nice_decorator to something like this:
def nice_decorator(route):
return composed(
app.route(route),
auth.login_required,
crossdomain(origin="*"),
nocache
)
Your previous version never actually returned anything. Python isn't like Ruby or Lisp where the last expression is the return value.

Python - Multiple decorators to a method malfunctioning

I am trying to learn decorators and have overcome a strange condition while having multiple decorators for a method. I have two decorators #makeupper and #decorator_maker_with_arguments.
#decorator_maker_with_arguments demonstrates how the arguments are accessed inside a decorator. This works perfectly fine by printing the supplied args but I see #makeupper malfunctioning. It prints None. I have put a print statement next to its method definition to see if its called and it printed but never prints the letters in hello() uppercase.
When I comment out #decorator_maker_with_arguments("swadhikar", "c") I see the #makeupper works good. Can someone explain what I am tangling here?
def makeupper(some_fun):
def wrapper(arg1, arg2):
return some_fun(arg1, arg2).upper()
return wrapper
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return wrapper
return my_decorator
#decorator_maker_with_arguments("swadhikar", "c")
#makeupper
def hello(ar1, ar2):
return "Hello User!"
Result:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "hello_arg1:another hello arg..."
None
but I see #makeupper malfunctioning. It prints None
makeupper isn't malfunctioning. The outer decorator decorator_maker_with_arguments isn't calling the wrapper of makeupper.
And then you have a None because you're not returning anything from the wrapper of decorator_maker_with_arguments.
The following modifications to decorator_maker reflect the proposed adjustments:
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
out = fn(fn_arg1, fn_arg2)
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return out
return wrapper
return my_decorator
Output:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "hello_arg1:another hello arg..."
HELLO USER!
You could add some syntactic sugar by decorating your wrappers with functool.wraps, but arguably it's necessary, at least if you want to keep things like function names, docstrings, etc.
You can add return statement inside my_decorator wrapper function.
Like following:
def makeupper(some_fun):
def wrapper(arg1, arg2):
return some_fun(arg1, arg2).upper()
return wrapper
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
"""Decorator make that demonstrates decorators with arguments"""
print "I am a decorator maker and you passed \"{}:{}\" while calling me...".format(decorator_arg1, decorator_arg2)
def my_decorator(fn):
def wrapper(fn_arg1, fn_arg2):
print "I am the wrapper and I can access the method args \"{}:{}\"".format(fn_arg1, fn_arg2)
return fn(fn_arg1, fn_arg2)
return wrapper
return my_decorator
#decorator_maker_with_arguments("swadhikar", "c")
#makeupper
def hello(ar1, ar2):
return "Hello User!"
print hello('arg1', 'arg2')
Output:
I am a decorator maker and you passed "swadhikar:c" while calling me...
I am the wrapper and I can access the method args "arg1:arg2"
HELLO USER!

How to use decorators (bottle.py)

I am trying to use bottle.py to build some webpages. It seems like a major part of using bottle is learning to use decorators but I have read the python docs explanation of what decorators are but I am still not sure I understand them.
The docs say:
"A Python decorator is a specific change to the Python syntax that allows us to more conveniently alter functions and methods (and possibly classes in a future version)."
It sounds like you are calling a function with some changes made but I am not sure why you would do it this way or how to read the decorator.
Looking at some bottle code:
if __name__ == '__main__':
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\\', '/')
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
#bottle.route('/static/<filepath:path>')
def server_static(filepath):
"""Handler for static files, used with the development server.
When running under a production server such as IIS or Apache,
the server should be configured to serve the static files."""
return bottle.static_file(filepath, root=STATIC_ROOT)
# Starts a local test server.
bottle.run(server='wsgiref', host=HOST, port=PORT)
What does this line do #bottle.route('/static/<filepath:path>')?
If its a fancy function call then why do it this way rather than just calling the function?
Thanks for your help! :D
Check out this code:
def my_decorator(func):
return lambda: print("goodbye")
def greet():
print('hello')
result = my_decorator(greet)
result()
--output:--
goodbye
The following is a shortcut to accomplish the same thing:
def my_decorator(func):
return lambda: print("goodbye")
#my_decorator
def greet():
print('hello')
greet()
--output:--
goodbye
The #my_decorator syntax takes the function below it, greet, and makes this call:
greet = my_decorator(greet)
The my_decorator() function has to be defined so that:
It takes a function as an argument.
Returns a function.
A Python decorator is a specific change to the Python syntax that
allows us to more conveniently alter functions and methods (and
possibly classes in a future version).
Okay, so let's say that you want to add to whatever the greet() function does:
def my_decorator(func): # func = greet
def add_to_greet():
func() #<*********This is greet()
print('world') #<***This is additional stuff.
return add_to_greet
#my_decorator
def greet():
print('hello')
greet()
--output:--
hello
world
What does this line do #bottle.route('/static/<filepath:path>')
Okay, are you ready? If the #some_name syntax specifies an argument, for instance:
#wrapper('world')
def do_stuff():
First python will execute the following call:
#wrapper('world')
def do_stuff():
...
#****HERE:
decorator = wrapper('world') #decorator is a newly created variable
The wrapper() function must be defined to:
Take any old argument, e.g. 'world'
Return a function that:
Takes a function as an argument.
Returns a function.
Secondly, python will execute the call:
#wrapper('world')
def do_stuff():
...
decorator = wrapper('world')
#*****HERE:
do_stuff = decorator(do_stuff)
Whew! Here is an example:
def wrapper(extra_greeting):
def my_decorator(func):
def add_to_greet():
func()
print(extra_greeting)
return add_to_greet
return my_decorator
#wrapper('world')
def greet():
print('hello')
greet()
--output:--
hello
world
Now, let's analyze this decorator:
#bottle.route('/static/<filepath:path>')
def server_static(filepath):
bottle -- a module
route -- a function(or other callable) defined in the bottle module
'/static/<filepath:path>' -- a route
So the bottle module might look like this:
#bottle.py
def route(your_route): #your_route <= '/static/<filepath:path>'
def my_decorator(func): #The decorator syntax will cause python to call this function with server_static as the argument
def do_stuff(filepath):
func(filepath) #Call the server_static() function with the part of the url that matched filepath
return do_stuff #This function will be called when your code calls server_static(...)
return my_decorator
If its a fancy function call then why do it this way rather than just
calling the function?
Advanced stuff.
Comment: Perhaps you forgot to explain what specifically that route decorator does?
#route('/hello')
def hello():
return "Hello World!"
The route() decorator binds a piece of code to an URL path. In this
case, we link the /hello path to the hello() function. This is called
a route (hence the decorator name) and is the most important concept
of this framework. You can define as many routes as you want. Whenever
a browser requests a URL, the associated function is called and the
return value is sent back to the browser. It’s as simple as that.
http://bottlepy.org/docs/dev/tutorial.html
A path can include wild cards:
The simplest form of a wildcard consists of a name enclosed in angle
brackets (e.g. <name>)....Each wildcard matches one or more
characters, but stops at the first slash (/).
The rule /<action>/<item> matches as follows:
Path Result
/save/123 {'action': 'save', 'item': '123'}
/save/123/ No Match
/save/ No Match
//123 No Match
Filters are used to define more specific wildcards, and/or transform
the matched part of the URL before it is passed to the callback. A
filtered wildcard is declared as <name:filter>
The following standard filters are implemented:
:path matches all characters including the slash character in a non-greedy way and may be used to match more than one path
segment.
http://bottlepy.org/docs/dev/routing.html
A decorator is just a function wrapper, it takes some computable and surround it with more computables, technically a decorators is a function that returns a function(or an object, in fact there are decorator classes).
Lets say for example you want to make a logger decorator, this logger decorator will execute something and log who is executing it:
def loggger(name):
def wrapper(f):
def retF(*args, **kwargs):
print name, "is executing"
f(*args, **kwargs)
return retF
return wrapper
So, we have our decorator that will print "Daniel is executing" before call our desired function, for example
#logger("Daniel")
def add2Nums(a,b):
return a+b
>>> add2Nums(1,2)
>>> Daniel is executing
>>> 3
Bottle just works the same way, in the
#bottle.route('/static/<filepath:path>')
it just wrapps your server_static call so whenever some acces that route your function is called.

Accessing function arguments from decorator

I have a Request handler and a decorator, I would like to work with the self object inside the decorator
class MyHandler(webapp.RequestHandler):
#myDecorator
def get(self):
#code
Update: Please notice the difference between the first and second self
class myDecorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
#work with self
MyHandler > get ( function ) > self ( argument )
myDecorator > __call__ ( function ) > self ( argument )
the self arguments mentioned above are different. My intention is to access the first self from inside __call__ function, or find a way to do something similar.
Hi can I access MyHandlers self argument from get function inside the decorator?
Update2: I want to implement a decorator to work with a custom login in google app engine:
I have a class ( requestHandler ):
class SomeHandler(webapp.RequestHandler):
#only_registered_users
def get(self):
#do stuff here
And I want to decorate the get function in order to check out if the user is logged in or not:
from util.sessions import Session
import logging
class only_registered_users(object):
def __init__(self, f):
self.f = f
def __call__(self):
def decorated_get(self):
logging.debug("request object:", self.request)
session = Session()
if hasattr(session, 'user_key'):
return self.f(self)
else:
self.request.redirect("/login")
return decorated_get
I know if a user is logged in if has the property 'user_key' in a session Object.
That's the main goal I'm interested in on this specific case
Let me know your suggestions / opinions if I'm doing something wrong!
Thanks!
I'm not entirely clear what it is you want, but if you just want to use the decorated function's arguments, then that is exactly what a basic decorator does. So to access say, self.request from a decorator you could do:
def log_request(fn):
def decorated_get(self):
logging.debug("request object:", self.request)
return fn(self)
return decorated_get
class MyHandler(webapp. RequestHandler):
#log_request
def get(self):
self.response.out.write('hello world')
If you are trying to access the class the decorated function is attached to, then it's a bit tricker and you'll have to cheat a bit using the inspect module.
import inspect
def class_printer(fn):
cls = inspect.getouterframes(inspect.currentframe())[1][3]
def decorated_fn(self, msg):
fn(self,cls+" says: "+msg)
return decorated_fn
class MyClass():
#class_printer
def say(self, msg):
print msg
In the example above we fetch the name of the class from the currentframe (during the execution of the decorator) and then store that in the decorated function. Here we are just prepending the class-name to whatever the msg variable is before passing it on to the original say function, but you can use your imagination to do what ever you like once you have the class name.
>>> MyClass().say('hello')
MyClass says: hello
source
def p_decorate(func):
def func_wrapper(name):
return "<p>{0}</p>".format(func(name))
return func_wrapper
#p_decorate
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
print get_text("John")
# Outputs <p>lorem ipsum, John dolor sit amet</p>
Try this approach: Can a Python decorator of an instance method access the class?
Not the exact same question but you should be able to use the same approach to create a reference to self or a reference to a dictionary with objects of a certain class in it that you can get out in your decorator.
import random
#decorator to the get function in order to check out if the user is logged in or not
def only_registered_users(func):
def wrapper(handler):
print 'Checking if user is logged in'
if random.randint(0, 1):
print 'User is logged in. Calling the original function.'
func(handler)
else:
print 'User is NOT logged in. Redirecting...'
# redirect code here
return wrapper
class MyHandler(object):
#only_registered_users
def get(self):
print 'Get function called'
m = MyHandler()
m.get()
The self argument to __call__ will be populated with the instance the decorated method is being called on. There's no way to access the decorator object from here - __call__ is a bound method, and what you're asking for would require it to be, in effect, 'doubly bound'. Python doesn't support this, so the decorator instance gets replaced with the decorated function's first argument.
The easiest way to work around this is to use nested functions, as #Chris recommends.

Categories