Coverage for src / minibook / utils.py: 100%

21 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-01-27 10:03 +0000

1"""Utility functions for MiniBook. 

2 

3This module provides shared utility functions used across MiniBook modules. 

4""" 

5 

6from datetime import datetime 

7from pathlib import Path 

8 

9from jinja2 import Environment, FileSystemLoader, Template, select_autoescape 

10 

11TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S" 

12 

13# Extensions that should have autoescape enabled 

14AUTOESCAPE_EXTENSIONS = ("html", "htm", "xml", "j2", "jinja", "jinja2") 

15 

16 

17def get_timestamp() -> str: 

18 r"""Generate a formatted timestamp string. 

19 

20 Returns: 

21 A timestamp string in the format 'YYYY-MM-DD HH:MM:SS'. 

22 

23 Examples: 

24 >>> import re 

25 >>> ts = get_timestamp() 

26 >>> bool(re.match(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}', ts)) 

27 True 

28 """ 

29 return datetime.now().strftime(TIMESTAMP_FORMAT) 

30 

31 

32def create_jinja_env(template_dir: Path) -> Environment: 

33 """Create a Jinja2 environment with secure defaults. 

34 

35 Args: 

36 template_dir: Directory containing template files. 

37 

38 Returns: 

39 A configured Jinja2 Environment with autoescape enabled. 

40 """ 

41 return Environment( 

42 loader=FileSystemLoader(template_dir), 

43 autoescape=select_autoescape(enabled_extensions=AUTOESCAPE_EXTENSIONS, default=True), 

44 ) 

45 

46 

47def load_template(template_path: str | None = None, default_template: str = "html.j2") -> Template: 

48 """Load a Jinja2 template from a path or use the default. 

49 

50 Args: 

51 template_path: Optional path to a custom Jinja2 template file. 

52 default_template: Name of the default template to use if no custom path provided. 

53 

54 Returns: 

55 A loaded Jinja2 Template object. 

56 

57 Raises: 

58 FileNotFoundError: If the specified template file does not exist. 

59 

60 Examples: 

61 >>> template = load_template() # Uses default html.j2 

62 >>> template.name 

63 'html.j2' 

64 >>> template = load_template(default_template="bare.j2") 

65 >>> template.name 

66 'bare.j2' 

67 """ 

68 if template_path: 

69 template_file = Path(template_path) 

70 if not template_file.exists(): 

71 msg = f"Template file not found: {template_path}" 

72 raise FileNotFoundError(msg) 

73 

74 template_dir = template_file.parent 

75 env = create_jinja_env(template_dir) 

76 return env.get_template(template_file.name) 

77 

78 # Use default template from package 

79 template_dir = Path(__file__).parent / "templates" 

80 env = create_jinja_env(template_dir) 

81 return env.get_template(default_template)