Created
September 14, 2011 13:06
-
-
Save defnull/1216497 to your computer and use it in GitHub Desktop.
Subclassable ViewPlugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ViewPlugin(object): | |
''' Automatically renders a template for callbacks that return a dictionary. | |
Subclasses may overrule some methods to implement engine specific | |
features. They must implement :meth:`prepare_file` and | |
:meth:`prepare_source`, should implement :meth:`prepare_factory` and may | |
implement :meth:`assemble_config`, :meth:`is_source`, :meth:`locate` and | |
additional methods. | |
''' | |
name = 'view' | |
api = 2 | |
def __init__(self, view=None, **conf): | |
self.view = view | |
self.conf = conf | |
def apply(self, callback, route): | |
view = route.config.get('view', self.view) | |
if not view: return callback | |
config = self.assemble_config(route) | |
app = route.app | |
render = self.prepare(view, **config) | |
def wrapper(*a, **ka): | |
rv = callback(*a, **ka) | |
if isinstance(rv, (dict, UserDict)): | |
rv.update(_view=self, _tpl=tpl, _app=app) | |
return render(rv) | |
return rv | |
return wrapper | |
def is_source(self, view): | |
''' Return True if the supplied string looks like template source code, | |
False otherwise. ''' | |
return "\n" in view or "{" in view or "%" in view or '$' in view | |
def locate(self, name, config): | |
''' Given a template or file name and the assembled config dictionary, | |
return the path to the template file, or None. The default | |
implementation tries every search path in config['lookup'] to find | |
a matching file. If the path contains `%s` (e.g. `./views/%s.tpl`), | |
it is used as a format string to get the full path. ''' | |
for path in ['%s'] + (config.get('lookup') or []): | |
if '%s' in path: path %= name | |
else: path = os.path.join(path, name) | |
if os.path.isfile(path): return fname | |
def assemble_config(self, route): | |
''' Merge config settings from four sources: Application, plugin class, | |
plugin instance and route config. The default implementation merges | |
all four configurations and overwrites existing keys. Subclasses | |
may decide to merge or check certain values. ''' | |
config = (route.app.config.get('view') or {}).copy() | |
config.update(self.conf) | |
config.update(route.config.get('view_conf') or {}) | |
return config | |
def prepare(self, view, **config): | |
''' Given a view identifier (which might be a factory callable, a source | |
string or a template name) and optional configuration as | |
additional keyword arguments, this method returns a callable | |
or raises an exception. The returned callable accepts a dictionary | |
with template vars and returns the rendered template as a string or | |
string iterator. ''' | |
if callable(view): | |
return self.prepare_factory(view, **config) | |
elif self.is_source(view): | |
return self.prepare_source(view, **config) | |
else: | |
filepath = self.locate(view, config) | |
if not filepath: raise TemplateError('Template %r not found.'%view) | |
return self.prepare_file(filepath, **config) | |
def prepare_file(self, filepath, **config): | |
''' :meth:`prepare` implementation that excepts a file path. ''' | |
raise NotImplementedError('View plugin does not support named views.') | |
def prepare_source(self, source, **config): | |
''' :meth:`prepare` implementation that excepts a source string. ''' | |
raise NotImplementedError('View plugin does not support source views.') | |
def prepare_factory(self, factory, **config): | |
''' :meth:`prepare` implementation that excepts a factory callable | |
(usually a pre-configured template instance). ''' | |
raise NotImplementedError('View plugin does not support factory views.') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment