| | 1 | {{{ |
| | 2 | # Programmer: limodou |
| | 3 | # E-mail: limodou@gmail.com |
| | 4 | # |
| | 5 | # Copyleft 2006 limodou |
| | 6 | # |
| | 7 | # Distributed under the terms of the GPL (GNU Public License) |
| | 8 | # |
| | 9 | # NewEdit is free software; you can redistribute it and/or modify |
| | 10 | # it under the terms of the GNU General Public License as published by |
| | 11 | # the Free Software Foundation; either version 2 of the License, or |
| | 12 | # (at your option) any later version. |
| | 13 | # |
| | 14 | # This program is distributed in the hope that it will be useful, |
| | 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| | 17 | # GNU General Public License for more details. |
| | 18 | # |
| | 19 | # You should have received a copy of the GNU General Public License |
| | 20 | # along with this program; if not, write to the Free Software |
| | 21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | 22 | # |
| | 23 | # Version 0.1 |
| | 24 | # This program is used to parse django's urlconf file. It can deal with standard |
| | 25 | # urls.py , e.g., it can parse prefix, pattern, method, and extra dictionary. |
| | 26 | # How to use it: |
| | 27 | # |
| | 28 | # from DjangoUrlConf import URLConf |
| | 29 | # #URLConf can receive a usrconf filename, or leave it empty |
| | 30 | # u = URLConf([urlsfile]) |
| | 31 | # #add common pattern |
| | 32 | # u.add(r'^test/$', 'newtest.test.main') |
| | 33 | # #add include pattern |
| | 34 | # u.add(r'^ajax/input/$', "include('newtest.test.ajax')") |
| | 35 | # #easyadd, it can automaticaly add '^' at the begin and '$' at the end |
| | 36 | # u.easyadd('tttt/input/', 'newtest.test.main') |
| | 37 | # #you can also pass it a dict variable |
| | 38 | # u.easyadd('tttt/input/', 'newtest.test.main', {'template': 'my_calendar/calendar'}) |
| | 39 | # #you can find a pattern |
| | 40 | # u.find(r'^ajax/input/$') |
| | 41 | # #or easyfind a pattern |
| | 42 | # u.easyfind('ajax/input/') |
| | 43 | # #find mapping method |
| | 44 | # u.has_method('newtest.test.ajax') |
| | 45 | # #save to a file, if the filename is omit, then use the filename which passwd to URLConf class |
| | 46 | # u.save([filename]) |
| | 47 | |
| | 48 | import sys |
| | 49 | |
| | 50 | class URLPatterns: |
| | 51 | def __init__(self): |
| | 52 | self.orders = [] |
| | 53 | self.prefix = '' |
| | 54 | self.nodes = {} |
| | 55 | |
| | 56 | def render(self): |
| | 57 | s = ['urlpatterns = patterns(%s\n' % self.prefix] |
| | 58 | for key in self.orders: |
| | 59 | if not self.nodes.has_key(key) : |
| | 60 | s.append(key) |
| | 61 | else: |
| | 62 | s.append(self.render_item(key)) |
| | 63 | s.append(")\n") |
| | 64 | return ''.join(s) |
| | 65 | |
| | 66 | def render_item(self, key): |
| | 67 | s = [] |
| | 68 | p, d = self.nodes[key] |
| | 69 | if not p.startswith('include('): |
| | 70 | p = repr(p) |
| | 71 | s.append(" (r%r, %s" % (key, p)) |
| | 72 | if d: |
| | 73 | if isinstance(d, dict): |
| | 74 | d = repr(d) |
| | 75 | s.append(", %s),\n" % d) |
| | 76 | else: |
| | 77 | s.append("),\n") |
| | 78 | return ''.join(s) |
| | 79 | |
| | 80 | def parse(self, text): |
| | 81 | text = text.replace('\r\n', '\n') |
| | 82 | text = text.replace('\r', '\n') |
| | 83 | |
| | 84 | i = 0 |
| | 85 | last = 0 |
| | 86 | flag = 0 #0 begin 1 comment 2 pattern |
| | 87 | while i<len(text): |
| | 88 | #skip blank |
| | 89 | while text[i] in (' ', '\t'): |
| | 90 | i += 1 |
| | 91 | if text[i] == '#': #if comment: |
| | 92 | while text[i] != '\n': |
| | 93 | i += 1 |
| | 94 | i += 1 |
| | 95 | self.orders.append(text[last:i]) |
| | 96 | last = i |
| | 97 | elif text[i] == '(': |
| | 98 | i += 1 |
| | 99 | last = i |
| | 100 | level = 1 |
| | 101 | while level != 0: |
| | 102 | if text[i] == '(': |
| | 103 | level += 1 |
| | 104 | elif text[i] == ')': |
| | 105 | level -= 1 |
| | 106 | i += 1 |
| | 107 | t = text[last:i-1] |
| | 108 | pos = t.find(',') |
| | 109 | if pos > -1: |
| | 110 | key = eval(t[:pos]) |
| | 111 | pos += 1 |
| | 112 | begin = pos |
| | 113 | pos = t.find(',', pos) |
| | 114 | if pos > -1: |
| | 115 | pattern = t[begin:pos].lstrip() |
| | 116 | dict = t[pos+1:].rstrip() |
| | 117 | else: |
| | 118 | pattern = t[begin:].strip() |
| | 119 | dict = None |
| | 120 | if key not in self.orders: |
| | 121 | self.orders.append(key) |
| | 122 | self.nodes[key] = (pattern, dict) |
| | 123 | while text[i] != '\n': |
| | 124 | i += 1 |
| | 125 | i += 1 |
| | 126 | last = i |
| | 127 | else: |
| | 128 | while i < len(text) and text[i] != '\n': |
| | 129 | i += 1 |
| | 130 | i += 1 |
| | 131 | self.orders.append(text[last:i]) |
| | 132 | last = i |
| | 133 | |
| | 134 | self.orders.pop(-1) |
| | 135 | |
| | 136 | |
| | 137 | def remove(self, key): |
| | 138 | if self.nodes.has_key(key): |
| | 139 | s = self.render_item(key) |
| | 140 | del self.nodes[key] |
| | 141 | pos = self.orders.index(key) |
| | 142 | self.orders[pos] = '#' + s |
| | 143 | |
| | 144 | def find(self, pattern): |
| | 145 | return self.nodes.get(pattern, None) |
| | 146 | |
| | 147 | def add(self, pattern, method, dict=None): |
| | 148 | if pattern not in self.orders: |
| | 149 | self.orders.append(pattern) |
| | 150 | self.nodes[pattern] = (method, dict) |
| | 151 | |
| | 152 | def has_method(self, method): |
| | 153 | for key, v in self.nodes(): |
| | 154 | p, d = v |
| | 155 | if p == method: |
| | 156 | return key |
| | 157 | return None |
| | 158 | |
| | 159 | |
| | 160 | class URLConf: |
| | 161 | def __init__(self, urlconf_filename=''): |
| | 162 | self.nodes = [] |
| | 163 | self.urlconf = URLPatterns() |
| | 164 | self.filename = urlconf_filename |
| | 165 | self.read(self.filename) |
| | 166 | |
| | 167 | def out(self): |
| | 168 | self.save(sys.stdout) |
| | 169 | |
| | 170 | def save(self, filename=None): |
| | 171 | if not filename: |
| | 172 | filename = self.filename |
| | 173 | if isinstance(filename, (str, unicode)): |
| | 174 | f = file(filename, 'w') |
| | 175 | else: |
| | 176 | f = filename |
| | 177 | text = [] |
| | 178 | for node in self.nodes: |
| | 179 | if isinstance(node, URLPatterns): |
| | 180 | text.append(node.render()) |
| | 181 | else: |
| | 182 | if isinstance(node, (list, tuple)): |
| | 183 | text.append(''.join(node)) |
| | 184 | else: |
| | 185 | text.append(node) |
| | 186 | s = ''.join(text) |
| | 187 | if s.find('from django.conf.urls.defaults import *') == -1: |
| | 188 | s = 'from django.conf.urls.defaults import *\n\n' + s |
| | 189 | |
| | 190 | f.write(s) |
| | 191 | |
| | 192 | |
| | 193 | def find(self, pattern): |
| | 194 | return self.urlconf.find(pattern, None) |
| | 195 | |
| | 196 | def easyfind(self, pattern): |
| | 197 | pattern = '^%s$' % pattern |
| | 198 | return self.find(pattern, None) |
| | 199 | |
| | 200 | def add(self, pattern, method, dict=None): |
| | 201 | self.urlconf.add(pattern, method, dict) |
| | 202 | |
| | 203 | def easyadd(self, pattern, method, dict=None): |
| | 204 | pattern = '^%s$' % pattern |
| | 205 | self.add(pattern, method, dict) |
| | 206 | |
| | 207 | def has_method(self, method): |
| | 208 | return self.urlconf.has_method(method) |
| | 209 | |
| | 210 | def read(self, filename): |
| | 211 | if not filename: |
| | 212 | self.nodes.append(self.urlconf) |
| | 213 | return |
| | 214 | |
| | 215 | f = file(filename) |
| | 216 | for line in f: |
| | 217 | if not line.startswith('urlpatterns'): |
| | 218 | self.nodes.append(line) |
| | 219 | else: |
| | 220 | begin = line.rfind('(') |
| | 221 | end = line.rfind(',') |
| | 222 | self.urlconf.prefix = line[begin+1:end] |
| | 223 | t = f.next() |
| | 224 | s = [] |
| | 225 | while t.strip() != ')': |
| | 226 | s.append(t) |
| | 227 | t = f.next() |
| | 228 | self.urlconf.parse(''.join(s+[')'])) |
| | 229 | self.nodes.append(self.urlconf) |
| | 230 | |
| | 231 | if __name__ == '__main__': |
| | 232 | # u = URLConf('urls.py') |
| | 233 | u = URLConf() |
| | 234 | # print u.find('^ajax/input/$') |
| | 235 | u.add('^test/$', 'newtest.test.main') |
| | 236 | u.add('^ajax/input/$', "include('newtest.test.ajax')") |
| | 237 | u.easyadd('tttt/input/', 'newtest.test.main') |
| | 238 | u.easyadd('tttt/input/', 'newtest.test.main', {'template': 'my_calendar/calendar'}) |
| | 239 | u.out() |
| | 240 | }}} |