Nevowにurlresolverを装備させる
Nevowはそのままだと非常に使いにくい。
というかそのぶん自由なんだけど。
個人的にはdjangoのurlresolverはなんだかんだいって
使いやすいのでこいつを組み込むといいなあと思ったのでやってみる。
パクリ
reolver.py
import re class Resolver404(Exception): pass class NoReverseMatch(Exception): silent_variable_failure = True def get_mod_func(callback): try: dot = callback.rindex('.') except ValueError: return callback, '' return callback[:dot], callback[dot+1:] class RegexURLPattern(object): def __init__(self, regex, callback, default_args=None): self.regex = re.compile(regex) if callable(callback): self._callback = callback else: self._callback = None self._callback_str = callback self.default_args = default_args or {} def resolve(self, path): match = self.regex.search(path) print "path ", path, match if match: kwargs = match.groupdict() if kwargs: args = () else: args = match.groups() kwargs.update(self.default_args) return self.callback, args, kwargs def _get_callback(self): if self._callback is not None: return self._callback mod_name, func_name = get_mod_func(self._callback_str) try: mod = __import__(mod_name, {}, {}, ['']) self._callback = getattr(__import__(mod_name, {}, {}, ['']), func_name) except ImportError, e: raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e)) except AttributeError, e: raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) return self._callback callback = property(_get_callback) class RegexURLResolver(object): def __init__(self, regex, urlconf_name, default_kwargs=None): self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None self.default_kwargs = default_kwargs or {} def resolve(self, path): tried = [] match = self.regex.search(path) if match: new_path = path[match.end():] for pattern in self.urlconf_module.urlpatterns: try: sub_match = pattern.resolve(new_path) except Resolver404, e: tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: if sub_match: sub_match_dict = dict(self.default_kwargs, **sub_match[2]) return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict) tried.append(pattern.regex.pattern) raise Resolver404, {'tried': tried, 'path': new_path} def _get_urlconf_module(self): try: return self._urlconf_module except AttributeError: try: self._urlconf_module = __import__(self.urlconf_name, {}, {}, ['']) except ValueError, e: # Invalid urlconf_name, such as "foo.bar." (note trailing period) raise ImproperlyConfigured, "Error while importing URLconf %r: %s" % (self.urlconf_name, e) return self._urlconf_module urlconf_module = property(_get_urlconf_module) def _get_url_patterns(self): return self.urlconf_module.urlpatterns url_patterns = property(_get_url_patterns) def _resolve_special(self, view_type): callback = getattr(self.urlconf_module, 'handler%s' % view_type) mod_name, func_name = get_mod_func(callback) try: return getattr(__import__(mod_name, {}, {}, ['']), func_name), {} except (ImportError, AttributeError), e: raise Exception, "Tried %s. Error was: %s" % (callback, str(e)) def resolve404(self): return self._resolve_special('404') def resolve500(self): return self._resolve_special('500') def resolve(path, urlconf=None): resolver = RegexURLResolver(r'^/', urlconf) return resolver.resolve(path) include = lambda urlconf_module: [urlconf_module] def patterns(prefix, *tuples): pattern_list = [] for t in tuples: regex, view_or_include = t[:2] default_kwargs = t[2:] if type(view_or_include) == list: pattern_list.append(RegexURLResolver(regex, view_or_include[0], *default_kwargs)) else: pattern_list.append(RegexURLPattern(regex, prefix and (prefix + '.' + view_or_include) or view_or_include, *default_kwargs)) return pattern_list
まあいつもとおり。
includeも拾えるようにしておく。
でRootPage
root.py
from nevow import inevow, loaders, rend, url, tags as T from twisted.web import static import resolver class RootPage(rend.Page): addSlash = True def locateChild(self, ctx, segments): request = inevow.IRequest(ctx) method = request.method path = "/".join(segments) try: callback, args, kwargs = resolver.resolve("/"+path, "url") page = callback(*args, **kwargs) if not len(segments): return page, () else: return page, () except: return rend.Page.locateChild(self, ctx, segments) class BasePage(RootPage): docFactory = loaders.htmlfile(templateDir='templates', template='base.html') child_css = static.File('css') #child_images = static.File('static/images') def render_content(self, context, data): tag = context.tag.clear() if hasattr(self, "contentTemplateFile"): tag[loaders.htmlfile(templateDir='templates', template=self.contentTemplateFile)] return tag return loaders.stan(self.contentStan) class IndexPage(BasePage): addSlash = True contentTemplateFile = 'index.html'
URL設定はurl.pyに記述している。
中身はdjangoと同じ。詳しく書かない。
こいつをRootとしてtwistedを起動するのでこんな感じ。
sample.tac
from twisted.application import internet from twisted.application import service from nevow import appserver from core import root application = service.Application('sample') appResource = root.BasePage() site = appserver.NevowSite(appResource) webServer = internet.TCPServer(8080, site) webServer.setServiceParent(application)
こうするとURLとPageの組み合わせが自由!
さらにURLの一部をパラメータに使える!
formlessを使うと死ぬのでformalを使う必要アリだけどね。
NevowはPage駆動なのでteedaライクなんだけどそいつについてはあとで書く。
Nevowはtwistedベースなのでテストは・・・・・。ってのもあとで書く。
うくく。