5858import  sys 
5959from  bisect  import  bisect_left  as  bisect 
6060from  contextlib  import  contextmanager , suppress 
61- from  functools  import  total_ordering 
6261from  pathlib  import  Path 
6362from  string  import  Template 
6463from  time  import  perf_counter , sleep 
@@ -103,11 +102,23 @@ def __reversed__(self) -> Iterator[Version]:
103102
104103    @classmethod  
105104    def  from_json (cls , data : dict ) ->  Versions :
106-         versions  =  sorted (
107-             [Version .from_json (name , release ) for  name , release  in  data .items ()],
108-             key = Version .as_tuple ,
109-         )
110-         return  cls (versions )
105+         """Load versions from the devguide's JSON representation.""" 
106+         permitted  =  ", " .join (sorted (Version .STATUSES  |  Version .SYNONYMS .keys ()))
107+ 
108+         versions  =  []
109+         for  name , release  in  data .items ():
110+             branch  =  release ["branch" ]
111+             status  =  release ["status" ]
112+             status  =  Version .SYNONYMS .get (status , status )
113+             if  status  not  in Version .STATUSES :
114+                 msg  =  (
115+                     f"Saw invalid version status { status !r}  
116+                     f"expected to be one of { permitted }  
117+                 )
118+                 raise  ValueError (msg )
119+             versions .append (Version (name = name , branch_or_tag = branch , status = status ))
120+ 
121+         return  cls (sorted (versions , key = Version .as_tuple ))
111122
112123    def  filter (self , branches : Sequence [str ] =  ()) ->  Sequence [Version ]:
113124        """Filter the given versions. 
@@ -143,10 +154,14 @@ def setup_indexsidebar(self, current: Version, dest_path: Path) -> None:
143154        dest_path .write_text (rendered_template , encoding = "UTF-8" )
144155
145156
146- @total_ordering  
157+ @dataclasses . dataclass ( frozen = True ,  kw_only = True ,  slots = True )  
147158class  Version :
148159    """Represents a CPython version and its documentation build dependencies.""" 
149160
161+     name : str 
162+     branch_or_tag : str  |  None 
163+     status : str 
164+ 
150165    STATUSES  =  {"EOL" , "security-fixes" , "stable" , "pre-release" , "in development" }
151166
152167    # Those synonyms map branch status vocabulary found in the devguide 
@@ -159,19 +174,6 @@ class Version:
159174        "prerelease" : "pre-release" ,
160175    }
161176
162-     def  __init__ (
163-         self , name : str , * , status : str , branch_or_tag : str  |  None  =  None 
164-     ) ->  None :
165-         status  =  self .SYNONYMS .get (status , status )
166-         if  status  not  in self .STATUSES :
167-             raise  ValueError (
168-                 "Version status expected to be one of: " 
169-                 f"{ ', ' .join (self .STATUSES  |  set (self .SYNONYMS .keys ()))} { status !r}  
170-             )
171-         self .name  =  name 
172-         self .branch_or_tag  =  branch_or_tag 
173-         self .status  =  status 
174- 
175177    def  __repr__ (self ) ->  str :
176178        return  f"Version({ self .name }  
177179
@@ -181,11 +183,6 @@ def __eq__(self, other: Version) -> bool:
181183    def  __gt__ (self , other : Version ) ->  bool :
182184        return  self .as_tuple () >  other .as_tuple ()
183185
184-     @classmethod  
185-     def  from_json (cls , name : str , values : dict ) ->  Version :
186-         """Loads a version from devguide's json representation.""" 
187-         return  cls (name , status = values ["status" ], branch_or_tag = values ["branch" ])
188- 
189186    @property  
190187    def  requirements (self ) ->  list [str ]:
191188        """Generate the right requirements for this version. 
0 commit comments