Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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.