@@ -371,29 +371,80 @@ def bump_build(self, token="build"):
371
371
build = cls ._increment_string (self ._build or (token or "build" ) + ".0" )
372
372
return cls (self ._major , self ._minor , self ._patch , self ._prerelease , build )
373
373
374
+ def compare (self , other ):
375
+ """
376
+ Compare self with other.
377
+
378
+ :param other: the second version (can be string, a dict, tuple/list, or
379
+ a VersionInfo instance)
380
+ :return: The return value is negative if ver1 < ver2,
381
+ zero if ver1 == ver2 and strictly positive if ver1 > ver2
382
+ :rtype: int
383
+
384
+ >>> semver.VersionInfo.parse("1.0.0").compare("2.0.0")
385
+ -1
386
+ >>> semver.VersionInfo.parse("2.0.0").compare("1.0.0")
387
+ 1
388
+ >>> semver.VersionInfo.parse("2.0.0").compare("2.0.0")
389
+ 0
390
+ >>> semver.VersionInfo.parse("2.0.0").compare(dict(major=2, minor=0, patch=0))
391
+ 0
392
+ """
393
+ cls = type (self )
394
+ if isinstance (other , str ):
395
+ other = cls .parse (other )
396
+ elif isinstance (other , dict ):
397
+ other = cls (** other )
398
+ elif isinstance (other , (tuple , list )):
399
+ other = cls (* other )
400
+ elif not isinstance (other , cls ):
401
+ raise TypeError (
402
+ "Expected str or {} instance, but got {}" .format (
403
+ cls .__name__ , type (other )
404
+ )
405
+ )
406
+
407
+ v1 = self .to_tuple ()[:3 ]
408
+ v2 = other .to_tuple ()[:3 ]
409
+ x = cmp (v1 , v2 )
410
+ if x :
411
+ return x
412
+
413
+ rc1 , rc2 = self .prerelease , other .prerelease
414
+ rccmp = _nat_cmp (rc1 , rc2 )
415
+
416
+ if not rccmp :
417
+ return 0
418
+ if not rc1 :
419
+ return 1
420
+ elif not rc2 :
421
+ return - 1
422
+
423
+ return rccmp
424
+
374
425
@comparator
375
426
def __eq__ (self , other ):
376
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) == 0
427
+ return self .compare ( other ) == 0
377
428
378
429
@comparator
379
430
def __ne__ (self , other ):
380
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) != 0
431
+ return self .compare ( other ) != 0
381
432
382
433
@comparator
383
434
def __lt__ (self , other ):
384
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) < 0
435
+ return self .compare ( other ) < 0
385
436
386
437
@comparator
387
438
def __le__ (self , other ):
388
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) <= 0
439
+ return self .compare ( other ) <= 0
389
440
390
441
@comparator
391
442
def __gt__ (self , other ):
392
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) > 0
443
+ return self .compare ( other ) > 0
393
444
394
445
@comparator
395
446
def __ge__ (self , other ):
396
- return _compare_by_keys ( self .to_dict (), _to_dict ( other ) ) >= 0
447
+ return self .compare ( other ) >= 0
397
448
398
449
def __repr__ (self ):
399
450
s = ", " .join ("%s=%r" % (key , val ) for key , val in self .to_dict ().items ())
@@ -424,6 +475,53 @@ def finalize_version(self):
424
475
cls = type (self )
425
476
return cls (self .major , self .minor , self .patch )
426
477
478
+ def match (self , match_expr ):
479
+ """
480
+ Compare self to match a match expression.
481
+
482
+ :param str match_expr: operator and version; valid operators are
483
+ < smaller than
484
+ > greater than
485
+ >= greator or equal than
486
+ <= smaller or equal than
487
+ == equal
488
+ != not equal
489
+ :return: True if the expression matches the version, otherwise False
490
+ :rtype: bool
491
+
492
+ >>> semver.VersionInfo.parse("2.0.0").match(">=1.0.0")
493
+ True
494
+ >>> semver.VersionInfo.parse("1.0.0").match(">1.0.0")
495
+ False
496
+ """
497
+ prefix = match_expr [:2 ]
498
+ if prefix in (">=" , "<=" , "==" , "!=" ):
499
+ match_version = match_expr [2 :]
500
+ elif prefix and prefix [0 ] in (">" , "<" ):
501
+ prefix = prefix [0 ]
502
+ match_version = match_expr [1 :]
503
+ else :
504
+ raise ValueError (
505
+ "match_expr parameter should be in format <op><ver>, "
506
+ "where <op> is one of "
507
+ "['<', '>', '==', '<=', '>=', '!=']. "
508
+ "You provided: %r" % match_expr
509
+ )
510
+
511
+ possibilities_dict = {
512
+ ">" : (1 ,),
513
+ "<" : (- 1 ,),
514
+ "==" : (0 ,),
515
+ "!=" : (- 1 , 1 ),
516
+ ">=" : (0 , 1 ),
517
+ "<=" : (- 1 , 0 ),
518
+ }
519
+
520
+ possibilities = possibilities_dict [prefix ]
521
+ cmp_res = self .compare (match_version )
522
+
523
+ return cmp_res in possibilities
524
+
427
525
@staticmethod
428
526
def parse (version ):
429
527
"""
@@ -495,14 +593,6 @@ def isvalid(cls, version):
495
593
return False
496
594
497
595
498
- def _to_dict (obj ):
499
- if isinstance (obj , VersionInfo ):
500
- return obj .to_dict ()
501
- elif isinstance (obj , tuple ):
502
- return VersionInfo (* obj ).to_dict ()
503
- return obj
504
-
505
-
506
596
@deprecated (replace = "semver.VersionInfo.parse" , version = "2.10.0" )
507
597
def parse_version_info (version ):
508
598
"""
@@ -560,25 +650,7 @@ def cmp_prerelease_tag(a, b):
560
650
return cmp (len (a ), len (b ))
561
651
562
652
563
- def _compare_by_keys (d1 , d2 ):
564
- for key in ["major" , "minor" , "patch" ]:
565
- v = cmp (d1 .get (key ), d2 .get (key ))
566
- if v :
567
- return v
568
-
569
- rc1 , rc2 = d1 .get ("prerelease" ), d2 .get ("prerelease" )
570
- rccmp = _nat_cmp (rc1 , rc2 )
571
-
572
- if not rccmp :
573
- return 0
574
- if not rc1 :
575
- return 1
576
- elif not rc2 :
577
- return - 1
578
-
579
- return rccmp
580
-
581
-
653
+ @deprecated (version = "2.10.0" )
582
654
def compare (ver1 , ver2 ):
583
655
"""
584
656
Compare two versions strings.
@@ -596,13 +668,11 @@ def compare(ver1, ver2):
596
668
>>> semver.compare("2.0.0", "2.0.0")
597
669
0
598
670
"""
599
-
600
- v1 = VersionInfo .parse (ver1 ).to_dict ()
601
- v2 = VersionInfo .parse (ver2 ).to_dict ()
602
-
603
- return _compare_by_keys (v1 , v2 )
671
+ v1 = VersionInfo .parse (ver1 )
672
+ return v1 .compare (ver2 )
604
673
605
674
675
+ @deprecated (version = "2.10.0" )
606
676
def match (version , match_expr ):
607
677
"""
608
678
Compare two versions strings through a comparison.
@@ -623,33 +693,8 @@ def match(version, match_expr):
623
693
>>> semver.match("1.0.0", ">1.0.0")
624
694
False
625
695
"""
626
- prefix = match_expr [:2 ]
627
- if prefix in (">=" , "<=" , "==" , "!=" ):
628
- match_version = match_expr [2 :]
629
- elif prefix and prefix [0 ] in (">" , "<" ):
630
- prefix = prefix [0 ]
631
- match_version = match_expr [1 :]
632
- else :
633
- raise ValueError (
634
- "match_expr parameter should be in format <op><ver>, "
635
- "where <op> is one of "
636
- "['<', '>', '==', '<=', '>=', '!=']. "
637
- "You provided: %r" % match_expr
638
- )
639
-
640
- possibilities_dict = {
641
- ">" : (1 ,),
642
- "<" : (- 1 ,),
643
- "==" : (0 ,),
644
- "!=" : (- 1 , 1 ),
645
- ">=" : (0 , 1 ),
646
- "<=" : (- 1 , 0 ),
647
- }
648
-
649
- possibilities = possibilities_dict [prefix ]
650
- cmp_res = compare (version , match_version )
651
-
652
- return cmp_res in possibilities
696
+ ver = VersionInfo .parse (version )
697
+ return ver .match (match_expr )
653
698
654
699
655
700
def max_ver (ver1 , ver2 ):
@@ -664,9 +709,10 @@ def max_ver(ver1, ver2):
664
709
>>> semver.max_ver("1.0.0", "2.0.0")
665
710
'2.0.0'
666
711
"""
667
- cmp_res = compare (ver1 , ver2 )
668
- if cmp_res == 0 or cmp_res == 1 :
669
- return ver1
712
+ ver1 = VersionInfo .parse (ver1 )
713
+ cmp_res = ver1 .compare (ver2 )
714
+ if cmp_res >= 0 :
715
+ return str (ver1 )
670
716
else :
671
717
return ver2
672
718
@@ -683,9 +729,10 @@ def min_ver(ver1, ver2):
683
729
>>> semver.min_ver("1.0.0", "2.0.0")
684
730
'1.0.0'
685
731
"""
686
- cmp_res = compare (ver1 , ver2 )
687
- if cmp_res == 0 or cmp_res == - 1 :
688
- return ver1
732
+ ver1 = VersionInfo .parse (ver1 )
733
+ cmp_res = ver1 .compare (ver2 )
734
+ if cmp_res <= 0 :
735
+ return str (ver1 )
689
736
else :
690
737
return ver2
691
738
0 commit comments