99import gc
1010from importlib .metadata import metadata
1111import os
12+ from pathlib import Path
1213import subprocess
1314import sys
1415import time
6061# (Sphinx looks at variable changes and rewrites all files if some change)
6162copyright = (
6263 f'2012–{ td .year } , MNE Developers. Last updated <time datetime="{ td .isoformat ()} " class="localized">{ td .strftime ("%Y-%m-%d %H:%M %Z" )} </time>\n ' # noqa: E501
63- '<script type="text/javascript">$(function () { $("time.localized").each(function () { var el = $(this); el.text(new Date(el.attr("datetime")).toLocaleString([], {dateStyle: "medium", timeStyle: "long"})); }); } )</script>'
64- ) # noqa: E501
64+ '<script type="text/javascript">$(function () { $("time.localized").each(function () { var el = $(this); el.text(new Date(el.attr("datetime")).toLocaleString([], {dateStyle: "medium", timeStyle: "long"})); }); } )</script>' # noqa: E501
65+ )
6566if os .getenv ("MNE_FULL_DATE" , "false" ).lower () != "true" :
6667 copyright = f"2012–{ td .year } , MNE Developers. Last updated locally."
6768
@@ -1636,87 +1637,70 @@ def reset_warnings(gallery_conf, fname):
16361637custom_redirects = {
16371638 # Custom redirects (one HTML path to another, relative to outdir)
16381639 # can be added here as fr->to key->value mappings
1639- "install/contributing.html" : "development/contributing.html" ,
1640- "overview/roadmap.html" : "development/roadmap.html" ,
1641- "whats_new.html" : "development/whats_new.html" ,
1642- f"{ tu } /evoked/plot_eeg_erp.html" : f"{ tu } /evoked/30_eeg_erp.html" ,
1643- f"{ tu } /evoked/plot_whitened.html" : f"{ tu } /evoked/40_whitened.html" ,
1644- f"{ tu } /misc/plot_modifying_data_inplace.html" : f"{ tu } /intro/15_inplace.html" ,
1645- f"{ tu } /misc/plot_report.html" : f"{ tu } /intro/70_report.html" ,
1646- f"{ tu } /misc/plot_seeg.html" : f"{ tu } /clinical/20_seeg.html" ,
1647- f"{ tu } /misc/plot_ecog.html" : f"{ tu } /clinical/30_ecog.html" ,
1648- f"{ tu } /{ ml } /plot_receptive_field.html" : f"{ tu } /{ ml } /30_strf.html" ,
1649- f"{ tu } /{ ml } /plot_sensors_decoding.html" : f"{ tu } /{ ml } /50_decoding.html" ,
1650- f"{ tu } /{ sm } /plot_background_freesurfer.html" : f"{ tu } /{ fw } /10_background_freesurfer.html" , # noqa E501
1651- f"{ tu } /{ sm } /plot_source_alignment.html" : f"{ tu } /{ fw } /20_source_alignment.html" ,
1652- f"{ tu } /{ sm } /plot_forward.html" : f"{ tu } /{ fw } /30_forward.html" ,
1653- f"{ tu } /{ sm } /plot_eeg_no_mri.html" : f"{ tu } /{ fw } /35_eeg_no_mri.html" ,
1654- f"{ tu } /{ sm } /plot_background_freesurfer_mne.html" : f"{ tu } /{ fw } /50_background_freesurfer_mne.html" , # noqa E501
1655- f"{ tu } /{ sm } /plot_fix_bem_in_blender.html" : f"{ tu } /{ fw } /80_fix_bem_in_blender.html" ,
1656- f"{ tu } /{ sm } /plot_compute_covariance.html" : f"{ tu } /{ fw } /90_compute_covariance.html" ,
1657- f"{ tu } /{ sm } /plot_object_source_estimate.html" : f"{ tu } /{ nv } /10_stc_class.html" ,
1658- f"{ tu } /{ sm } /plot_dipole_fit.html" : f"{ tu } /{ nv } /20_dipole_fit.html" ,
1659- f"{ tu } /{ sm } /plot_mne_dspm_source_localization.html" : f"{ tu } /{ nv } /30_mne_dspm_loreta.html" , # noqa E501
1660- f"{ tu } /{ sm } /plot_dipole_orientations.html" : f"{ tu } /{ nv } /35_dipole_orientations.html" , # noqa E501
1661- f"{ tu } /{ sm } /plot_mne_solutions.html" : f"{ tu } /{ nv } /40_mne_fixed_free.html" ,
1662- f"{ tu } /{ sm } /plot_beamformer_lcmv.html" : f"{ tu } /{ nv } /50_beamformer_lcmv.html" ,
1663- f"{ tu } /{ sm } /plot_visualize_stc.html" : f"{ tu } /{ nv } /60_visualize_stc.html" ,
1664- f"{ tu } /{ sm } /plot_eeg_mri_coords.html" : f"{ tu } /{ nv } /70_eeg_mri_coords.html" ,
1665- f"{ tu } /{ sd } /plot_brainstorm_phantom_elekta.html" : f"{ tu } /{ nv } /80_brainstorm_phantom_elekta.html" , # noqa E501
1666- f"{ tu } /{ sd } /plot_brainstorm_phantom_ctf.html" : f"{ tu } /{ nv } /85_brainstorm_phantom_ctf.html" , # noqa E501
1667- f"{ tu } /{ sd } /plot_phantom_4DBTi.html" : f"{ tu } /{ nv } /90_phantom_4DBTi.html" ,
1668- f"{ tu } /{ sd } /plot_brainstorm_auditory.html" : f"{ tu } /io/60_ctf_bst_auditory.html" ,
1669- f"{ tu } /{ sd } /plot_sleep.html" : f"{ tu } /clinical/60_sleep.html" ,
1670- f"{ tu } /{ di } /plot_background_filtering.html" : f"{ tu } /{ pr } /25_background_filtering.html" , # noqa E501
1671- f"{ tu } /{ di } /plot_background_statistics.html" : f"{ tu } /{ sn } /10_background_stats.html" ,
1672- f"{ tu } /{ sn } /plot_stats_cluster_erp.html" : f"{ tu } /{ sn } /20_erp_stats.html" ,
1673- f"{ tu } /{ sn } /plot_stats_cluster_1samp_test_time_frequency.html" : f"{ tu } /{ sn } /40_cluster_1samp_time_freq.html" , # noqa E501
1674- f"{ tu } /{ sn } /plot_stats_cluster_time_frequency.html" : f"{ tu } /{ sn } /50_cluster_between_time_freq.html" , # noqa E501
1675- f"{ tu } /{ sn } /plot_stats_spatio_temporal_cluster_sensors.html" : f"{ tu } /{ sn } /75_cluster_ftest_spatiotemporal.html" , # noqa E501
1676- f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal.html" : f"{ tu } /{ sr } /20_cluster_1samp_spatiotemporal.html" , # noqa E501
1677- f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal_2samp.html" : f"{ tu } /{ sr } /30_cluster_ftest_spatiotemporal.html" , # noqa E501
1678- f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal_repeated_measures_anova.html" : f"{ tu } /{ sr } /60_cluster_rmANOVA_spatiotemporal.html" , # noqa E501
1679- f"{ tu } /{ sr } /plot_stats_cluster_time_frequency_repeated_measures_anova.html" : f"{ tu } /{ sn } /70_cluster_rmANOVA_time_freq.html" , # noqa E501
1680- f"{ tu } /{ tf } /plot_sensors_time_frequency.html" : f"{ tu } /{ tf } /20_sensors_time_frequency.html" , # noqa E501
1681- f"{ tu } /{ tf } /plot_ssvep.html" : f"{ tu } /{ tf } /50_ssvep.html" ,
1682- f"{ tu } /{ si } /plot_creating_data_structures.html" : f"{ tu } /{ si } /10_array_objs.html" ,
1683- f"{ tu } /{ si } /plot_point_spread.html" : f"{ tu } /{ si } /70_point_spread.html" ,
1684- f"{ tu } /{ si } /plot_dics.html" : f"{ tu } /{ si } /80_dics.html" ,
1685- f"{ tu } /{ tf } /plot_eyetracking.html" : f"{ tu } /{ pr } /90_eyetracking_data.html" ,
1686- f"{ ex } /{ co } /mne_inverse_label_connectivity.html" : f"{ mne_conn } /{ ex } /mne_inverse_label_connectivity.html" , # noqa E501
1687- f"{ ex } /{ co } /cwt_sensor_connectivity.html" : f"{ mne_conn } /{ ex } /cwt_sensor_connectivity.html" , # noqa E501
1688- f"{ ex } /{ co } /mixed_source_space_connectivity.html" : f"{ mne_conn } /{ ex } /mixed_source_space_connectivity.html" , # noqa E501
1689- f"{ ex } /{ co } /mne_inverse_coherence_epochs.html" : f"{ mne_conn } /{ ex } /mne_inverse_coherence_epochs.html" , # noqa E501
1690- f"{ ex } /{ co } /mne_inverse_connectivity_spectrum.html" : f"{ mne_conn } /{ ex } /mne_inverse_connectivity_spectrum.html" , # noqa E501
1691- f"{ ex } /{ co } /mne_inverse_envelope_correlation_volume.html" : f"{ mne_conn } /{ ex } /mne_inverse_envelope_correlation_volume.html" , # noqa E501
1692- f"{ ex } /{ co } /mne_inverse_envelope_correlation.html" : f"{ mne_conn } /{ ex } /mne_inverse_envelope_correlation.html" , # noqa E501
1693- f"{ ex } /{ co } /mne_inverse_psi_visual.html" : f"{ mne_conn } /{ ex } /mne_inverse_psi_visual.html" , # noqa E501
1694- f"{ ex } /{ co } /sensor_connectivity.html" : f"{ mne_conn } /{ ex } /sensor_connectivity.html" ,
1695- f"{ ex } /{ vi } /publication_figure.html" : f"{ tu } /{ vi } /10_publication_figure.html" ,
1696- f"{ ex } /{ vi } /sensor_noise_level.html" : f"{ tu } /{ pr } /50_artifact_correction_ssp.html" ,
1640+ "install/contributing" : "development/contributing" ,
1641+ "overview/cite" : "documentation/cite" ,
1642+ "overview/get_help" : "help/index" ,
1643+ "overview/roadmap" : "development/roadmap" ,
1644+ "whats_new" : "development/whats_new" ,
1645+ f"{ tu } /evoked/plot_eeg_erp" : f"{ tu } /evoked/30_eeg_erp" ,
1646+ f"{ tu } /evoked/plot_whitened" : f"{ tu } /evoked/40_whitened" ,
1647+ f"{ tu } /misc/plot_modifying_data_inplace" : f"{ tu } /intro/15_inplace" ,
1648+ f"{ tu } /misc/plot_report" : f"{ tu } /intro/70_report" ,
1649+ f"{ tu } /misc/plot_seeg" : f"{ tu } /clinical/20_seeg" ,
1650+ f"{ tu } /misc/plot_ecog" : f"{ tu } /clinical/30_ecog" ,
1651+ f"{ tu } /{ ml } /plot_receptive_field" : f"{ tu } /{ ml } /30_strf" ,
1652+ f"{ tu } /{ ml } /plot_sensors_decoding" : f"{ tu } /{ ml } /50_decoding" ,
1653+ f"{ tu } /{ sm } /plot_background_freesurfer" : f"{ tu } /{ fw } /10_background_freesurfer" ,
1654+ f"{ tu } /{ sm } /plot_source_alignment" : f"{ tu } /{ fw } /20_source_alignment" ,
1655+ f"{ tu } /{ sm } /plot_forward" : f"{ tu } /{ fw } /30_forward" ,
1656+ f"{ tu } /{ sm } /plot_eeg_no_mri" : f"{ tu } /{ fw } /35_eeg_no_mri" ,
1657+ f"{ tu } /{ sm } /plot_background_freesurfer_mne" : f"{ tu } /{ fw } /50_background_freesurfer_mne" , # noqa E501
1658+ f"{ tu } /{ sm } /plot_fix_bem_in_blender" : f"{ tu } /{ fw } /80_fix_bem_in_blender" ,
1659+ f"{ tu } /{ sm } /plot_compute_covariance" : f"{ tu } /{ fw } /90_compute_covariance" ,
1660+ f"{ tu } /{ sm } /plot_object_source_estimate" : f"{ tu } /{ nv } /10_stc_class" ,
1661+ f"{ tu } /{ sm } /plot_dipole_fit" : f"{ tu } /{ nv } /20_dipole_fit" ,
1662+ f"{ tu } /{ sm } /plot_mne_dspm_source_localization" : f"{ tu } /{ nv } /30_mne_dspm_loreta" ,
1663+ f"{ tu } /{ sm } /plot_dipole_orientations" : f"{ tu } /{ nv } /35_dipole_orientations" ,
1664+ f"{ tu } /{ sm } /plot_mne_solutions" : f"{ tu } /{ nv } /40_mne_fixed_free" ,
1665+ f"{ tu } /{ sm } /plot_beamformer_lcmv" : f"{ tu } /{ nv } /50_beamformer_lcmv" ,
1666+ f"{ tu } /{ sm } /plot_visualize_stc" : f"{ tu } /{ nv } /60_visualize_stc" ,
1667+ f"{ tu } /{ sm } /plot_eeg_mri_coords" : f"{ tu } /{ nv } /70_eeg_mri_coords" ,
1668+ f"{ tu } /{ sd } /plot_brainstorm_phantom_elekta" : f"{ tu } /{ nv } /80_brainstorm_phantom_elekta" , # noqa E501
1669+ f"{ tu } /{ sd } /plot_brainstorm_phantom_ctf" : f"{ tu } /{ nv } /85_brainstorm_phantom_ctf" ,
1670+ f"{ tu } /{ sd } /plot_phantom_4DBTi" : f"{ tu } /{ nv } /90_phantom_4DBTi" ,
1671+ f"{ tu } /{ sd } /plot_brainstorm_auditory" : f"{ tu } /io/60_ctf_bst_auditory" ,
1672+ f"{ tu } /{ sd } /plot_sleep" : f"{ tu } /clinical/60_sleep" ,
1673+ f"{ tu } /{ di } /plot_background_filtering" : f"{ tu } /{ pr } /25_background_filtering" ,
1674+ f"{ tu } /{ di } /plot_background_statistics" : f"{ tu } /{ sn } /10_background_stats" ,
1675+ f"{ tu } /{ sn } /plot_stats_cluster_erp" : f"{ tu } /{ sn } /20_erp_stats" ,
1676+ f"{ tu } /{ sn } /plot_stats_cluster_1samp_test_time_frequency" : f"{ tu } /{ sn } /40_cluster_1samp_time_freq" , # noqa E501
1677+ f"{ tu } /{ sn } /plot_stats_cluster_time_frequency" : f"{ tu } /{ sn } /50_cluster_between_time_freq" , # noqa E501
1678+ f"{ tu } /{ sn } /plot_stats_spatio_temporal_cluster_sensors" : f"{ tu } /{ sn } /75_cluster_ftest_spatiotemporal" , # noqa E501
1679+ f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal" : f"{ tu } /{ sr } /20_cluster_1samp_spatiotemporal" , # noqa E501
1680+ f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal_2samp" : f"{ tu } /{ sr } /30_cluster_ftest_spatiotemporal" , # noqa E501
1681+ f"{ tu } /{ sr } /plot_stats_cluster_spatio_temporal_repeated_measures_anova" : f"{ tu } /{ sr } /60_cluster_rmANOVA_spatiotemporal" , # noqa E501
1682+ f"{ tu } /{ sr } /plot_stats_cluster_time_frequency_repeated_measures_anova" : f"{ tu } /{ sn } /70_cluster_rmANOVA_time_freq" , # noqa E501
1683+ f"{ tu } /{ tf } /plot_sensors_time_frequency" : f"{ tu } /{ tf } /20_sensors_time_frequency" ,
1684+ f"{ tu } /{ tf } /plot_ssvep" : f"{ tu } /{ tf } /50_ssvep" ,
1685+ f"{ tu } /{ si } /plot_creating_data_structures" : f"{ tu } /{ si } /10_array_objs" ,
1686+ f"{ tu } /{ si } /plot_point_spread" : f"{ tu } /{ si } /70_point_spread" ,
1687+ f"{ tu } /{ si } /plot_dics" : f"{ tu } /{ si } /80_dics" ,
1688+ f"{ tu } /{ tf } /plot_eyetracking" : f"{ tu } /{ pr } /90_eyetracking_data" ,
1689+ f"{ ex } /{ co } /mne_inverse_label_connectivity" : f"{ mne_conn } /{ ex } /mne_inverse_label_connectivity" , # noqa E501
1690+ f"{ ex } /{ co } /cwt_sensor_connectivity" : f"{ mne_conn } /{ ex } /cwt_sensor_connectivity" ,
1691+ f"{ ex } /{ co } /mixed_source_space_connectivity" : f"{ mne_conn } /{ ex } /mixed_source_space_connectivity" , # noqa E501
1692+ f"{ ex } /{ co } /mne_inverse_coherence_epochs" : f"{ mne_conn } /{ ex } /mne_inverse_coherence_epochs" , # noqa E501
1693+ f"{ ex } /{ co } /mne_inverse_connectivity_spectrum" : f"{ mne_conn } /{ ex } /mne_inverse_connectivity_spectrum" , # noqa E501
1694+ f"{ ex } /{ co } /mne_inverse_envelope_correlation_volume" : f"{ mne_conn } /{ ex } /mne_inverse_envelope_correlation_volume" , # noqa E501
1695+ f"{ ex } /{ co } /mne_inverse_envelope_correlation" : f"{ mne_conn } /{ ex } /mne_inverse_envelope_correlation" , # noqa E501
1696+ f"{ ex } /{ co } /mne_inverse_psi_visual" : f"{ mne_conn } /{ ex } /mne_inverse_psi_visual" ,
1697+ f"{ ex } /{ co } /sensor_connectivity" : f"{ mne_conn } /{ ex } /sensor_connectivity" ,
1698+ f"{ ex } /{ vi } /publication_figure" : f"{ tu } /{ vi } /10_publication_figure" ,
1699+ f"{ ex } /{ vi } /sensor_noise_level" : f"{ tu } /{ pr } /50_artifact_correction_ssp" ,
16971700}
16981701
1699-
1700- def check_existing_redirect (path ):
1701- """Make sure existing HTML files are redirects, before overwriting."""
1702- if os .path .isfile (path ):
1703- with open (path , "r" ) as fid :
1704- for _ in range (8 ):
1705- next (fid )
1706- line = fid .readline ()
1707- assert "Page Redirection" in line , line
1708-
1709-
1710- def make_redirects (app , exception ):
1711- """Make HTML redirects."""
1712- # https://www.sphinx-doc.org/en/master/extdev/appapi.html
1713- # Adapted from sphinxcontrib/redirects (BSD-2-Clause)
1714- if not (
1715- isinstance (app .builder , sphinx .builders .html .StandaloneHTMLBuilder )
1716- and exception is None
1717- ):
1718- return
1719- TEMPLATE = """\
1702+ # Adapted from sphinxcontrib/redirects (BSD-2-Clause)
1703+ REDIRECT_TEMPLATE = """\
17201704 <!DOCTYPE HTML>
17211705<html lang="en-US">
17221706 <head>
@@ -1730,66 +1714,104 @@ def make_redirects(app, exception):
17301714 <body>
17311715 If you are not redirected automatically, follow this <a href='{to}'>link</a>.
17321716 </body>
1733- </html>""" # noqa: E501
1734- sphinx_gallery_conf = app .config ["sphinx_gallery_conf" ]
1735- for src_dir , out_dir in zip (
1736- sphinx_gallery_conf ["examples_dirs" ], sphinx_gallery_conf ["gallery_dirs" ]
1737- ):
1738- root = os .path .abspath (os .path .join (app .srcdir , src_dir ))
1717+ </html>"""
1718+
1719+
1720+ def check_existing_redirect (path ):
1721+ """Make sure existing HTML files are redirects, before overwriting."""
1722+ if path .is_file ():
1723+ with open (path , "r" ) as fid :
1724+ for _ in range (8 ):
1725+ next (fid )
1726+ line = fid .readline ()
1727+ if "Page Redirection" not in line :
1728+ raise RuntimeError (
1729+ "Attempted overwrite of HTML file with a redirect, where the "
1730+ "original file was not already a redirect."
1731+ )
1732+
1733+
1734+ def _check_valid_builder (app , exception ):
1735+ valid_builder = isinstance (app .builder , sphinx .builders .html .StandaloneHTMLBuilder )
1736+ return valid_builder and exception is None
1737+
1738+
1739+ def make_gallery_redirects (app , exception ):
1740+ """Make HTML redirects for our sphinx gallery pages."""
1741+ if not _check_valid_builder (app , exception ):
1742+ return
1743+ sg_conf = app .config ["sphinx_gallery_conf" ]
1744+ for src_dir , out_dir in zip (sg_conf ["examples_dirs" ], sg_conf ["gallery_dirs" ]):
1745+ root = (Path (app .srcdir ) / src_dir ).resolve ()
17391746 fnames = [
1740- os .path .join (os .path .relpath (dirpath , root ), fname )
1741- for dirpath , _ , fnames in os .walk (root )
1742- for fname in fnames
1743- if fname in needed_plot_redirects
1747+ pyfile .relative_to (root )
1748+ for pyfile in root .rglob (r"**/*.py" )
1749+ if pyfile .name in needed_plot_redirects
17441750 ]
17451751 # plot_ redirects
17461752 for fname in fnames :
1747- dirname = os . path . join (app .outdir , out_dir , os . path . dirname ( fname ))
1748- to_fname = os . path . splitext ( os . path . basename ( fname ))[ 0 ] + ".html"
1753+ dirname = Path (app .outdir ) / out_dir / fname . parent
1754+ to_fname = fname . with_suffix ( ".html" ). name
17491755 fr_fname = f"plot_{ to_fname } "
1750- to_path = os . path . join ( dirname , to_fname )
1751- fr_path = os . path . join ( dirname , fr_fname )
1752- assert os . path . isfile ( to_path ), (fname , to_path )
1756+ to_path = dirname / to_fname
1757+ fr_path = dirname / fr_fname
1758+ assert to_path . is_file ( ), (fname , to_path )
17531759 with open (fr_path , "w" ) as fid :
1754- fid .write (TEMPLATE .format (to = to_fname ))
1760+ fid .write (REDIRECT_TEMPLATE .format (to = to_fname ))
17551761 sphinx_logger .info (
17561762 f"Added { len (fnames ):3d} HTML plot_* redirects for { out_dir } "
17571763 )
1758- # API redirects
1764+
1765+
1766+ def make_api_redirects (app , exception ):
1767+ """Make HTML redirects for our API pages."""
1768+ if not _check_valid_builder (app , exception ):
1769+ return
1770+
17591771 for page in api_redirects :
17601772 fname = f"{ page } .html"
1761- fr_path = os . path . join (app .outdir , fname )
1762- to_path = os . path . join (app .outdir , "api" , fname )
1773+ fr_path = Path (app .outdir ) / fname
1774+ to_path = Path (app .outdir ) / "api" / fname
17631775 # allow overwrite if existing file is just a redirect
17641776 check_existing_redirect (fr_path )
17651777 with open (fr_path , "w" ) as fid :
1766- fid .write (TEMPLATE .format (to = to_path ))
1778+ fid .write (REDIRECT_TEMPLATE .format (to = to_path ))
17671779 sphinx_logger .info (f"Added { len (api_redirects ):3d} HTML API redirects" )
1768- # custom redirects
1769- for fr , to in custom_redirects .items ():
1770- if not to .startswith ("http" ):
1771- assert os .path .isfile (os .path .join (app .outdir , to )), to
1772- # handle links to sibling folders
1773- path_parts = to .split ("/" )
1774- if tu in path_parts :
1775- path_parts = [".." ] + path_parts [(path_parts .index (tu ) + 1 ) :]
1776- to = os .path .join (* path_parts )
1777- assert to .endswith ("html" ), to
1778- fr_path = os .path .join (app .outdir , fr )
1779- assert fr_path .endswith ("html" ), fr_path
1780- # allow overwrite if existing file is just a redirect
1780+
1781+
1782+ def make_custom_redirects (app , exception ):
1783+ """Make HTML redirects for miscellaneous pages."""
1784+ if not _check_valid_builder (app , exception ):
1785+ return
1786+
1787+ for _fr , _to in custom_redirects .items ():
1788+ fr = f"{ _fr } .html"
1789+ to = f"{ _to } .html"
1790+ fr_path = Path (app .outdir ) / fr
17811791 check_existing_redirect (fr_path )
1782- # handle folders that no longer exist
1783- if fr_path .split ("/" )[- 2 ] in (
1792+ if to .startswith ("http" ):
1793+ to_path = to
1794+ else :
1795+ to_path = Path (app .outdir ) / to
1796+ assert to_path .is_file (), to_path
1797+ # recreate folders that no longer exist
1798+ defunct_gallery_folders = (
17841799 "misc" ,
17851800 "discussions" ,
17861801 "source-modeling" ,
17871802 "sample-datasets" ,
17881803 "connectivity" ,
1804+ )
1805+ parts = fr_path .relative_to (Path (app .outdir )).parts
1806+ if (
1807+ len (parts ) > 1 # whats_new violates this
1808+ and parts [1 ] in defunct_gallery_folders
1809+ and not fr_path .parent .exists ()
17891810 ):
1790- os .makedirs (os .path .dirname (fr_path ), exist_ok = True )
1811+ os .makedirs (fr_path .parent , exist_ok = True )
1812+ # write the redirect
17911813 with open (fr_path , "w" ) as fid :
1792- fid .write (TEMPLATE .format (to = to ))
1814+ fid .write (REDIRECT_TEMPLATE .format (to = to_path ))
17931815 sphinx_logger .info (f"Added { len (custom_redirects ):3d} HTML custom redirects" )
17941816
17951817
@@ -1818,5 +1840,7 @@ def setup(app):
18181840 app .connect ("autodoc-process-docstring" , append_attr_meth_examples )
18191841 report_scraper .app = app
18201842 app .connect ("builder-inited" , report_scraper .copyfiles )
1821- app .connect ("build-finished" , make_redirects )
1843+ app .connect ("build-finished" , make_gallery_redirects )
1844+ app .connect ("build-finished" , make_api_redirects )
1845+ app .connect ("build-finished" , make_custom_redirects )
18221846 app .connect ("build-finished" , make_version )
0 commit comments