@@ -192,6 +192,10 @@ def create_file(
192192 tag_intro_text: str
193193 the words after which the tags of a given page are listed (e.g. "Tags: programming, python")
194194
195+ Returns
196+ -------
197+ filename : str
198+ The path of the generated file.
195199
196200 """
197201 # Get sorted file paths for tag pages, relative to /docs/_tags
@@ -228,10 +232,10 @@ def create_file(
228232 content .append (f" ../{ path } " )
229233
230234 content .append ("" )
231- with open (
232- os .path .join (srcdir , tags_output_dir , filename ), "w" , encoding = "utf8"
233- ) as f :
235+ output_filepath = os .path .join (srcdir , tags_output_dir , filename )
236+ with open (output_filepath , "w" , encoding = "utf8" ) as f :
234237 f .write ("\n " .join (content ))
238+ return output_filepath
235239
236240
237241class Entry :
@@ -316,6 +320,12 @@ def tagpage(tags, outdir, title, extension, tags_index_head):
316320
317321 This page contains a list of all available tags.
318322
323+ Returns
324+ -------
325+
326+ filename : str
327+ Filename of generated file.
328+
319329 """
320330
321331 tags = list (tags .values ())
@@ -365,6 +375,8 @@ def tagpage(tags, outdir, title, extension, tags_index_head):
365375 with open (filename , "w" , encoding = "utf8" ) as f :
366376 f .write ("\n " .join (content ))
367377
378+ return filename
379+
368380
369381def assign_entries (app ):
370382 """Assign all found entries to their tag."""
@@ -388,6 +400,7 @@ def assign_entries(app):
388400
389401def update_tags (app ):
390402 """Update tags according to pages found"""
403+ generated_files = []
391404 if app .config .tags_create_tags :
392405 tags_output_dir = Path (app .config .tags_output_dir )
393406
@@ -402,28 +415,41 @@ def update_tags(app):
402415 tags , pages = assign_entries (app )
403416
404417 for tag in tags .values ():
405- tag .create_file (
418+ filepath = tag .create_file (
406419 [item for item in pages if tag .name in item .tags ],
407420 app .config .tags_extension ,
408421 tags_output_dir ,
409422 app .srcdir ,
410423 app .config .tags_page_title ,
411424 app .config .tags_page_header ,
412425 )
426+ generated_files .append (filepath )
413427
414428 # Create tags overview page
415- tagpage (
429+ filepath = tagpage (
416430 tags ,
417431 os .path .join (app .srcdir , tags_output_dir ),
418432 app .config .tags_overview_title ,
419433 app .config .tags_extension ,
420434 app .config .tags_index_head ,
421435 )
436+ generated_files .append (filepath )
422437 logger .info ("Tags updated" , color = "white" )
423438 else :
424439 logger .info (
425440 "Tags were not created (tags_create_tags=False in conf.py)" , color = "white"
426441 )
442+ return [os .path .relpath (gf .split ("." )[0 ], app .srcdir ) for gf in generated_files ]
443+
444+
445+ def refresh_tags_on_incremental_build (app , env , added , changed , removed ):
446+ generated_files = set (update_tags (app ))
447+ if new_files := generated_files .difference (env .found_docs ):
448+ logger .warning (
449+ "The following new tag files were generated on an incremental build, they will not be built by sphinx %s" ,
450+ new_files ,
451+ )
452+ return generated_files
427453
428454
429455def setup (app ):
@@ -456,6 +482,7 @@ def setup(app):
456482 # tags should be updated after sphinx-gallery is generated, and the
457483 # sphinx-gallery plugin uses default priority so we use a higher one
458484 app .connect ("builder-inited" , update_tags , priority = 1000 )
485+ app .connect ("env-get-outdated" , refresh_tags_on_incremental_build )
459486 app .add_directive ("tags" , TagLinks )
460487
461488 return {
0 commit comments