Coverage for jinja2_async_environment/loaders/dict.py: 83%
47 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-03 14:09 -0700
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-03 14:09 -0700
1"""Async dictionary template loader implementation."""
3import typing as t
5from jinja2.utils import internalcode
7from .base import AsyncBaseLoader, SourceType
9if t.TYPE_CHECKING:
10 from ..environment import AsyncEnvironment
13class AsyncDictLoader(AsyncBaseLoader):
14 """Async dictionary template loader with memory optimization.
16 This loader stores templates in memory as a dictionary, useful for
17 testing and applications that generate templates dynamically.
18 """
20 __slots__ = ("mapping",)
22 def __init__(
23 self,
24 mapping: dict[str, str],
25 searchpath: t.Any = None, # For backward compatibility
26 ) -> None:
27 """Initialize the dictionary loader.
29 Args:
30 mapping: Dictionary mapping template names to template source
31 searchpath: Path or sequence of paths for compatibility
32 """
33 # Call parent with provided searchpath
34 if searchpath is not None:
35 super().__init__(searchpath)
36 else:
37 # Call parent with empty searchpath for backward compatibility
38 super().__init__([])
39 self.mapping = dict(mapping) # Create a copy for safety
41 @internalcode
42 async def get_source_async(
43 self, environment: "AsyncEnvironment", name: str
44 ) -> SourceType:
45 """Get template source from dictionary asynchronously with caching.
47 Args:
48 environment: The async environment instance
49 name: Template name to load
51 Returns:
52 Tuple of (source, filename, uptodate_func)
54 Raises:
55 TemplateNotFound: If template is not in the mapping
56 """
57 self._ensure_initialized()
59 # Try to get from cache first
60 cache_manager = self._get_cache_manager(environment)
61 cache_key = f"dict:{name}"
63 if cache_manager:
64 cached_source = cache_manager.get("template", cache_key)
65 if cached_source is not None:
66 return cached_source
68 if name not in self.mapping:
69 self._handle_template_not_found(name)
71 source = self.mapping[name]
73 # For dictionary loader, we use None as filename and create an uptodate function
74 # that checks if the template still exists and has the same content
75 def uptodate() -> bool:
76 # Check if template still exists
77 if name not in self.mapping:
78 return False
79 # Check if content is the same
80 current_content = self.mapping[name]
81 return current_content == source
83 source_data = (source, None, uptodate)
85 # Cache the result
86 if cache_manager:
87 cache_manager.set("template", cache_key, source_data)
89 return source_data
91 @internalcode
92 async def list_templates_async(self) -> list[str]:
93 """List all templates in the mapping asynchronously.
95 Returns:
96 Sorted list of template names
97 """
98 self._ensure_initialized()
99 return sorted(self.mapping.keys())
101 def add_template(self, name: str, source: str) -> None:
102 """Add a new template to the mapping.
104 Args:
105 name: Template name
106 source: Template source code
107 """
108 self.mapping[name] = source
110 def remove_template(self, name: str) -> None:
111 """Remove a template from the mapping.
113 Args:
114 name: Template name to remove
116 Raises:
117 KeyError: If template is not in the mapping
118 """
119 del self.mapping[name]
121 def update_mapping(self, mapping: dict[str, str]) -> None:
122 """Update the template mapping.
124 Args:
125 mapping: New mapping to merge with existing templates
126 """
127 self.mapping.update(mapping)
129 def clear_templates(self) -> None:
130 """Clear all templates from the mapping."""
131 self.mapping.clear()
133 def has_template(self, name: str) -> bool:
134 """Check if a template exists in the mapping.
136 Args:
137 name: Template name to check
139 Returns:
140 True if template exists, False otherwise
141 """
142 return name in self.mapping