How to use decorators (bottle.py) - python

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.

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.

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

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

How do decorators mark a function?

I was going throught the basic Flask tutorial which has the following code:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
Also I went through the basics of Python decorators from many websites including Stackoverflow Decorators
I was of the assumption that in the previous code, the function hello will be changed and decorated, and for running the application I need to call the function hello() somewhere. How does Flask determine the name of the function it has to call.
Does just wrapping the function definition with a decorator somehow marks that function? If so, how?
For example in the below code, somewhere down the line I'm calling the function I've decorated:
def decorate(foo):
print("I'm doing a lot of important stuff right now")
def inner():
print("Some stuff 1")
foo()
print("Some stuff 2")
return inner
#decorate
def hello():
print("Hello")
hello()
In decorate, foo is the function you are decorating (in this case, hello). You can store the function in a list or dictionary somewhere, since it's a normal object.
For example:
decorated_functions = []
def decorate(foo):
def inner():
print("Some stuff 1")
foo()
print("Some stuff 2")
decorated_functions.append(inner)
return inner
#decorate
def hello():
print("Hello")
## The above is the same as:
# def hello():
# print("Hello")
# hello = decorate(hello)
print(decorated_functions[0] == hello) # prints True
decorated_functions[0]() # prints "Some stuff 1", "Hello", and "Some stuff 2"
hello() # same as above
Decorators are actually a very simple construct in Python. The following two examples are equivalent:
#foo
def bar():
pass
def bar():
pass
bar = foo(bar)
So your definition of hello in your first example is the equivalent to this:
def hello():
return "Hello World!"
hello = app.route("/")(hello)
The double function calls might be a bit confusing so lets rewrite it like this:
_tempfn = app.route("/")
hello = _tempfn(hello)
So it should be clear now that app.route isn't actually a decorator, it's a function that creates decorators. Now what isn't obvious is what the newly decorator does. Without looking at the source for Flash, it's likely that it adds the function hello to a dictionary member of a app. So app.route is implemented something like this:
class app(object):
def route(self, path):
def decorator(fn):
self.pathmap[path] = fn
return fn
return decorator
Note that this is pretty much a condensed version of the explanation given in the link that Jon Piparsky provided.
The decorator is simply registering the function in a lookup table. Decorators don't need to modify a function in any way, there are so many other useful things, decorators can do.
In fact, decorators in python
#some_decorator
def foo():
pass
are only a short form of
def foo():
pass
foo = some_decorator(foo)
and the function some_decorator can do anything with its arguments and can return any return value, but usually returns a function.

I have a Python code that is given below, when I run this global name PDBAttributes is not defined

#!/usr/bin/env python2.7
##-*- mode:python;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t;python-indent:2 -*-'
import noesy
import argparse
import library
parser =argparse.ArgumentParser(description="read pdb file",
add_help=True)
parser.add_argument("file",help="protein pdb file")
library.add_standard_args( parser )
args = parser.parse_args()
def read_structure(pdbfile):
struct=[]
for line in pdbfile:
if len(line):
struct.append(PDBAttributes.read_from_line(line))
return struct
pdb=read_structure(open(args.file,'r'))
class PDBAttributes:
def __init__(self, atomindex=1, atom=noesy.Atom(), atomx=1, atomy=1, atomz=1):
self._atomindex=atomindex
self._atom=atom
self._atomx=atomx
self._atomy=atomy
self._atomz=atomz
def __str__(self):
s='ATOM %(_atomindex)d %(_atom)s at %(_atomx)8.3f %(_atomy)8.3f %(_atomz)8.3f'%self.__dict__
return s
def atom(self):
return self._atom
def atomindex(self):
return self._atomindex
def atomx(self):
return self._atomx
def atomy(self):
return self._atomy
def atomz(self):
return self._atomz
#classmethod
def read_from_line(obj,line):
tags=line.split()
atomindex=int(tags[1])
atom=noesy.Atom(tags[2],int(tags[5]))
atomx=float(tags[6])
atomy=float(tags[7])
atomz=float(tags[8])
obj=PDBAttributes(atomindex, atom, atomx, atomy, atomz)
print obj
class AtomDistance(PDBAttributes):
def distance(self, atom1,atom2):
pass
The NameError you are getting is due to the order you have placed the code in your file.
When you call read_structure to create a value for the pdb variable, it tries to look for PDBAttributes, but it has not been defined yet. If you move that line lower down in the file (below the class definition) you'll avoid that error. Note that it is OK to have the declaration of read_structure above the PDBAttributes class definition, though you might want to move it lower too to make the code easier to understand.
Here's a very simple bit of code that demonstrates the same error:
def foo():
print(foo_text)
foo() # raises a NameError
foo_text = "foo"
Here's a fixed version:
def foo():
print(foo_text)
foo_text = "foo"
foo() # no error, prints "foo"
Move your call of read_structure to follow the definition of the PDBAttributes class.
Also, in the process of reformatting your post, I see that you have mixed tabs and spaces for your indentation. Try reformatting your code to use all spaces for indentation, the recommended form is 4-space indents.
Your definition of all those getter functions looks like Java written in Python - this is a lot of extra code that is often unnecessary in Python. The recommended approach is to omit these all-they-do-is-assign-a-value-to-an-attribute-with-the-same-name-but-with-a-leading-underscore methods and just use attributes with the public names. See Python is Not Java.

Categories