@@ -208,6 +208,11 @@ class Environment:
208208 `optimized`
209209 should the optimizer be enabled? Default is ``True``.
210210
211+ `remember_parsed_names`
212+ Should we remember parsed names? This is useful for dynamic
213+ dependency tracking, see `extract_parsed_names` for details.
214+ Default is ``False``.
215+
211216 `undefined`
212217 :class:`Undefined` or a subclass of it that is used to represent
213218 undefined values in the template.
@@ -305,6 +310,7 @@ def __init__(
305310 keep_trailing_newline : bool = KEEP_TRAILING_NEWLINE ,
306311 extensions : t .Sequence [t .Union [str , t .Type ["Extension" ]]] = (),
307312 optimized : bool = True ,
313+ remember_parsed_names : bool = False ,
308314 undefined : t .Type [Undefined ] = Undefined ,
309315 finalize : t .Optional [t .Callable [..., t .Any ]] = None ,
310316 autoescape : t .Union [bool , t .Callable [[t .Optional [str ]], bool ]] = False ,
@@ -344,6 +350,9 @@ def __init__(
344350 self .optimized = optimized
345351 self .finalize = finalize
346352 self .autoescape = autoescape
353+ self .parsed_names : t .Optional [t .List [str ]] = (
354+ [] if remember_parsed_names else None
355+ )
347356
348357 # defaults
349358 self .filters = DEFAULT_FILTERS .copy ()
@@ -614,8 +623,36 @@ def _parse(
614623 self , source : str , name : t .Optional [str ], filename : t .Optional [str ]
615624 ) -> nodes .Template :
616625 """Internal parsing function used by `parse` and `compile`."""
626+ if name is not None and self .parsed_names is not None :
627+ self .parsed_names .append (name )
617628 return Parser (self , source , name , filename ).parse ()
618629
630+ def extract_parsed_names (self ) -> t .Optional [t .List [str ]]:
631+ """Return all template names that have been parsed so far, and clear the list.
632+
633+ This is enabled if `remember_parsed_names = True` was passed to the
634+ `Environment` constructor, otherwise it returns `None`. It can be used
635+ after `Template.render()` to extract dependency information. Compared
636+ to `jinja2.meta.find_referenced_templates()`, it:
637+
638+ a. works on dynamic inheritance and includes
639+ b. does not work unless and until you actually render the template
640+
641+ Many buildsystems are unable to support (b), but some do e.g. [1], the
642+ key point being that if the target file does not exist, dependency
643+ information is not needed since the target file must be built anyway.
644+ In such cases, you may prefer this function due to (a).
645+
646+ [1] https://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
647+
648+ .. versionadded:: 3.2
649+ """
650+ if self .parsed_names is None :
651+ return None
652+ names = self .parsed_names [:]
653+ self .parsed_names .clear ()
654+ return names
655+
619656 def lex (
620657 self ,
621658 source : str ,
0 commit comments