[docs]classPageBuilder(object):""" Builder class to init Jinja2 environment and build given pages. Arguments: settings (conf.model.SettingsModel): Settings registry instance. Keyword Arguments: jinja_env (jinja2.Jinja2Environment): Jinja2 environment. Default is ``None``. assets_env (webassets.Environment): Webasset environment. Default is ``None``. dry_run (boolean): Enable dry run mode. Default is ``False``. Attributes: logger (logging.Logger): Optimus logger. settings (conf.model.SettingsModel): Settings registry instance. jinja_env (jinja2.Jinja2Environment): Jinja2 environment. Default is ``None``. assets_env (webassets.Environment): Webasset environment. Default is ``None``. internationalized (boolean): Indicate if internationalization is enabled. Will be automatically set to ``True`` if Jinja environment enable the i18n extension. translations (dict): Dictionnary of translation catalog indexed on language identifier. registry (optimus.pages.registry.PageRegistry): Registry of all knowed page from scanning. Registry will be automatically filled only if you use the ``PageBuilder.scan_bulk(..)`` method. dry_run (boolean): Dry run mode. """def__init__(self,settings,jinja_env=None,assets_env=None,dry_run=False):self.logger=logging.getLogger("optimus")self.settings=settingsself.assets_env=assets_envself.internationalized=Falseself.translations={}self.jinja_env=jinja_envorself.get_environnement(assets_env)self.jinja_env.globals.update(self.get_globals())self.logger.debug("PageBuilder initialized")self.registry=PageRegistry()self.dry_run=dry_run
[docs]defget_environnement(self,assets_env=None):""" Init and configure Jinja environment. Automatically enable some extensions and link possible asset environment. Keyword Arguments: assets_env (webassets.Environment): Webasset environment. Default is ``None``. If empty, webassets will not be available from page templates. Returns: jinja2.Jinja2Environment: Configured Jinja2 environment. """exts=[]self.logger.debug(("No Jinja2 environment given, initializing a new environment"))# It the assets environment is given, active the Jinja extension to# use webassetsifself.assets_envisnotNone:exts.append(AssetsExtension)# Enabled Jinja extensionsforextinself.settings.JINJA_EXTENSIONS:exts.append(ext)# Active i18n behaviors if i18n extension is loaded and Babel has been# importedif"jinja2.ext.i18n"inextsandbabel_supportisnotNone:self.internationalized=Trueself.logger.debug("'i18n' enabled")# Boot Jinja environmentenv=Jinja2Environment(loader=FileSystemLoader(self.settings.TEMPLATES_DIR),extensions=exts)# Enable Jinja filtersforname,moduleinself.settings.JINJA_FILTERS.items():env.filters[name]=moduleifassets_env:env.assets_environment=assets_envreturnenv
[docs]defserialize_settings(self):""" Get and return valid settings variables. Valid settings means only variable names full uppercase. Returns: dict: Settings variables. """items={}foritemindir(self.settings):ifnotitem.startswith("_")anditem.isupper():items[item]=getattr(self.settings,item)returnitems
[docs]defget_globals(self):""" Get global context variables. Returns: dict: Shortcuts to some common settings like ``SITE`` options, static urls, Optimus version and finally all settings contained in ``_SETTINGS``. """domain_prefix="http://{}"ifself.settings.HTTPS_ENABLED:domain_prefix="https://{}"return{"debug":self.settings.DEBUG,"SITE":{"name":self.settings.SITE_NAME,"domain":self.settings.SITE_DOMAIN,"web_url":domain_prefix.format(self.settings.SITE_DOMAIN),},"STATIC_URL":self.settings.STATIC_URL,"_SETTINGS":self.serialize_settings(),"OPTIMUS":__version__,}
[docs]defget_translation_for_item(self,page_item):""" Try to load the translations for the page language if any, then install it in Jinja2. It does not reload a language translations if a previous page has allready loaded it. Arguments: page_item (optimus.pages.views.PageViewBase): Page instance which its language identifier will be used to search for translation catalog. Returns: babel.support.Translations: Translations object to give to Jinja i18n extension. """ifnotbabel_support:returnNone# Get page language objectlang=page_item.get_lang()# Dont load again allredy registered catalogiflang.codenotinself.translations:msg=" - Loading translations for locale: {} - {}"self.logger.debug(msg.format(lang.code,lang))self.translations[lang.code]=babel_support.Translations.load(self.settings.LOCALES_DIR,lang.code,"messages")# Install it in the Jinja envself.jinja_env.install_gettext_translations(self.translations[lang.code],newstyle=False)returnself.translations[lang.code]
[docs]defscan_item(self,page_item):""" Scan given page to retrieve template dependancies. Possibly connect settings to page instance if not allready done. Arguments: page_item (optimus.pages.views.PageViewBase): Page instance. Returns: string: All used templates from given page. """# Connect stored settings to page if not allready settry:page_item.settingsexceptViewImproperlyConfigured:page_item.settings=self.settingsmsg=" Scanning page: {}"self.logger.info(msg.format(page_item.get_destination()))returnpage_item.introspect(self.jinja_env)
[docs]defscan_bulk(self,page_list):""" Scan all given pages to register their dependancy templates. TODO: Implement a 'settings' kwarg to pass to 'scan_item' to connect settings object to view. Arguments: page_list (list): List of page instances. Returns: set: Every template names involved in scanned page instances. """self.logger.info("Starting page builds")ifnotpage_list:self.logger.warning(("Page scanning skipped as there are no registered pages"))returnNoneknowed=set([])forpageinpage_list:# Scan possible view template to find templates inheritances to registerfound=self.scan_item(page)iffound:self.registry.add_page(page,found)knowed.update(found)# Scan possible view datas to registerself.registry.add_data(page,page.get_datas())ifgetattr(page,"template_name",None):knowed.add(page.template_name)returnknowed
[docs]defbuild_item(self,page_item):""" Build given page. Possibly connect settings to page instance if not allready done. Arguments: page_item (optimus.pages.views.PageViewBase): Page instance. Returns: string: Destination path from builded page. """# Connect stored settings to page if not allready settry:page_item.settingsexceptViewImproperlyConfigured:page_item.settings=self.settingsmsg=" Building page: {}"self.logger.info(msg.format(page_item.get_destination()))# Optional i18nifself.internationalized:self.get_translation_for_item(page_item)# Template rendercontent=page_item.render(self.jinja_env)# Creating destination path if neededdestination_path=os.path.join(self.settings.PUBLISH_DIR,page_item.get_destination())destination_dir,destination_file=os.path.split(destination_path)ifnotos.path.exists(destination_dir):msg=" - Creating new directory : {}"self.logger.debug(msg.format(destination_dir))ifnotself.dry_run:os.makedirs(destination_dir)# Write itself.logger.debug(" - Writing to: {}".format(destination_path))ifnotself.dry_run:withio.open(destination_path,"w")asfp:fp.write(content)returndestination_path
[docs]defbuild_bulk(self,page_list):""" Build all given pages. Return all the effective builded pages Arguments: page_list (list): List of page instances. Returns: list: List of destination paths from builded pages. """self.logger.info("Starting page builds")ifnotpage_list:self.logger.warning("Page management is skipped because there are no registered pages")returnNonebuilded=[]forpageinpage_list:builded.append(self.build_item(page))returnbuilded