@@ -208,6 +208,11 @@ class Environment:
208
208
`optimized`
209
209
should the optimizer be enabled? Default is ``True``.
210
210
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
+
211
216
`undefined`
212
217
:class:`Undefined` or a subclass of it that is used to represent
213
218
undefined values in the template.
@@ -313,6 +318,7 @@ def __init__(
313
318
auto_reload : bool = True ,
314
319
bytecode_cache : t .Optional ["BytecodeCache" ] = None ,
315
320
enable_async : bool = False ,
321
+ remember_parsed_names : bool = False ,
316
322
):
317
323
# !!Important notice!!
318
324
# The constructor accepts quite a few arguments that should be
@@ -344,6 +350,9 @@ def __init__(
344
350
self .optimized = optimized
345
351
self .finalize = finalize
346
352
self .autoescape = autoescape
353
+ self .parsed_names : t .Optional [t .List [str ]] = (
354
+ [] if remember_parsed_names else None
355
+ )
347
356
348
357
# defaults
349
358
self .filters = DEFAULT_FILTERS .copy ()
@@ -614,8 +623,36 @@ def _parse(
614
623
self , source : str , name : t .Optional [str ], filename : t .Optional [str ]
615
624
) -> nodes .Template :
616
625
"""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 )
617
628
return Parser (self , source , name , filename ).parse ()
618
629
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
+
619
656
def lex (
620
657
self ,
621
658
source : str ,
0 commit comments