44
55import hashlib
66from pathlib import Path
7+ from typing import TYPE_CHECKING
78
89import matplotlib
10+ import matplotlib .font_manager
911import matplotlib .image as mpimg
1012from matplotlib import pyplot as plt
1113from sphinx .util import logging
1214
15+ if TYPE_CHECKING :
16+ from typing import TypeAlias
17+
18+ from matplotlib .figure import Figure
19+ from matplotlib .text import Text
20+ from sphinx .application import Sphinx
21+
22+ PltObjects : TypeAlias = tuple [Figure , Text , Text , Text , Text ]
23+
1324matplotlib .use ("agg" )
1425
1526LOGGER = logging .getLogger (__name__ )
3849# They must be defined here otherwise Sphinx errors when trying to pickle them.
3950# They are dependent on the `multiple` variable defined when the figure is created.
4051# Because they are depending on the figure size and renderer used to generate them.
41- def _set_page_title_line_width ():
52+ def _set_page_title_line_width () -> int :
4253 return 825
4354
4455
45- def _set_description_line_width ():
56+ def _set_description_line_width () -> int :
4657 return 1000
4758
4859
4960def create_social_card (
50- app , config_social , site_name , page_title , description , url_text , page_path
51- ):
61+ app : Sphinx ,
62+ config_social : dict [str , bool | str ],
63+ site_name : str ,
64+ page_title : str ,
65+ description : str ,
66+ url_text : str ,
67+ page_path : str ,
68+ ) -> Path :
5269 """Create a social preview card according to page metadata.
5370
5471 This uses page metadata and calls a render function to generate the image.
@@ -75,22 +92,20 @@ def create_social_card(
7592 # This is because we hash the values of the text + images in the social card.
7693 # If the hash doesn't change, it means the output should be the same.
7794 if path_image .exists ():
78- return
95+ return path_images_relative / filename_image
7996
8097 # These kwargs are used to generate the base figure image
81- kwargs_fig = {}
98+ kwargs_fig : dict [ str , str | Path | None ] = {}
8299
83100 # Large image to the top right
84- if config_social .get ("image" ):
85- kwargs_fig ["image" ] = Path (app .builder .srcdir ) / config_social . get ( "image" )
101+ if cs_image := config_social .get ("image" ):
102+ kwargs_fig ["image" ] = Path (app .builder .srcdir ) / cs_image
86103 elif app .config .html_logo :
87104 kwargs_fig ["image" ] = Path (app .builder .srcdir ) / app .config .html_logo
88105
89106 # Mini image to the bottom right
90- if config_social .get ("image_mini" ):
91- kwargs_fig ["image_mini" ] = Path (app .builder .srcdir ) / config_social .get (
92- "image_mini"
93- )
107+ if cs_image_mini := config_social .get ("image_mini" ):
108+ kwargs_fig ["image_mini" ] = Path (app .builder .srcdir ) / cs_image_mini
94109 else :
95110 kwargs_fig ["image_mini" ] = (
96111 Path (__file__ ).parent / "_static/sphinx-logo-shadow.png"
@@ -119,18 +134,19 @@ def create_social_card(
119134 kwargs_fig [config ] = config_social .get (config )
120135
121136 # Generate the image and store the matplotlib objects so that we can re-use them
122- if hasattr ( app . env , "ogp_social_card_plt_objects" ) :
137+ try :
123138 plt_objects = app .env .ogp_social_card_plt_objects
124- else :
125- plt_objects = None
139+ except AttributeError :
140+ # If objects is None it means this is the first time plotting.
141+ # Create the figure objects and return them so that we re-use them later.
142+ plt_objects = create_social_card_objects (** kwargs_fig )
126143 plt_objects = render_social_card (
127144 path_image ,
128145 site_name ,
129146 page_title ,
130147 description ,
131148 url_text ,
132149 plt_objects ,
133- kwargs_fig ,
134150 )
135151 app .env .ogp_social_card_plt_objects = plt_objects
136152
@@ -140,27 +156,15 @@ def create_social_card(
140156
141157
142158def render_social_card (
143- path ,
144- site_title = None ,
145- page_title = None ,
146- description = None ,
147- siteurl = None ,
148- plt_objects = None ,
149- kwargs_fig = None ,
150- ):
159+ path : Path ,
160+ site_title : str ,
161+ page_title : str ,
162+ description : str ,
163+ siteurl : str ,
164+ plt_objects : PltObjects ,
165+ ) -> PltObjects :
151166 """Render a social preview card with Matplotlib and write to disk."""
152- # If objects is None it means this is the first time plotting.
153- # Create the figure objects and return them so that we re-use them later.
154- if plt_objects is None :
155- (
156- fig ,
157- txt_site_title ,
158- txt_page_title ,
159- txt_description ,
160- txt_url ,
161- ) = create_social_card_objects (** kwargs_fig )
162- else :
163- fig , txt_site_title , txt_page_title , txt_description , txt_url = plt_objects
167+ fig , txt_site_title , txt_page_title , txt_description , txt_url = plt_objects
164168
165169 # Update the matplotlib text objects with new text from this page
166170 txt_site_title .set_text (site_title )
@@ -174,16 +178,16 @@ def render_social_card(
174178
175179
176180def create_social_card_objects (
177- image = None ,
178- image_mini = None ,
179- page_title_color = "#2f363d" ,
180- description_color = "#585e63" ,
181- site_title_color = "#585e63" ,
182- site_url_color = "#2f363d" ,
183- background_color = "white" ,
184- line_color = "#5A626B" ,
185- font = None ,
186- ):
181+ image : Path | None = None ,
182+ image_mini : Path | None = None ,
183+ page_title_color : str = "#2f363d" ,
184+ description_color : str = "#585e63" ,
185+ site_title_color : str = "#585e63" ,
186+ site_url_color : str = "#2f363d" ,
187+ background_color : str = "white" ,
188+ line_color : str = "#5A626B" ,
189+ font : str | None = None ,
190+ ) -> PltObjects :
187191 """Create the Matplotlib objects for the first time."""
188192 # If no font specified, load the Roboto Flex font as a fallback
189193 if font is None :
0 commit comments