Source code for cioxml2.lib.utils

"""Some various utilities."""

from __future__ import annotations
from os import remove
from os.path import join, exists, basename, splitext
from re import finditer as re_finditer, sub as re_sub
from base64 import b64encode
from json import load as json_load, dumps as json_dumps
from json.decoder import JSONDecodeError

from pyramid.request import Request

from cioprocessor.lib.utils import select_files
from cioprocessor.lib.pbuild import PBuild
from ciowarehouse2.lib.ciotype import CioType
from ciowarehouse2.lib.ciopath import CioPath
from ciowarehouse2.lib.warehouse import Warehouse
from .i18n import _, translate


# =============================================================================
[docs] def special_protect(content: str) -> str: """Convert special characters (&, <, >) in a secure representation. :param str content: Content to protect. :rtype: str """ return content\ .replace('&amp;', '&').replace(' ', '‧')\ .replace('&lt;', '<').replace('&gt;', '>') \ if content else ''
# =============================================================================
[docs] def special_unprotect(content: str) -> str: """Cancel the protection made by _special_protect(). :param str content: Protected content. :rtype: str """ return content\ .replace('&', '&amp;').replace('‧', ' ')\ .replace('<', '&lt;').replace('>', '&gt;').replace('’', "'") \ if content else ''
# =============================================================================
[docs] def image_base64( pbuild: PBuild, abs_path: str, html: str, remove_original: bool = True) -> str | None: """Replace image source with its content in base64. :type pbuild: .lib.pbuild.PBuild :param pbuild: Current processor build object. :param str abs_path: Absolute path to current directory. :param str html: HTML to process. :param remove_original: bool If `True`, remove original image. :rtype: str """ modified = False to_remove = set() for occur in re_finditer(r'src="([^\?"]+)\?cioreplace=base64"', html): filename = join(abs_path, occur.group(1)) if not exists(filename): pbuild.warning( translate( _('${f} does not exist.', {'f': occur.group(1)}), pbuild.lang)) continue with open(filename, 'rb') as hdl: encoded = b64encode(hdl.read()) ext = { '.png': 'png', '.jpg': 'jpeg', '.jpeg': 'jpeg', '.svg': 'svg+xml', '.gif': 'gif', '.webp': 'webp' }.get(splitext(filename)[1], 'png') html = html.replace( occur.group(0), f'src="data:image/{ext};base64,{encoded.decode("utf8")}"') if remove_original: to_remove.add(filename) modified = True for filename in to_remove: remove(filename) return html if modified else None
# =============================================================================
[docs] def remove_css_maps(pbuild: PBuild, step: dict): """Remove CSS maps and their call. :type build: cioprocessor.lib.build.PBuild :param build: Current build object. :param dict step: Dictionary defining the current step. """ if not pbuild.current['values'].get('remove_css_map'): return if 'select' not in step: step['select'] = '\\.css$' for path in select_files(pbuild, step): map_file = '{}.map'.format(path) if exists(map_file): remove(map_file) with open(path, 'r', encoding='utf8') as hdl: content = hdl.read() content = re_sub('/\\*# sourceMappingURL=[^*]+\\*/', '', content) with open(path, 'w', encoding='utf8') as hdl: hdl.write(content)
# =============================================================================
[docs] def ajust_css_maps(pbuild: PBuild, step: dict): """Ajust CSS maps and their call. :type build: cioprocessor.lib.build.PBuild :param build: Current build object. :param dict step: Dictionary defining the current step. """ if 'select' not in step: step['select'] = '\\.css$' for path in select_files(pbuild, step): with open(path, 'r', encoding='utf8') as hdl: content = hdl.read() content = re_sub( '/\\*# sourceMappingURL=[^*]+\\*/', f'/*# sourceMappingURL={basename(path)}.map */', content) with open(path, 'w', encoding='utf8') as hdl: hdl.write(content)
# =============================================================================
[docs] def pretty_print_json(pbuild: PBuild, step: dict) -> bool: """Pretty print JSON files. :type build: cioprocessor.lib.build.PBuild :param build: Current build object. :param dict step: Dictionary defining the current step. :rtype: bool """ if 'select' not in step: step['select'] = '\\.json$' has_error = False for path in select_files(pbuild, step): with open(path, 'r', encoding='utf8') as hdl: try: json = json_load(hdl) except (OSError, JSONDecodeError) as error: pbuild.error( translate(_('JSON: ${e}', {'e': error}), pbuild.lang)) has_error = True continue with open(path, 'w', encoding='utf8') as hdl: hdl.write(json_dumps(json, indent=4, ensure_ascii=False)) return has_error
# =============================================================================
[docs] def calling_file( request: Request, rendering_type: str | None = None ) -> tuple[Warehouse | None, CioPath | None, dict | None]: """Return warehouse, `CioPath` and rendering of the URL found in the request. :type request: pyramid.request.Request :param request: Current request. :param str rendering_type: (optional) Type of rendering ('viewing' or 'editing') :rtype: tuple """ ciotype = CioType.from_request(request) ciopath = CioPath.from_request(request) ciowarehouse2 = request.registry['modules']['ciowarehouse2'] warehouse = ciowarehouse2.warehouse(request, ciopath.wid) manager = ciowarehouse2.manager(request, ciotype) if warehouse is None or manager is None: return warehouse, ciopath, None if rendering_type is None: rendering_type = request.matchdict.get('rendering') rendering = manager.current_rendering(request, warehouse, rendering_type) return warehouse, ciopath, rendering