Source code for pyechonext.static

import mimetypes
import os
from pathlib import Path
from typing import List, Optional

from pyechonext.cache import InMemoryCache
from pyechonext.config import Settings
from pyechonext.logging import logger
from pyechonext.utils import prepare_url
from pyechonext.utils.exceptions import StaticFileNotFoundError


[docs] class StaticFile: """ This class describes a static file. """
[docs] def __init__( self, settings: Settings, filename: str, update_timeout: Optional[int] = 3600, precache: Optional[bool] = False, ): """Constructs a Static File Args: settings (Settings): settings of webapp. filename (str, optional): static filename without static dir. update_timeout (int, optional): timeout to update inmemory-cache file content. Defaults to 3600. precache (bool, optional): preload a file content flag. Defaults to False. Raises: StaticFileNotFoundError: static file at static dir not found """ self.settings: Settings = settings self.filename: str = f"/{settings.STATIC_DIR}/{filename}".replace("//", "/") self.abs_filename: Path = Path( os.path.join(self.settings.BASE_DIR, self.settings.STATIC_DIR, filename) ) if not self.abs_filename.exists(): raise StaticFileNotFoundError( f'Static file "{self.abs_filename}" not found.' ) self.content_cache: InMemoryCache = InMemoryCache(timeout=update_timeout) self.precache: bool = precache self.preloaded_value: Optional[str] = None if self.precache: self.preloaded_value = self.caching_static_file()
[docs] def caching_static_file(self): """Set and save static file to cache""" content = self._load_content() item = self.content_cache.get(self.filename) if item is None: logger.debug(f"Caching static file: {self.filename}") self.content_cache.set(self.filename, content) item = content else: logger.debug(f"Load static file from cache: {self.filename}") return item
def _load_content(self) -> str: """Load content of static file Returns: str: content """ with open(self.abs_filename, "r") as file: return file.read().strip()
[docs] def get_content_type(self) -> str: """Get content type Returns: str: get mimetype """ content_type, _ = mimetypes.guess_type(str(self.abs_filename)) return content_type or "application/octet-stream"
[docs] def get_file_size(self) -> int: """Get file size Returns: int: file st size """ return self.abs_filename.stat().st_size
[docs] class StaticFilesManager: """ This class describes a static files manager. """
[docs] def __init__(self, static_files: List[StaticFile]): """Initialize manager Args: static_files (List[StaticFile]): list of static files. """ self.static_files = static_files
[docs] def get_file_type(self, url: str) -> str | None: """Get file content type Args: url (str): static file url Returns: str | None: content type """ for static_file in self.static_files: if static_file.filename == url: return static_file.get_content_type()
[docs] def get_file_size(self, url: str) -> int | None: """Get file size Args: url (str): url of static page Returns: int | None: file size """ for static_file in self.static_files: if static_file.filename == url: return static_file.get_file_size()
[docs] def serve_static_file(self, url: str) -> str | bool: """Serve static files Args: url (str): URL for serving Returns: str | bool: static file content or False if static file not found """ url = prepare_url(url) for static_file in self.static_files: if static_file.filename == url: logger.info(f"Found static file: {static_file.filename}") if static_file.precache: logger.debug(f"Use preloaded value of static file {static_file}") return static_file.preloaded_value else: return static_file.caching_static_file() return False