import os.path import re from typing import Any from .template import Template class View: # Path where this view's template(s) live template_path = "." # Extension for templates template_extension = "mustache" # The name of this template. If none is given the View will try # to infer it based on the class name. template_name: str = None # Absolute path to the template itself. Pystache will try to guess # if it's not provided. template_file: str = None # Contents of the template. template: str = None # Character encoding of the template file. If None, Pystache will not # do any decoding of the template. template_encoding: str = None def __init__(self, template=None, context=None, **kwargs) -> None: self.template = template self.context = context or {} # If the context we're handed is a View, we want to inherit # its settings. if isinstance(context, View): self.inherit_settings(context) if kwargs: self.context.update(kwargs) def inherit_settings(self, view) -> None: """Given another View, copies its settings.""" if view.template_path: self.template_path = view.template_path if view.template_name: self.template_name = view.template_name def load_template(self) -> Any: if self.template: return self.template if self.template_file: return self._load_template() name = self.get_template_name() + "." + self.template_extension if isinstance(self.template_path, str): self.template_file = os.path.join(self.template_path, name) return self._load_template() for path in self.template_path: self.template_file = os.path.join(path, name) if os.path.exists(self.template_file): return self._load_template() raise IOError('"%s" not found in "%s"' % (name, ":".join(self.template_path),)) def _load_template(self) -> str: f = open(self.template_file, "r") try: template = f.read() if self.template_encoding and isinstance(template, bytes): template = str(template, self.template_encoding) finally: f.close() return template def get_template_name(self, name=None) -> Any: """TemplatePartial => template_partial Takes a string but defaults to using the current class' name or the `template_name` attribute """ if self.template_name: return self.template_name if not name: name = self.__class__.__name__ def repl(match): return "_" + match.group(0).lower() return re.sub("[A-Z]", repl, name)[1:] def __contains__(self, needle) -> bool: return needle in self.context or hasattr(self, needle) def __getitem__(self, attr) -> Any: val = self.get(attr, None) if not val: raise KeyError("No such key.") return val def get(self, attr, default) -> Any: attr = self.context.get(attr, getattr(self, attr, default)) if hasattr(attr, "__call__"): return attr() else: return attr def render(self, encoding=None) -> str: template = self.load_template() return Template(template, self).render(encoding=encoding) def __str__(self) -> str: return self.render()