mirror of
https://github.com/kennethreitz-archive/pystache.git
synced 2026-06-05 23:40:16 +00:00
style and import changes
This commit is contained in:
+30
-14
@@ -1,47 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
pystache.loader
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This module provides Pystache's Loader class.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class Loader(object):
|
||||
|
||||
|
||||
template_extension = 'mustache'
|
||||
template_path = '.'
|
||||
template_encoding = None
|
||||
|
||||
|
||||
def load_template(self, template_name, template_dirs=None, encoding=None, extension=None):
|
||||
'''Returns the template string from a file or throws IOError if it non existent'''
|
||||
"""Returns the template string from a file, or throws IOError
|
||||
if it is non-existent.
|
||||
"""
|
||||
|
||||
if None == template_dirs:
|
||||
template_dirs = self.template_path
|
||||
|
||||
|
||||
if encoding is not None:
|
||||
self.template_encoding = encoding
|
||||
|
||||
|
||||
if extension is not None:
|
||||
self.template_extension = extension
|
||||
|
||||
|
||||
file_name = template_name + '.' + self.template_extension
|
||||
|
||||
# Given a single directory we'll load from it
|
||||
# Given a single directory, we'll load from it.
|
||||
if isinstance(template_dirs, basestring):
|
||||
file_path = os.path.join(template_dirs, file_name)
|
||||
|
||||
return self._load_template_file(file_path)
|
||||
|
||||
# Given a list of directories we'll check each for our file
|
||||
|
||||
# Given a list of directories, we'll check each for our file.
|
||||
for path in template_dirs:
|
||||
file_path = os.path.join(path, file_name)
|
||||
if os.path.exists(file_path):
|
||||
return self._load_template_file(file_path)
|
||||
|
||||
|
||||
raise IOError('"%s" not found in "%s"' % (template_name, ':'.join(template_dirs),))
|
||||
|
||||
|
||||
|
||||
def _load_template_file(self, file_path):
|
||||
'''Loads and returns the template file from disk'''
|
||||
"""Loads and returns the template file from disk."""
|
||||
|
||||
f = open(file_path, 'r')
|
||||
|
||||
|
||||
try:
|
||||
template = f.read()
|
||||
if self.template_encoding:
|
||||
template = unicode(template, self.template_encoding)
|
||||
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
|
||||
return template
|
||||
+44
-16
@@ -1,14 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import cgi
|
||||
import collections
|
||||
import os
|
||||
import copy
|
||||
|
||||
from .loader import Loader
|
||||
|
||||
try:
|
||||
import markupsafe
|
||||
escape = markupsafe.escape
|
||||
literal = markupsafe.Markup
|
||||
|
||||
except ImportError:
|
||||
escape = lambda x: cgi.escape(unicode(x))
|
||||
literal = unicode
|
||||
@@ -18,15 +19,15 @@ class Modifiers(dict):
|
||||
"""Dictionary with a decorator for assigning functions to keys."""
|
||||
|
||||
def set(self, key):
|
||||
"""
|
||||
Decorator function to set the given key to the decorated function.
|
||||
"""Decorator function to set the given key to
|
||||
the decorated function.
|
||||
|
||||
>>> modifiers = {}
|
||||
>>> @modifiers.set('P')
|
||||
... def render_tongue(self, tag_name=None, context=None):
|
||||
... return ":P %s" % tag_name
|
||||
>>> modifiers
|
||||
{'P': <function render_tongue at 0x...>}
|
||||
>>> modifiers = {}
|
||||
>>> @modifiers.set('P')
|
||||
... def render_tongue(self, tag_name=None, context=None):
|
||||
... return ":P %s" % tag_name
|
||||
>>> modifiers
|
||||
{'P': <function render_tongue at 0x...>}
|
||||
"""
|
||||
|
||||
def setter(func):
|
||||
@@ -35,18 +36,17 @@ class Modifiers(dict):
|
||||
return setter
|
||||
|
||||
|
||||
|
||||
class Template(object):
|
||||
|
||||
tag_re = None
|
||||
|
||||
otag = '{{'
|
||||
|
||||
ctag = '}}'
|
||||
|
||||
modifiers = Modifiers()
|
||||
|
||||
def __init__(self, template=None, context=None, **kwargs):
|
||||
from view import View
|
||||
from .view import View
|
||||
|
||||
self.template = template
|
||||
|
||||
@@ -56,6 +56,7 @@ class Template(object):
|
||||
self.view = context if isinstance(context, View) else View(context=context)
|
||||
self._compile_regexps()
|
||||
|
||||
|
||||
def _compile_regexps(self):
|
||||
tags = {
|
||||
'otag': re.escape(self.otag),
|
||||
@@ -68,6 +69,7 @@ class Template(object):
|
||||
tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+"
|
||||
self.tag_re = re.compile(tag % tags)
|
||||
|
||||
|
||||
def _render_sections(self, template, view):
|
||||
while True:
|
||||
match = self.section_re.search(template)
|
||||
@@ -82,18 +84,22 @@ class Template(object):
|
||||
# Callable
|
||||
if it and isinstance(it, collections.Callable):
|
||||
replacer = it(inner)
|
||||
|
||||
# Dictionary
|
||||
elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'):
|
||||
if section[2] != '^':
|
||||
replacer = self._render_dictionary(inner, it)
|
||||
|
||||
# Lists
|
||||
elif it and hasattr(it, '__iter__'):
|
||||
if section[2] != '^':
|
||||
replacer = self._render_list(inner, it)
|
||||
|
||||
# Other objects
|
||||
elif it and isinstance(it, object):
|
||||
if section[2] != '^':
|
||||
replacer = self._render_dictionary(inner, it)
|
||||
|
||||
# Falsey and Negated or Truthy and Not Negated
|
||||
elif (not it and section[2] == '^') or (it and section[2] != '^'):
|
||||
replacer = self._render_dictionary(inner, it)
|
||||
@@ -102,6 +108,7 @@ class Template(object):
|
||||
|
||||
return template
|
||||
|
||||
|
||||
def _render_tags(self, template):
|
||||
while True:
|
||||
match = self.tag_re.search(template)
|
||||
@@ -116,22 +123,32 @@ class Template(object):
|
||||
|
||||
return template
|
||||
|
||||
|
||||
def _render_dictionary(self, template, context):
|
||||
|
||||
self.view.context_list.insert(0, context)
|
||||
|
||||
template = Template(template, self.view)
|
||||
out = template.render()
|
||||
|
||||
self.view.context_list.pop(0)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def _render_list(self, template, listing):
|
||||
|
||||
insides = []
|
||||
|
||||
for item in listing:
|
||||
insides.append(self._render_dictionary(template, item))
|
||||
|
||||
return ''.join(insides)
|
||||
|
||||
|
||||
@modifiers.set(None)
|
||||
def _render_tag(self, tag_name):
|
||||
|
||||
raw = self.view.get(tag_name, '')
|
||||
|
||||
# For methods with no return value
|
||||
@@ -143,30 +160,41 @@ class Template(object):
|
||||
|
||||
return escape(raw)
|
||||
|
||||
|
||||
@modifiers.set('!')
|
||||
def _render_comment(self, tag_name):
|
||||
return ''
|
||||
|
||||
|
||||
@modifiers.set('>')
|
||||
def _render_partial(self, template_name):
|
||||
from pystache import Loader
|
||||
markup = Loader().load_template(template_name, self.view.template_path, encoding=self.view.template_encoding)
|
||||
|
||||
markup = Loader().load_template(
|
||||
template_name,
|
||||
self.view.template_path,
|
||||
encoding=self.view.template_encoding)
|
||||
template = Template(markup, self.view)
|
||||
return template.render()
|
||||
|
||||
|
||||
@modifiers.set('=')
|
||||
def _change_delimiter(self, tag_name):
|
||||
"""Changes the Mustache delimiter."""
|
||||
|
||||
self.otag, self.ctag = tag_name.split(' ')
|
||||
self._compile_regexps()
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
@modifiers.set('{')
|
||||
@modifiers.set('&')
|
||||
def render_unescaped(self, tag_name):
|
||||
"""Render a tag without escaping it."""
|
||||
|
||||
return literal(self.view.get(tag_name, ''))
|
||||
|
||||
|
||||
def render(self, encoding=None):
|
||||
template = self._render_sections(self.template, self.view)
|
||||
result = self._render_tags(template)
|
||||
|
||||
+116
-75
@@ -1,9 +1,121 @@
|
||||
from pystache import Template
|
||||
import os.path
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
pystache.loader
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This module provides Pystache's views.
|
||||
"""
|
||||
|
||||
import re
|
||||
from types import *
|
||||
from types import UnboundMethodType
|
||||
|
||||
from .loader import Loader
|
||||
from .template import Template
|
||||
|
||||
|
||||
|
||||
class View(object):
|
||||
"""A Pystache view."""
|
||||
|
||||
template_name = None
|
||||
template_path = None
|
||||
template = None
|
||||
template_encoding = None
|
||||
template_extension = 'mustache'
|
||||
|
||||
def __init__(self, template=None, context=None, **kwargs):
|
||||
|
||||
self.template = template
|
||||
|
||||
context = context or {}
|
||||
context.update(kwargs)
|
||||
|
||||
self.context_list = [context]
|
||||
|
||||
|
||||
def get(self, attr, default=None):
|
||||
|
||||
attr = get_or_attr(self.context_list, attr, getattr(self, attr, default))
|
||||
|
||||
if hasattr(attr, '__call__') and type(attr) is UnboundMethodType:
|
||||
return attr()
|
||||
else:
|
||||
return attr
|
||||
|
||||
|
||||
def get_template(self, template_name):
|
||||
|
||||
if not self.template:
|
||||
|
||||
template_name = self._get_template_name(template_name)
|
||||
|
||||
self.template = Loader().load_template(
|
||||
template_name,
|
||||
self.template_path,
|
||||
encoding=self.template_encoding,
|
||||
extension=self.template_extension)
|
||||
|
||||
return self.template
|
||||
|
||||
|
||||
def _get_template_name(self, template_name=None):
|
||||
"""TemplatePartial => template_partial
|
||||
Takes a string but defaults to using the current class' name or
|
||||
the `template_name` attribute.
|
||||
"""
|
||||
|
||||
if template_name:
|
||||
return template_name
|
||||
|
||||
template_name = self.__class__.__name__
|
||||
|
||||
def repl(match):
|
||||
return '_' + match.group(0).lower()
|
||||
|
||||
return re.sub('[A-Z]', repl, template_name)[1:]
|
||||
|
||||
|
||||
def _get_context(self):
|
||||
context = {}
|
||||
for item in self.context_list:
|
||||
if hasattr(item, 'keys') and hasattr(item, '__getitem__'):
|
||||
context.update(item)
|
||||
return context
|
||||
|
||||
|
||||
def render(self, encoding=None):
|
||||
template = Template(self.get_template(self.template_name), self)
|
||||
return template.render(encoding=encoding)
|
||||
|
||||
|
||||
def __contains__(self, needle):
|
||||
return needle in self.context or hasattr(self, needle)
|
||||
|
||||
|
||||
def __getitem__(self, attr):
|
||||
val = self.get(attr, None)
|
||||
|
||||
if not val and val is not 0:
|
||||
raise KeyError("Key '%s' does not exist in View" % attr)
|
||||
return val
|
||||
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'context':
|
||||
return self._get_context()
|
||||
|
||||
raise AttributeError("Attribute '%s' does not exist in View" % attr)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.render()
|
||||
|
||||
|
||||
|
||||
def get_or_attr(context_list, name, default=None):
|
||||
"""Returns an attribute from given context."""
|
||||
|
||||
if not context_list:
|
||||
return default
|
||||
|
||||
@@ -17,78 +129,7 @@ def get_or_attr(context_list, name, default=None):
|
||||
return getattr(obj, name)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return default
|
||||
|
||||
class View(object):
|
||||
|
||||
template_name = None
|
||||
template_path = None
|
||||
template = None
|
||||
template_encoding = None
|
||||
template_extension = 'mustache'
|
||||
|
||||
def __init__(self, template=None, context=None, **kwargs):
|
||||
self.template = template
|
||||
context = context or {}
|
||||
context.update(**kwargs)
|
||||
|
||||
self.context_list = [context]
|
||||
|
||||
def get(self, attr, default=None):
|
||||
attr = get_or_attr(self.context_list, attr, getattr(self, attr, default))
|
||||
if hasattr(attr, '__call__') and type(attr) is UnboundMethodType:
|
||||
return attr()
|
||||
else:
|
||||
return attr
|
||||
|
||||
def get_template(self, template_name):
|
||||
if not self.template:
|
||||
from pystache import Loader
|
||||
template_name = self._get_template_name(template_name)
|
||||
self.template = Loader().load_template(template_name, self.template_path, encoding=self.template_encoding, extension=self.template_extension)
|
||||
|
||||
return self.template
|
||||
|
||||
def _get_template_name(self, template_name=None):
|
||||
"""TemplatePartial => template_partial
|
||||
Takes a string but defaults to using the current class' name or
|
||||
the `template_name` attribute
|
||||
"""
|
||||
if template_name:
|
||||
return template_name
|
||||
|
||||
template_name = self.__class__.__name__
|
||||
|
||||
def repl(match):
|
||||
return '_' + match.group(0).lower()
|
||||
|
||||
return re.sub('[A-Z]', repl, template_name)[1:]
|
||||
|
||||
def _get_context(self):
|
||||
context = {}
|
||||
for item in self.context_list:
|
||||
if hasattr(item, 'keys') and hasattr(item, '__getitem__'):
|
||||
context.update(item)
|
||||
return context
|
||||
|
||||
def render(self, encoding=None):
|
||||
return Template(self.get_template(self.template_name), self).render(encoding=encoding)
|
||||
|
||||
def __contains__(self, needle):
|
||||
return needle in self.context or hasattr(self, needle)
|
||||
|
||||
def __getitem__(self, attr):
|
||||
val = self.get(attr, None)
|
||||
|
||||
if not val and val is not 0:
|
||||
raise KeyError("Key '%s' does not exist in View" % attr)
|
||||
return val
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'context':
|
||||
return self._get_context()
|
||||
|
||||
raise AttributeError("Attribute '%s' does not exist in View" % attr)
|
||||
|
||||
def __str__(self):
|
||||
return self.render()
|
||||
Reference in New Issue
Block a user