@@ -299,6 +299,7 @@ def _resolve_includes(template: str):
299
299
300
300
301
301
def _resolve_includes_blocks_and_extends (template : str ):
302
+ extended_templates : "set[str]" = set ()
302
303
block_replacements : "dict[str, str]" = {}
303
304
304
305
# Processing nested child templates
@@ -308,6 +309,19 @@ def _resolve_includes_blocks_and_extends(template: str):
308
309
if not _exists_and_is_file (extended_template_path ):
309
310
raise OSError (f"Template file not found: { extended_template_path } " )
310
311
312
+ # Check for circular extends
313
+ if extended_template_path in extended_templates :
314
+ raise TemplateSyntaxError (
315
+ f"Circular extends" ,
316
+ Token (
317
+ template ,
318
+ extends_match .start (),
319
+ extends_match .end (),
320
+ ),
321
+ )
322
+ else :
323
+ extended_templates .add (extended_template_path )
324
+
311
325
# Load extended template
312
326
with open (
313
327
extended_template_path , "rt" , encoding = "utf-8"
@@ -334,16 +348,16 @@ def _resolve_includes_blocks_and_extends(template: str):
334
348
while (block_match := _find_block (template [offset :])) is not None :
335
349
block_name = block_match .group (0 )[9 :- 3 ]
336
350
337
- # Check for any unopened endblock tags before current block
338
- if unopened_endblock_match := _find_endblock (
351
+ # Check for any tokens between blocks
352
+ if token_between_blocks_match := _find_token (
339
353
template [offset : offset + block_match .start ()]
340
354
):
341
355
raise TemplateSyntaxError (
342
- "No matching {% block %} " ,
356
+ "Token between blocks " ,
343
357
Token (
344
358
template ,
345
- offset + unopened_endblock_match .start (),
346
- offset + unopened_endblock_match .end (),
359
+ offset + token_between_blocks_match .start (),
360
+ offset + token_between_blocks_match .end (),
347
361
),
348
362
)
349
363
0 commit comments