4
4
5
5
import hashlib
6
6
from pathlib import Path
7
+ from typing import TYPE_CHECKING
7
8
8
9
import matplotlib
10
+ import matplotlib .font_manager
9
11
import matplotlib .image as mpimg
10
12
from matplotlib import pyplot as plt
11
13
from sphinx .util import logging
12
14
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
+
13
24
matplotlib .use ("agg" )
14
25
15
26
LOGGER = logging .getLogger (__name__ )
38
49
# They must be defined here otherwise Sphinx errors when trying to pickle them.
39
50
# They are dependent on the `multiple` variable defined when the figure is created.
40
51
# 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 :
42
53
return 825
43
54
44
55
45
- def _set_description_line_width ():
56
+ def _set_description_line_width () -> int :
46
57
return 1000
47
58
48
59
49
60
def 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 :
52
69
"""Create a social preview card according to page metadata.
53
70
54
71
This uses page metadata and calls a render function to generate the image.
@@ -75,22 +92,20 @@ def create_social_card(
75
92
# This is because we hash the values of the text + images in the social card.
76
93
# If the hash doesn't change, it means the output should be the same.
77
94
if path_image .exists ():
78
- return
95
+ return path_images_relative / filename_image
79
96
80
97
# These kwargs are used to generate the base figure image
81
- kwargs_fig = {}
98
+ kwargs_fig : dict [ str , str | Path | None ] = {}
82
99
83
100
# 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
86
103
elif app .config .html_logo :
87
104
kwargs_fig ["image" ] = Path (app .builder .srcdir ) / app .config .html_logo
88
105
89
106
# 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
94
109
else :
95
110
kwargs_fig ["image_mini" ] = (
96
111
Path (__file__ ).parent / "_static/sphinx-logo-shadow.png"
@@ -119,18 +134,19 @@ def create_social_card(
119
134
kwargs_fig [config ] = config_social .get (config )
120
135
121
136
# 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 :
123
138
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 )
126
143
plt_objects = render_social_card (
127
144
path_image ,
128
145
site_name ,
129
146
page_title ,
130
147
description ,
131
148
url_text ,
132
149
plt_objects ,
133
- kwargs_fig ,
134
150
)
135
151
app .env .ogp_social_card_plt_objects = plt_objects
136
152
@@ -140,27 +156,15 @@ def create_social_card(
140
156
141
157
142
158
def 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 :
151
166
"""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
164
168
165
169
# Update the matplotlib text objects with new text from this page
166
170
txt_site_title .set_text (site_title )
@@ -174,16 +178,16 @@ def render_social_card(
174
178
175
179
176
180
def 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 :
187
191
"""Create the Matplotlib objects for the first time."""
188
192
# If no font specified, load the Roboto Flex font as a fallback
189
193
if font is None :
0 commit comments