Source code for chrysalio.includes.themes

"""Theme management."""

from __future__ import annotations
from sys import exit as sys_exit
from os.path import exists, join, abspath
from configparser import ConfigParser

from pyramid.asset import abspath_from_asset_spec
from pyramid.config import Configurator
from pyramid.request import Request

from ..lib.i18n import _, translate
from ..lib.config import config_get_namespace
from ..lib.config import settings_get_list, settings_get_directories


# =============================================================================
[docs] def includeme(configurator: Configurator): """Function to include themes. :type configurator: pyramid.config.Configurator :param configurator: Object used to do configuration declaration within the application. """ if isinstance(configurator, Configurator): load_themes(configurator)
# =============================================================================
[docs] def load_themes(configurator: Configurator): """Load available themes in registry. :type configurator: pyramid.config.Configurator :param configurator: Object used to do configuration declaration within the application. Set into registry a tuple such as ``(default_theme, theme_dict)`` where ``theme_dict`` is a dictionary like ``{'theme_id': theme_info…}``. ``theme_info`` is a dictionary with keys ``path``, ``layout``, ``login``,... """ # Read list of available themes themes = {} directories = settings_get_directories( configurator.get_settings(), 'theme', 'theme.conf') for theme_id, dir_path in directories.items(): config = ConfigParser({'here': dir_path}) config.read(join(dir_path, 'theme.conf'), encoding='utf8') # yapf: disable themes[theme_id] = { 'path': dir_path, 'name': config_get_namespace(config, 'Description', 'name')} for section in ('Templates', 'Static'): if not config.has_section(section): sys_exit(translate(_( '*** Theme "${t}" must have a section [${s}].', {'t': theme_id, 's': section}))) if section == 'Templates' and \ not config.has_option(section, 'layout'): sys_exit(translate(_( '*** An option is missing for [${s}] of theme "${t}".', {'s': section, 't': theme_id}))) if section == 'Static' and ( not config.has_option(section, 'css') or not config.has_option(section, 'js')): sys_exit(translate(_( '*** An option is missing for [${s}] of theme "${t}".', {'s': section, 't': theme_id}))) for item in config.items(section): if item[0] == 'here': continue if not item[1]: sys_exit(translate(_( '*** Option "${o}" of theme "${t}" must be defined.', {'o': item[0], 't': theme_id}))) path = abspath(abspath_from_asset_spec(item[1])) if not exists(path): sys_exit(translate(_( '*** File "${f}" of theme "${t}" does not exist.', {'f': path, 't': theme_id}))) if section == 'Templates': themes[theme_id][item[0]] = path else: configurator.add_static_view( '/theme/{theme_id}/{static_id}/'.format( theme_id=theme_id.lower(), static_id=item[0]), path) # yapf: enable configurator.registry['themes'] = themes configurator.commit() # Read default theme default = configurator.registry['settings']['theme'] default = settings_get_list( configurator.get_settings(), 'theme.patterns', [''])[0] \ if not default and default not in themes and themes else default if default not in themes: sys_exit(translate(_('*** Must have an existing default theme.'))) configurator.registry['settings']['theme'] = default
# =============================================================================
[docs] def create_default_theme(configurator: Configurator, package: str): """If the theme management is not activated, it creates a default theme in registry. :type configurator: pyramid.config.Configurator :param configurator: Object used to do configuration declaration within the application. :param str package: Name of the calling package. """ # Templates settings = configurator.get_settings() path = abspath(abspath_from_asset_spec(f'{package}:Templates')) configurator.registry['themes'] = { '': { 'path': None, 'name': {}, 'layout': settings.get('site.layout', join(path, 'layout2.pt')) } } # Static path = abspath(abspath_from_asset_spec(f'{package}:Static')) configurator.add_static_view( '/css/', settings.get('site.css', join(path, 'Css'))) configurator.add_static_view( '/js/', settings.get('site.js', join(path, 'Js'))) configurator.add_static_view( '/images/', settings.get('site.images', join(path, 'Images'))) configurator.add_static_view( '/fonts/', settings.get('site.fonts', join(path, 'Fonts'))) configurator.add_static_view( '/custom/', settings.get('site.custom', join(path, 'Custom'))) configurator.commit()
# =============================================================================
[docs] def theme_template(request: Request, template_id: str) -> str | None: """Retrieve the absolute file path of the file ``template_id`` of the current theme. :param request: pyramid.request.Request` :param request: Current request. :param str template_id: ID of the file to retrieve. :rtype: str :return: Absolute path to the template file or ``None``. """ theme_id = request.session.get( 'theme', request.registry['settings']['theme']) return request.registry['themes'][theme_id].get(template_id)
# =============================================================================
[docs] def theme_static_prefix(request: Request) -> str: """Return the URL prefix for the current theme. :param request: pyramid.request.Request` :param request: Current request. :rtype: str A string such as ``/theme/alternative`` for theme `Alternative` or ''. """ if request is None: return '' theme_id = request.session.get( 'theme', request.registry['settings']['theme']) return f'/theme/{theme_id.lower()}' if theme_id else ''
# =============================================================================
[docs] def theme_has_static(request: Request, static_id: str) -> bool: """Return ``True`` if the descriminator exists in static views. :param request: pyramid.request.Request` :param request: Current request. :param str static_id: ID of static view to check. :rtype: bool """ theme_id = request.session.get( 'theme', request.registry['settings']['theme']) return request.registry.introspector.get( 'static views', '/theme/{theme_id}/{static_id}/'.format( theme_id=theme_id.lower(), static_id=static_id)) is not None