mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
118 lines
3.5 KiB
Python
118 lines
3.5 KiB
Python
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()
|