@@ -594,6 +594,32 @@ def _first_non_none(*args):
594594
595595 return None
596596
597+ def _key (self , release_key = ("z" ,)):
598+ """This function returns a tuple that can be used in 'sorted' calls.
599+
600+ This implements the PEP440 version sorting.
601+ """
602+ return (
603+ self .epoch ,
604+ self .release ,
605+ # PEP440 Within a pre-release, post-release or development release segment with
606+ # a shared prefix, ordering MUST be by the value of the numeric component.
607+ # PEP440 release ordering: .devN, aN, bN, rcN, <no suffix>, .postN
608+ # We choose to first match the pre-release, then post release, then dev and
609+ # then stable
610+ _first_non_none (self .pre , self .post , self .dev , release_key ),
611+ # PEP440 local versions go before post versions
612+ tuple ([(type (item ) == "int" , item ) for item in self .local or []]),
613+ # PEP440 - pre-release ordering: .devN, <no suffix>, .postN
614+ _first_non_none (
615+ self .post ,
616+ self .dev ,
617+ release_key ,
618+ ),
619+ # PEP440 - post release ordering: .devN, <no suffix>
620+ self .dev or release_key ,
621+ )
622+
597623def _new_version (* , epoch = 0 , release , pre = "" , post = "" , dev = "" , local = "" , is_prefix = False , norm ):
598624 epoch = epoch or 0
599625 _release = tuple ([int (d ) for d in release .split ("." )])
@@ -612,13 +638,20 @@ def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "
612638 if not post .startswith (".post" ):
613639 fail ("post release identifier must start with '.post', got: {}" .format (post ))
614640 post = int (post [len (".post" ):])
641+
642+ # We choose `~` since almost all of the ASCII characters will be before
643+ # it. Use `ord` and `chr` functions to find a good value.
644+ post = ("~" , post )
615645 else :
616646 post = None
617647
618648 if dev :
619649 if not dev .startswith (".dev" ):
620650 fail ("dev release identifier must start with '.dev', got: {}" .format (dev ))
621651 dev = int (dev [len (".dev" ):])
652+
653+ # Empty string goes first when comparing
654+ dev = ("" , dev )
622655 else :
623656 dev = None
624657
@@ -647,34 +680,7 @@ def _new_version(*, epoch = 0, release, pre = "", post = "", dev = "", local = "
647680 le = lambda x : not _version_gt (self , x ), # buildifier: disable=uninitialized
648681 ge = lambda x : not _version_lt (self , x ), # buildifier: disable=uninitialized
649682 str = lambda : norm ,
650- key = lambda : (
651- epoch ,
652- _release ,
653- # PEP440 Within a pre-release, post-release or development release segment with
654- # a shared prefix, ordering MUST be by the value of the numeric component.
655- # PEP440 release ordering: .devN, aN, bN, rcN, <no suffix>, .postN
656- # We choose to first match the pre-release, then post release, then dev and
657- # then stable
658- _first_non_none (
659- pre ,
660- # We choose `~` since almost all of the ASCII characters will be before
661- # it. Use `ord` and `chr` functions to find a good value.
662- ("~" , post ) if post != None else None ,
663- ("" , dev ) if dev != None else None ,
664- # 'z' is just a character that goes after "rc",
665- ("z" , 0 ),
666- ),
667- # PEP440 local versions go before post versions
668- tuple ([(type (item ) == "int" , item ) for item in local or []]),
669- # PEP440 - pre-release ordering: .devN, <no suffix>, .postN
670- _first_non_none (
671- ("~" , post ) if post != None else None ,
672- ("" , dev ) if dev != None else None ,
673- ("z" , 0 ),
674- ),
675- # PEP440 - post release ordering: .devN, <no suffix>
676- ("" , dev ) if dev != None else ("~" ,),
677- ),
683+ key = lambda : _key (self ), # buildifier: disable=uninitialized
678684 )
679685
680686 return self
0 commit comments