Commit 20bec630 by Kenneth Reitz

style and import changes

parent 8ca7408f
# -*- coding: utf-8 -*-
"""
pystache.loader
~~~~~~~~~~~~~~~
This module provides Pystache's Loader class.
"""
import os import os
class Loader(object): class Loader(object):
template_extension = 'mustache' template_extension = 'mustache'
template_path = '.' template_path = '.'
template_encoding = None template_encoding = None
def load_template(self, template_name, template_dirs=None, encoding=None, extension=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: if None == template_dirs:
template_dirs = self.template_path template_dirs = self.template_path
if encoding is not None: if encoding is not None:
self.template_encoding = encoding self.template_encoding = encoding
if extension is not None: if extension is not None:
self.template_extension = extension self.template_extension = extension
file_name = template_name + '.' + self.template_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): if isinstance(template_dirs, basestring):
file_path = os.path.join(template_dirs, file_name) file_path = os.path.join(template_dirs, file_name)
return self._load_template_file(file_path) 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: for path in template_dirs:
file_path = os.path.join(path, file_name) file_path = os.path.join(path, file_name)
if os.path.exists(file_path): if os.path.exists(file_path):
return self._load_template_file(file_path) return self._load_template_file(file_path)
raise IOError('"%s" not found in "%s"' % (template_name, ':'.join(template_dirs),)) raise IOError('"%s" not found in "%s"' % (template_name, ':'.join(template_dirs),))
def _load_template_file(self, file_path): 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') f = open(file_path, 'r')
try: try:
template = f.read() template = f.read()
if self.template_encoding: if self.template_encoding:
template = unicode(template, self.template_encoding) template = unicode(template, self.template_encoding)
finally: finally:
f.close() f.close()
return template return template
\ No newline at end of file
# -*- coding: utf-8 -*-
import re import re
import cgi import cgi
import collections import collections
import os
import copy from .loader import Loader
try: try:
import markupsafe import markupsafe
escape = markupsafe.escape escape = markupsafe.escape
literal = markupsafe.Markup literal = markupsafe.Markup
except ImportError: except ImportError:
escape = lambda x: cgi.escape(unicode(x)) escape = lambda x: cgi.escape(unicode(x))
literal = unicode literal = unicode
...@@ -18,15 +19,15 @@ class Modifiers(dict): ...@@ -18,15 +19,15 @@ class Modifiers(dict):
"""Dictionary with a decorator for assigning functions to keys.""" """Dictionary with a decorator for assigning functions to keys."""
def set(self, key): def set(self, key):
""" """Decorator function to set the given key to
Decorator function to set the given key to the decorated function. the decorated function.
>>> modifiers = {} >>> modifiers = {}
>>> @modifiers.set('P') >>> @modifiers.set('P')
... def render_tongue(self, tag_name=None, context=None): ... def render_tongue(self, tag_name=None, context=None):
... return ":P %s" % tag_name ... return ":P %s" % tag_name
>>> modifiers >>> modifiers
{'P': <function render_tongue at 0x...>} {'P': <function render_tongue at 0x...>}
""" """
def setter(func): def setter(func):
...@@ -35,18 +36,17 @@ class Modifiers(dict): ...@@ -35,18 +36,17 @@ class Modifiers(dict):
return setter return setter
class Template(object): class Template(object):
tag_re = None tag_re = None
otag = '{{' otag = '{{'
ctag = '}}' ctag = '}}'
modifiers = Modifiers() modifiers = Modifiers()
def __init__(self, template=None, context=None, **kwargs): def __init__(self, template=None, context=None, **kwargs):
from view import View from .view import View
self.template = template self.template = template
...@@ -56,6 +56,7 @@ class Template(object): ...@@ -56,6 +56,7 @@ class Template(object):
self.view = context if isinstance(context, View) else View(context=context) self.view = context if isinstance(context, View) else View(context=context)
self._compile_regexps() self._compile_regexps()
def _compile_regexps(self): def _compile_regexps(self):
tags = { tags = {
'otag': re.escape(self.otag), 'otag': re.escape(self.otag),
...@@ -68,6 +69,7 @@ class Template(object): ...@@ -68,6 +69,7 @@ class Template(object):
tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+" tag = r"%(otag)s(#|=|&|!|>|\{)?(.+?)\1?%(ctag)s+"
self.tag_re = re.compile(tag % tags) self.tag_re = re.compile(tag % tags)
def _render_sections(self, template, view): def _render_sections(self, template, view):
while True: while True:
match = self.section_re.search(template) match = self.section_re.search(template)
...@@ -82,18 +84,22 @@ class Template(object): ...@@ -82,18 +84,22 @@ class Template(object):
# Callable # Callable
if it and isinstance(it, collections.Callable): if it and isinstance(it, collections.Callable):
replacer = it(inner) replacer = it(inner)
# Dictionary # Dictionary
elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'): elif it and hasattr(it, 'keys') and hasattr(it, '__getitem__'):
if section[2] != '^': if section[2] != '^':
replacer = self._render_dictionary(inner, it) replacer = self._render_dictionary(inner, it)
# Lists # Lists
elif it and hasattr(it, '__iter__'): elif it and hasattr(it, '__iter__'):
if section[2] != '^': if section[2] != '^':
replacer = self._render_list(inner, it) replacer = self._render_list(inner, it)
# Other objects # Other objects
elif it and isinstance(it, object): elif it and isinstance(it, object):
if section[2] != '^': if section[2] != '^':
replacer = self._render_dictionary(inner, it) replacer = self._render_dictionary(inner, it)
# Falsey and Negated or Truthy and Not Negated # Falsey and Negated or Truthy and Not Negated
elif (not it and section[2] == '^') or (it and section[2] != '^'): elif (not it and section[2] == '^') or (it and section[2] != '^'):
replacer = self._render_dictionary(inner, it) replacer = self._render_dictionary(inner, it)
...@@ -102,6 +108,7 @@ class Template(object): ...@@ -102,6 +108,7 @@ class Template(object):
return template return template
def _render_tags(self, template): def _render_tags(self, template):
while True: while True:
match = self.tag_re.search(template) match = self.tag_re.search(template)
...@@ -116,22 +123,32 @@ class Template(object): ...@@ -116,22 +123,32 @@ class Template(object):
return template return template
def _render_dictionary(self, template, context): def _render_dictionary(self, template, context):
self.view.context_list.insert(0, context) self.view.context_list.insert(0, context)
template = Template(template, self.view) template = Template(template, self.view)
out = template.render() out = template.render()
self.view.context_list.pop(0) self.view.context_list.pop(0)
return out return out
def _render_list(self, template, listing): def _render_list(self, template, listing):
insides = [] insides = []
for item in listing: for item in listing:
insides.append(self._render_dictionary(template, item)) insides.append(self._render_dictionary(template, item))
return ''.join(insides) return ''.join(insides)
@modifiers.set(None) @modifiers.set(None)
def _render_tag(self, tag_name): def _render_tag(self, tag_name):
raw = self.view.get(tag_name, '') raw = self.view.get(tag_name, '')
# For methods with no return value # For methods with no return value
...@@ -143,30 +160,41 @@ class Template(object): ...@@ -143,30 +160,41 @@ class Template(object):
return escape(raw) return escape(raw)
@modifiers.set('!') @modifiers.set('!')
def _render_comment(self, tag_name): def _render_comment(self, tag_name):
return '' return ''
@modifiers.set('>') @modifiers.set('>')
def _render_partial(self, template_name): 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) template = Template(markup, self.view)
return template.render() return template.render()
@modifiers.set('=') @modifiers.set('=')
def _change_delimiter(self, tag_name): def _change_delimiter(self, tag_name):
"""Changes the Mustache delimiter.""" """Changes the Mustache delimiter."""
self.otag, self.ctag = tag_name.split(' ') self.otag, self.ctag = tag_name.split(' ')
self._compile_regexps() self._compile_regexps()
return '' return ''
@modifiers.set('{') @modifiers.set('{')
@modifiers.set('&') @modifiers.set('&')
def render_unescaped(self, tag_name): def render_unescaped(self, tag_name):
"""Render a tag without escaping it.""" """Render a tag without escaping it."""
return literal(self.view.get(tag_name, '')) return literal(self.view.get(tag_name, ''))
def render(self, encoding=None): def render(self, encoding=None):
template = self._render_sections(self.template, self.view) template = self._render_sections(self.template, self.view)
result = self._render_tags(template) result = self._render_tags(template)
......
from pystache import Template # -*- coding: utf-8 -*-
import os.path
"""
pystache.loader
~~~~~~~~~~~~~~~
This module provides Pystache's views.
"""
import re import re
from types import * from types import UnboundMethodType
from .loader import Loader
from .template import Template
def get_or_attr(context_list, name, default=None):
if not context_list:
return default
for obj in context_list:
try:
return obj[name]
except KeyError:
pass
except:
try:
return getattr(obj, name)
except AttributeError:
pass
return default
class View(object): class View(object):
"""A Pystache view."""
template_name = None template_name = None
template_path = None template_path = None
template = None template = None
template_encoding = None template_encoding = None
template_extension = 'mustache' template_extension = 'mustache'
def __init__(self, template=None, context=None, **kwargs): def __init__(self, template=None, context=None, **kwargs):
self.template = template self.template = template
context = context or {} context = context or {}
context.update(**kwargs) context.update(kwargs)
self.context_list = [context] self.context_list = [context]
def get(self, attr, default=None): def get(self, attr, default=None):
attr = get_or_attr(self.context_list, attr, getattr(self, attr, default)) attr = get_or_attr(self.context_list, attr, getattr(self, attr, default))
if hasattr(attr, '__call__') and type(attr) is UnboundMethodType: if hasattr(attr, '__call__') and type(attr) is UnboundMethodType:
return attr() return attr()
else: else:
return attr return attr
def get_template(self, template_name): def get_template(self, template_name):
if not self.template: if not self.template:
from pystache import Loader
template_name = self._get_template_name(template_name) 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)
self.template = Loader().load_template(
template_name,
self.template_path,
encoding=self.template_encoding,
extension=self.template_extension)
return self.template return self.template
def _get_template_name(self, template_name=None): def _get_template_name(self, template_name=None):
"""TemplatePartial => template_partial """TemplatePartial => template_partial
Takes a string but defaults to using the current class' name or Takes a string but defaults to using the current class' name or
the `template_name` attribute the `template_name` attribute.
""" """
if template_name: if template_name:
return template_name return template_name
...@@ -64,6 +75,7 @@ class View(object): ...@@ -64,6 +75,7 @@ class View(object):
return re.sub('[A-Z]', repl, template_name)[1:] return re.sub('[A-Z]', repl, template_name)[1:]
def _get_context(self): def _get_context(self):
context = {} context = {}
for item in self.context_list: for item in self.context_list:
...@@ -71,12 +83,16 @@ class View(object): ...@@ -71,12 +83,16 @@ class View(object):
context.update(item) context.update(item)
return context return context
def render(self, encoding=None): def render(self, encoding=None):
return Template(self.get_template(self.template_name), self).render(encoding=encoding) template = Template(self.get_template(self.template_name), self)
return template.render(encoding=encoding)
def __contains__(self, needle): def __contains__(self, needle):
return needle in self.context or hasattr(self, needle) return needle in self.context or hasattr(self, needle)
def __getitem__(self, attr): def __getitem__(self, attr):
val = self.get(attr, None) val = self.get(attr, None)
...@@ -84,11 +100,36 @@ class View(object): ...@@ -84,11 +100,36 @@ class View(object):
raise KeyError("Key '%s' does not exist in View" % attr) raise KeyError("Key '%s' does not exist in View" % attr)
return val return val
def __getattr__(self, attr): def __getattr__(self, attr):
if attr == 'context': if attr == 'context':
return self._get_context() return self._get_context()
raise AttributeError("Attribute '%s' does not exist in View" % attr) raise AttributeError("Attribute '%s' does not exist in View" % attr)
def __str__(self): def __str__(self):
return self.render() return self.render()
\ No newline at end of file
def get_or_attr(context_list, name, default=None):
"""Returns an attribute from given context."""
if not context_list:
return default
for obj in context_list:
try:
return obj[name]
except KeyError:
pass
except:
try:
return getattr(obj, name)
except AttributeError:
pass
return default
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment