2626""" 
2727from  __future__ import  annotations 
2828
29- import  os 
3029import  re 
3130from  collections  import  OrderedDict , defaultdict 
31+ from  dataclasses  import  dataclass 
3232from  datetime  import  date 
33- from  typing  import  TYPE_CHECKING , Callable , Iterable ,  cast 
33+ from  typing  import  TYPE_CHECKING , Callable , Iterable 
3434
3535from  jinja2  import  (
3636    BaseLoader ,
3737    ChoiceLoader ,
3838    Environment ,
3939    FileSystemLoader ,
40-     PackageLoader ,
4140    Template ,
4241)
4342
4443from  commitizen  import  out 
4544from  commitizen .bump  import  normalize_tag 
46- from  commitizen .defaults  import  encoding 
4745from  commitizen .exceptions  import  InvalidConfigurationError , NoCommitsFoundError 
4846from  commitizen .git  import  GitCommit , GitTag 
4947from  commitizen .version_schemes  import  (
5048    DEFAULT_SCHEME ,
5149    BaseVersion ,
5250    InvalidVersion ,
53-     Pep440 ,
5451)
5552
5653if  TYPE_CHECKING :
5754    from  commitizen .version_schemes  import  VersionScheme 
5855
59- DEFAULT_TEMPLATE  =  "CHANGELOG.md.j2" 
56+ 
57+ @dataclass  
58+ class  Metadata :
59+     """ 
60+     Metadata extracted from the changelog produced by a plugin 
61+     """ 
62+ 
63+     unreleased_start : int  |  None  =  None 
64+     unreleased_end : int  |  None  =  None 
65+     latest_version : str  |  None  =  None 
66+     latest_version_position : int  |  None  =  None 
6067
6168
6269def  get_commit_tag (commit : GitCommit , tags : list [GitTag ]) ->  GitTag  |  None :
@@ -196,100 +203,31 @@ def order_changelog_tree(tree: Iterable, change_type_order: list[str]) -> Iterab
196203    return  sorted_tree 
197204
198205
199- def  get_changelog_template (
200-     loader : BaseLoader  |  None  =  None , template : str  |  None  =  None 
201- ) ->  Template :
206+ def  get_changelog_template (loader : BaseLoader , template : str ) ->  Template :
202207    loader  =  ChoiceLoader (
203208        [
204209            FileSystemLoader ("." ),
205-             loader   or   PackageLoader ( "commitizen" ,  "templates" ) ,
210+             loader ,
206211        ]
207212    )
208213    env  =  Environment (loader = loader , trim_blocks = True )
209-     return  env .get_template (template   or   DEFAULT_TEMPLATE )
214+     return  env .get_template (template )
210215
211216
212217def  render_changelog (
213218    tree : Iterable ,
214-     loader : BaseLoader   |   None   =   None ,
215-     template : str   |   None   =   None ,
219+     loader : BaseLoader ,
220+     template : str ,
216221    ** kwargs ,
217222) ->  str :
218-     jinja_template  =  get_changelog_template (loader , template   or   DEFAULT_TEMPLATE )
223+     jinja_template  =  get_changelog_template (loader , template )
219224    changelog : str  =  jinja_template .render (tree = tree , ** kwargs )
220225    return  changelog 
221226
222227
223- def  parse_version_from_markdown (
224-     value : str , scheme : VersionScheme  =  Pep440 
225- ) ->  str  |  None :
226-     if  not  value .startswith ("#" ):
227-         return  None 
228-     m  =  scheme .parser .search (value )
229-     if  not  m :
230-         return  None 
231-     return  cast (str , m .group ("version" ))
232- 
233- 
234- def  parse_title_type_of_line (value : str ) ->  str  |  None :
235-     md_title_parser  =  r"^(?P<title>#+)" 
236-     m  =  re .search (md_title_parser , value )
237-     if  not  m :
238-         return  None 
239-     return  m .groupdict ().get ("title" )
240- 
241- 
242- def  get_metadata (
243-     filepath : str , scheme : VersionScheme  =  Pep440 , encoding : str  =  encoding 
244- ) ->  dict :
245-     unreleased_start : int  |  None  =  None 
246-     unreleased_end : int  |  None  =  None 
247-     unreleased_title : str  |  None  =  None 
248-     latest_version : str  |  None  =  None 
249-     latest_version_position : int  |  None  =  None 
250-     if  not  os .path .isfile (filepath ):
251-         return  {
252-             "unreleased_start" : None ,
253-             "unreleased_end" : None ,
254-             "latest_version" : None ,
255-             "latest_version_position" : None ,
256-         }
257- 
258-     with  open (filepath , encoding = encoding ) as  changelog_file :
259-         for  index , line  in  enumerate (changelog_file ):
260-             line  =  line .strip ().lower ()
261- 
262-             unreleased : str  |  None  =  None 
263-             if  "unreleased"  in  line :
264-                 unreleased  =  parse_title_type_of_line (line )
265-             # Try to find beginning and end lines of the unreleased block 
266-             if  unreleased :
267-                 unreleased_start  =  index 
268-                 unreleased_title  =  unreleased 
269-                 continue 
270-             elif  (
271-                 isinstance (unreleased_title , str )
272-                 and  parse_title_type_of_line (line ) ==  unreleased_title 
273-             ):
274-                 unreleased_end  =  index 
275- 
276-             # Try to find the latest release done 
277-             version  =  parse_version_from_markdown (line , scheme )
278-             if  version :
279-                 latest_version  =  version 
280-                 latest_version_position  =  index 
281-                 break   # there's no need for more info 
282-         if  unreleased_start  is  not None  and  unreleased_end  is  None :
283-             unreleased_end  =  index 
284-     return  {
285-         "unreleased_start" : unreleased_start ,
286-         "unreleased_end" : unreleased_end ,
287-         "latest_version" : latest_version ,
288-         "latest_version_position" : latest_version_position ,
289-     }
290- 
291- 
292- def  incremental_build (new_content : str , lines : list [str ], metadata : dict ) ->  list [str ]:
228+ def  incremental_build (
229+     new_content : str , lines : list [str ], metadata : Metadata 
230+ ) ->  list [str ]:
293231    """Takes the original lines and updates with new_content. 
294232
295233    The metadata governs how to remove the old unreleased section and where to place the 
@@ -303,9 +241,9 @@ def incremental_build(new_content: str, lines: list[str], metadata: dict) -> lis
303241    Returns: 
304242        Updated lines 
305243    """ 
306-     unreleased_start  =  metadata .get ( " unreleased_start" ) 
307-     unreleased_end  =  metadata .get ( " unreleased_end" ) 
308-     latest_version_position  =  metadata .get ( " latest_version_position" ) 
244+     unreleased_start  =  metadata .unreleased_start 
245+     unreleased_end  =  metadata .unreleased_end 
246+     latest_version_position  =  metadata .latest_version_position 
309247    skip  =  False 
310248    output_lines : list [str ] =  []
311249    for  index , line  in  enumerate (lines ):
0 commit comments