55from pathlib import Path
66from typing import TYPE_CHECKING , Any
77
8- from jinja2 import Environment , FileSystemLoader , StrictUndefined
8+ from jinja2 import Environment , FileSystemLoader , StrictUndefined , TemplateNotFound
99
1010from corsair ._version import VERSION
1111
1212if TYPE_CHECKING :
13+ from collections .abc import Callable
14+
1315 from typing_extensions import Self
1416
1517
18+ class _EnhancedFileSystemLoader (FileSystemLoader ):
19+ """Custom Jinja2 FileSystemLoader that supports both relative and absolute paths."""
20+
21+ def __init__ (self , searchpath : list [Path ], ** kwargs : Any ) -> None :
22+ super ().__init__ (searchpath = searchpath , ** kwargs )
23+
24+ def get_source (
25+ self ,
26+ environment : Environment ,
27+ template : str ,
28+ ) -> tuple [str , str , Callable [[], bool ]]:
29+ """Get the template source, filename and reload helper for a template.
30+
31+ Checks for absolute paths first, otherwise delegates to the parent FileSystemLoader.
32+ """
33+ template_path = Path (template )
34+ if template_path .is_absolute ():
35+ if not template_path .is_file ():
36+ raise TemplateNotFound (template )
37+
38+ mtime = template_path .stat ().st_mtime
39+ with template_path .open ("r" , encoding = "utf-8" ) as f :
40+ source = f .read ()
41+
42+ # Return the source, filename (absolute path), and a mtime check function
43+ return source , str (template_path ), lambda : template_path .stat ().st_mtime == mtime
44+
45+ # If it's not an absolute path, delegate to the parent class method
46+ return super ().get_source (environment , template )
47+
48+
1649class TemplateEnvironment (Environment ):
1750 """Singleton environment for managing Jinja2 templates."""
1851
@@ -24,14 +57,16 @@ def __new__(cls, *args: Any, **kwargs: Any) -> Self: # noqa: ARG003
2457 cls ._instance = super ().__new__ (cls )
2558 return cls ._instance
2659
27- def __init__ (self , searchpaths : list [Path ] | None = None ) -> None :
60+ def __init__ (self , searchpath : list [Path ] | None = None ) -> None :
2861 """Initialize the template environment."""
29- if not searchpaths :
30- searchpaths = []
31- searchpaths .append (Path (__file__ ).parent )
62+ if not searchpath :
63+ searchpath = []
64+ # Always include the directory containing the built-in templates
65+ if Path (__file__ ).parent not in searchpath :
66+ searchpath .append (Path (__file__ ).parent )
3267
3368 super ().__init__ (
34- loader = FileSystemLoader (searchpath = searchpaths ),
69+ loader = _EnhancedFileSystemLoader (searchpath = searchpath ),
3570 trim_blocks = True ,
3671 lstrip_blocks = True ,
3772 undefined = StrictUndefined , # to throw exception on any undefined variable within template
0 commit comments