Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 84 lines (58 sloc) 2.83 kB
6218709 edit
anonymous authored
1 ---
2 layout: default
3 title: MetaClassAutoURLS
4 ---
5
6 # MetaClassAutoURLS
7
abcf273 edit
anonymous authored
8 web.py maps URLs regexes to classes via a list like so:
9
10 class Default(object):
11 ''' Action for / ''' def GET(self):
12 pass
13
14 class Login(object):
15 ''' Action for /login ''' def GET(self):
16 pass
17
18 def POST(self):
19 pass
20
21 urls = ["/", "Default", "/login", "Login"]
22
23 One of the disadvantages of this approach is that for large applications, the urls list can get very long and tedious to maintain. Things get worse during long refactorings/reorgnanizations because it's easy to typo a class or module name or just forget to update the urls list. After spending a couple hours debugging just this problem and then smacking myself on the forehead for missing such a simple mistake, I thought to myself, _There's got to be a way to automate this!_ After some research, I found that metaclasses can do exactly what I want:
24
25 urls = [ ]
26
27 class ActionMetaClass(type):
28 def __init__(klass, name, bases, attrs):
29 urls.append(attrs["url"])
30 urls.append("%s.%s" % (klass.__module__, name))
31
32 class Default(object):
33 __metaclass__ = ActionMetaClass
34 url = "/"
35 def GET(self):
36 pass
37
38 class Login(object):
39 __metaclass__ = ActionMetaClass
40 url = "/login"
41 def GET(self):
42 pass
43
44 def POST(self):
45 pass
46
53f57e5 AaronSw
anonymous authored
47 Of course, this is a simple example that leaves a lot to be desired (handling attrs lacking a url key, for instance), but it should get you on your way.
48
49 * * *
50
50ae59b edit
anonymous authored
51 **AaronSw writes:** That's a clever idea. One improvement might be to have the classes inherit from a class with the metaclass set, so you don't have that unsightly `__metaclass__` every time.
52
53 * * *
54
0a896bc edit
anonymous authored
55 May be it's better to do it with decorators?
56
57 * * *
58
98f43ee edit
anonymous authored
59 I couldn't figure out how to get this to work with URL classes in separate files, so I did something a little different, based on [this Python Cookbook recipe](http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/436873):
0a896bc edit
anonymous authored
60
61 import os, web
62
63 urls = [ ]
64
65 for aaa in os.listdir(os.getcwd()):
66 module_name, ext = os.path.splitext(aaa)
67 if module_name.startswith('cgi_') and ext == '.py':
68 module = __import__(module_name)
69 urls.append(module.url[0])
70 urls.append(module_name + "." + module.url[1])
71
72 if __name__ == "__main__":
73 web.run(urls)
74
75 And then e.g. cgi_hello.py (in the same directory) would be:
76
77 import web
78 url = ('/(.*)', 'hello')
79
80 class hello:
81 def GET(self, name):
82 i = web.input(times=1)
83 if not name: name = 'world' for c in xrange(int(i.times)): print 'Hello,', name+'!'
84 Is this a terrible way to do it?
Something went wrong with that request. Please try again.