50
50
51
51
TYPE_CHECKING = False
52
52
if TYPE_CHECKING :
53
- from collections .abc import Sequence
53
+ from collections .abc import Iterator , Sequence
54
54
from typing import Literal , TypeAlias
55
55
56
- Versions : TypeAlias = Sequence ["Version" ]
57
56
Languages : TypeAlias = Sequence ["Language" ]
58
57
59
58
try :
71
70
HERE = Path (__file__ ).resolve ().parent
72
71
73
72
73
+ @dataclass (frozen = True , slots = True )
74
+ class Versions :
75
+ _seq : Sequence [Version ]
76
+
77
+ def __iter__ (self ) -> Iterator [Version ]:
78
+ return iter (self ._seq )
79
+
80
+ def __reversed__ (self ) -> Iterator [Version ]:
81
+ return reversed (self ._seq )
82
+
83
+ @classmethod
84
+ def from_json (cls , data ) -> Versions :
85
+ versions = sorted (
86
+ [Version .from_json (name , release ) for name , release in data .items ()],
87
+ key = Version .as_tuple ,
88
+ )
89
+ return cls (versions )
90
+
91
+ def filter (self , branch : str = "" ) -> Sequence [Version ]:
92
+ """Filter the given versions.
93
+
94
+ If *branch* is given, only *versions* matching *branch* are returned.
95
+
96
+ Else all live versions are returned (this means no EOL and no
97
+ security-fixes branches).
98
+ """
99
+ if branch :
100
+ return [v for v in self if branch in (v .name , v .branch_or_tag )]
101
+ return [v for v in self if v .status not in {"EOL" , "security-fixes" }]
102
+
103
+ @property
104
+ def current_stable (self ) -> Version :
105
+ """Find the current stable CPython version."""
106
+ return max ((v for v in self if v .status == "stable" ), key = Version .as_tuple )
107
+
108
+ @property
109
+ def current_dev (self ) -> Version :
110
+ """Find the current CPython version in development."""
111
+ return max (self , key = Version .as_tuple )
112
+
113
+ def setup_indexsidebar (self , current : Version , dest_path : Path ) -> None :
114
+ """Build indexsidebar.html for Sphinx."""
115
+ template_path = HERE / "templates" / "indexsidebar.html"
116
+ template = jinja2 .Template (template_path .read_text (encoding = "UTF-8" ))
117
+ rendered_template = template .render (
118
+ current_version = current ,
119
+ versions = list (reversed (self )),
120
+ )
121
+ dest_path .write_text (rendered_template , encoding = "UTF-8" )
122
+
123
+
74
124
@total_ordering
75
125
class Version :
76
126
"""Represents a CPython version and its documentation build dependencies."""
@@ -101,6 +151,17 @@ def __init__(self, name, *, status, branch_or_tag=None):
101
151
def __repr__ (self ):
102
152
return f"Version({ self .name } )"
103
153
154
+ def __eq__ (self , other ):
155
+ return self .name == other .name
156
+
157
+ def __gt__ (self , other ):
158
+ return self .as_tuple () > other .as_tuple ()
159
+
160
+ @classmethod
161
+ def from_json (cls , name , values ):
162
+ """Loads a version from devguide's json representation."""
163
+ return cls (name , status = values ["status" ], branch_or_tag = values ["branch" ])
164
+
104
165
@property
105
166
def requirements (self ):
106
167
"""Generate the right requirements for this version.
@@ -144,29 +205,6 @@ def title(self):
144
205
"""The title of this version's doc, for the sidebar."""
145
206
return f"Python { self .name } ({ self .status } )"
146
207
147
- @staticmethod
148
- def filter (versions , branch = None ):
149
- """Filter the given versions.
150
-
151
- If *branch* is given, only *versions* matching *branch* are returned.
152
-
153
- Else all live versions are returned (this means no EOL and no
154
- security-fixes branches).
155
- """
156
- if branch :
157
- return [v for v in versions if branch in (v .name , v .branch_or_tag )]
158
- return [v for v in versions if v .status not in ("EOL" , "security-fixes" )]
159
-
160
- @staticmethod
161
- def current_stable (versions ):
162
- """Find the current stable CPython version."""
163
- return max ((v for v in versions if v .status == "stable" ), key = Version .as_tuple )
164
-
165
- @staticmethod
166
- def current_dev (versions ):
167
- """Find the current CPython version in development."""
168
- return max (versions , key = Version .as_tuple )
169
-
170
208
@property
171
209
def picker_label (self ):
172
210
"""Forge the label of a version picker."""
@@ -176,27 +214,6 @@ def picker_label(self):
176
214
return f"pre ({ self .name } )"
177
215
return self .name
178
216
179
- def setup_indexsidebar (self , versions : Versions , dest_path : Path ):
180
- """Build indexsidebar.html for Sphinx."""
181
- template_path = HERE / "templates" / "indexsidebar.html"
182
- template = jinja2 .Template (template_path .read_text (encoding = "UTF-8" ))
183
- rendered_template = template .render (
184
- current_version = self ,
185
- versions = versions [::- 1 ],
186
- )
187
- dest_path .write_text (rendered_template , encoding = "UTF-8" )
188
-
189
- @classmethod
190
- def from_json (cls , name , values ):
191
- """Loads a version from devguide's json representation."""
192
- return cls (name , status = values ["status" ], branch_or_tag = values ["branch" ])
193
-
194
- def __eq__ (self , other ):
195
- return self .name == other .name
196
-
197
- def __gt__ (self , other ):
198
- return self .as_tuple () > other .as_tuple ()
199
-
200
217
201
218
@dataclass (order = True , frozen = True , kw_only = True )
202
219
class Language :
@@ -619,8 +636,8 @@ def build(self):
619
636
+ (["" ] if sys .platform == "darwin" else [])
620
637
+ ["s/ *-A switchers=1//" , self .checkout / "Doc" / "Makefile" ]
621
638
)
622
- self .version .setup_indexsidebar (
623
- self .versions ,
639
+ self .versions .setup_indexsidebar (
640
+ self .version ,
624
641
self .checkout / "Doc" / "tools" / "templates" / "indexsidebar.html" ,
625
642
)
626
643
run_with_logging (
@@ -1013,7 +1030,7 @@ def build_docs(args) -> bool:
1013
1030
# This runs languages in config.toml order and versions newest first.
1014
1031
todo = [
1015
1032
(version , language )
1016
- for version in Version .filter (versions , args .branch )
1033
+ for version in versions .filter (args .branch )
1017
1034
for language in reversed (Language .filter (languages , args .languages ))
1018
1035
]
1019
1036
del args .branch
@@ -1081,9 +1098,7 @@ def parse_versions_from_devguide(http: urllib3.PoolManager) -> Versions:
1081
1098
"python/devguide/main/include/release-cycle.json" ,
1082
1099
timeout = 30 ,
1083
1100
).json ()
1084
- versions = [Version .from_json (name , release ) for name , release in releases .items ()]
1085
- versions .sort (key = Version .as_tuple )
1086
- return versions
1101
+ return Versions .from_json (releases )
1087
1102
1088
1103
1089
1104
def parse_languages_from_config () -> Languages :
@@ -1170,7 +1185,7 @@ def major_symlinks(
1170
1185
- /es/3/ → /es/3.9/
1171
1186
"""
1172
1187
logging .info ("Creating major version symlinks..." )
1173
- current_stable = Version .current_stable ( versions ) .name
1188
+ current_stable = versions .current_stable .name
1174
1189
for language in languages :
1175
1190
symlink (
1176
1191
www_root ,
@@ -1200,7 +1215,7 @@ def dev_symlink(
1200
1215
- /es/dev/ → /es/3.11/
1201
1216
"""
1202
1217
logging .info ("Creating development version symlinks..." )
1203
- current_dev = Version .current_dev ( versions ) .name
1218
+ current_dev = versions .current_dev .name
1204
1219
for language in languages :
1205
1220
symlink (
1206
1221
www_root ,
0 commit comments