@@ -237,6 +237,16 @@ def setup_instparser(instparser):
237237        "releaseargs" , nargs = argparse .REMAINDER , help = extraargs_help ("pytest" )
238238    )
239239
240+     patchreleaseparser  =  subparsers .add_parser (
241+         "update_patch_versions" ,
242+         help = "Updates version numbers during patch release, used by maintainers and CI" ,
243+     )
244+     patchreleaseparser .set_defaults (func = patch_release_args )
245+     patchreleaseparser .add_argument ("--stable_version" , required = True )
246+     patchreleaseparser .add_argument ("--unstable_version" , required = True )
247+     patchreleaseparser .add_argument ("--stable_version_prev" , required = True )
248+     patchreleaseparser .add_argument ("--unstable_version_prev" , required = True )
249+ 
240250    fmtparser  =  subparsers .add_parser (
241251        "format" ,
242252        help = "Formats all source code with black and isort." ,
@@ -655,6 +665,24 @@ def update_dependencies(targets, version, packages):
655665        )
656666
657667
668+ def  update_patch_dependencies (targets , version , prev_version , packages ):
669+     print ("updating patch dependencies" )
670+     # PEP 508 allowed specifier operators 
671+     operators  =  ["==" , "!=" , "<=" , ">=" , "<" , ">" , "===" , "~=" , "=" ]
672+     operators_pattern  =  "|" .join (re .escape (op ) for  op  in  operators )
673+ 
674+     for  pkg  in  packages :
675+         search  =  rf"({ basename (pkg )}  [^,]*?)(\s?({ operators_pattern }  )\s?)(.*{ prev_version }  )" 
676+         replace  =  r"\g<1>\g<2>"  +  version 
677+         print (f"{ search = } \t { replace = } \t { pkg = }  " )
678+         update_files (
679+             targets ,
680+             "pyproject.toml" ,
681+             search ,
682+             replace ,
683+         )
684+ 
685+ 
658686def  update_files (targets , filename , search , replace ):
659687    errors  =  False 
660688    for  target  in  targets :
@@ -707,6 +735,32 @@ def release_args(args):
707735    update_changelogs ("-" .join (updated_versions ))
708736
709737
738+ def  patch_release_args (args ):
739+     print ("preparing patch release" )
740+ 
741+     rootpath  =  find_projectroot ()
742+     targets  =  list (find_targets_unordered (rootpath ))
743+     cfg  =  ConfigParser ()
744+     cfg .read (str (find_projectroot () /  "eachdist.ini" ))
745+     # stable 
746+     mcfg  =  cfg ["stable" ]
747+     packages  =  mcfg ["packages" ].split ()
748+     print (f"update stable packages to { args .stable_version }  " )
749+     update_patch_dependencies (
750+         targets , args .stable_version , args .stable_version_prev , packages 
751+     )
752+     update_version_files (targets , args .stable_version , packages )
753+ 
754+     # prerelease 
755+     mcfg  =  cfg ["prerelease" ]
756+     packages  =  mcfg ["packages" ].split ()
757+     print (f"update prerelease packages to { args .unstable_version }  " )
758+     update_patch_dependencies (
759+         targets , args .unstable_version , args .unstable_version_prev , packages 
760+     )
761+     update_version_files (targets , args .unstable_version , packages )
762+ 
763+ 
710764def  test_args (args ):
711765    clean_remainder_args (args .pytestargs )
712766    execute_args (
0 commit comments