Source code for optimus.pages.views.base

# -*- coding: utf-8 -*-
import logging
import os

from jinja2 import meta as Jinja2Meta

from optimus.exceptions import ViewImproperlyConfigured
from optimus.i18n.lang import LangBase


[docs]class PageViewBase: """ Base view object for a page You can set class attributes at the init if needed The render method is responsible to rendering the HTML from the template and his context. Actually this is the only used method directly. Only ``lang`` and ``context`` attributes are optional, so take care to set all the required ones because their default value is ``None``. You should not use directly ``PageViewBase``, inherit it in a common object with all attributes setted by default. Template context will have the following variables : page_title Page title page_destination Page destination page_lang Given langage if any page_template_name Template name used to compile the page HTML But you can add new variable if needed. The default context variables can not be overriden from the ``context`` class attribute, only from the ``get_context`` class method. View need settings to be defined either as argument on instance init or later through attribute setter. Attributes: title (string): Page title. template_name (string): Page template file path relaive to templates directoy. Used as Python template string with optional non positional argument ``{{ language_code }}`` available for internationalized pages. destination (string): Page destionation path relative to build directory. lang (string): Language identifier or an instance of ``optimus.i18n.LangBase``. context (dict): Initial page template context. logger (logging.Logger): Optimus logger. _used_templates (list): List of every used templates. Only filled when ``introspect()`` method is executed. Default to ``None``. __settings (conf.model.SettingsModel): Settings registry instance when given in kwargs. Default to ``None``. Arguments: **kwargs: Arbitrary keyword arguments. Will be added as object attribute. """ title = None template_name = None destination = None lang = None context = {} def __init__(self, **kwargs): self._used_templates = None self.logger = logging.getLogger("optimus") self.__settings = kwargs.pop("settings", None) # Store every passed keyword argument as object attribute for key, value in kwargs.items(): setattr(self, key, value) self.validate() def __str__(self): return self.get_destination() def __repr__(self): """ Object representation Returns: string: Representation with name and code """ return "<{name} {dest}>".format( name=self.__class__.__name__, dest=self.get_destination() )
[docs] def validate(self): """ Validate every required attribute is set. Returns: boolean: ``True`` if requirements are set. """ err = [] for item in ["title", "template_name", "destination"]: if not getattr(self, item): err.append(item) if len(err) > 0: msg = "These attributes are required: {}".format(", ".join(err)) raise ViewImproperlyConfigured(msg) return True
@property def settings(self): """ ``settings`` attribute getter, check settings have been correctly defined. Returns: conf.model.SettingsModel: Settings registry instance when given in kwargs. Default to ``None``. """ if not self.__settings: msg = ( """View required settings defined either from init """ """arguments or through settings attribute""" ) raise ViewImproperlyConfigured(msg) return self.__settings @settings.setter def settings(self, settings): """ ``settings`` attribute setter Arguments: settings (conf.model.SettingsModel): Settings registry instance. """ self.__settings = settings
[docs] def get_title(self): """ Get page title. Default behavior is to used page attribute ``title``. Returns: string: Page title. """ return self.title
[docs] def get_lang(self): """ Get page language object. Returns: optimus.i18n.LangBase: Language object. If ``lang`` page attribute is ``None`` it will create a language object using default language identifier from setting ``LANGUAGE_CODE``. """ # Defaut language identifier if not given if getattr(self, "lang", None) is None: self.lang = LangBase(code=self.settings.LANGUAGE_CODE) # If the lang attribute contains a string, assume this is the language # identifier elif isinstance(getattr(self, "lang"), str): self.lang = LangBase(code=getattr(self, "lang")) return self.lang
[docs] def get_destination(self): """ Get page destination path. Returns: string: Page destination path relative to build directory. """ return os.path.normpath( self.destination.format(language_code=self.get_lang().code) )
[docs] def get_relative_position(self): """ Get relative path position from the destination file to the root. Returns: string: Either something like "../../" if the destination is in subdirectories or "./" if at the root. Won't never return empty string. """ return (len(self.get_destination().split("/")) - 1) * "../" or "./"
[docs] def get_template_name(self): """ Get template file path. Returns: string: Template file path relative to templates directory. """ return self.template_name.format(language_code=self.get_lang().code)
[docs] def get_context(self): """ Get template context. Returns: dict: Template context of variables. """ self.context.update( { "page_title": self.get_title(), "page_destination": self.get_destination(), "page_relative_position": self.get_relative_position(), "page_lang": self.get_lang(), "page_template_name": self.get_template_name(), } ) self.logger.debug(" - Initial context: {}".format(self.context)) return self.context
[docs] def render(self, env): """ Take the Jinja2 environment as required argument. Arguments: env (jinja2.Jinja2Environment): Jinja environment. Returns: string: HTML builded from page template with its context. """ self.env = env context = self.get_context() template = self.env.get_template(self.get_template_name()) return template.render(lang=self.get_lang(), **context)
[docs] def introspect(self, env): """ Take the Jinja2 environment as required argument to find every templates dependancies from page. Arguments: env (jinja2.Jinja2Environment): Jinja environment. Returns: list: List of involved templates sources files. """ if self._used_templates is None: self.env = env found = self._recurse_template_search(env, self.get_template_name()) self._used_templates = [self.get_template_name()] + found self.logger.debug(" - Used templates: {}".format(self._used_templates)) return self._used_templates