|
10 | 10 | import warnings |
11 | 11 |
|
12 | 12 |
|
| 13 | +PY2 = sys.version_info[0] == 2 |
| 14 | +PY3 = sys.version_info[0] == 3 |
| 15 | + |
| 16 | + |
13 | 17 | __version__ = "2.10.2" |
14 | 18 | __author__ = "Kostiantyn Rybnikov" |
15 | 19 | __author_email__ = "[email protected]" |
@@ -60,6 +64,53 @@ def cmp(a, b): |
60 | 64 | return (a > b) - (a < b) |
61 | 65 |
|
62 | 66 |
|
| 67 | +if PY3: # pragma: no cover |
| 68 | + string_types = str, bytes |
| 69 | + text_type = str |
| 70 | + binary_type = bytes |
| 71 | + |
| 72 | + def b(s): |
| 73 | + return s.encode("latin-1") |
| 74 | + |
| 75 | + def u(s): |
| 76 | + return s |
| 77 | + |
| 78 | + |
| 79 | +else: # pragma: no cover |
| 80 | + string_types = unicode, str |
| 81 | + text_type = unicode |
| 82 | + binary_type = str |
| 83 | + |
| 84 | + def b(s): |
| 85 | + return s |
| 86 | + |
| 87 | + # Workaround for standalone backslash |
| 88 | + def u(s): |
| 89 | + return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") |
| 90 | + |
| 91 | + |
| 92 | +def ensure_str(s, encoding="utf-8", errors="strict"): |
| 93 | + # Taken from six project |
| 94 | + """ |
| 95 | + Coerce *s* to `str`. |
| 96 | +
|
| 97 | + For Python 2: |
| 98 | + - `unicode` -> encoded to `str` |
| 99 | + - `str` -> `str` |
| 100 | +
|
| 101 | + For Python 3: |
| 102 | + - `str` -> `str` |
| 103 | + - `bytes` -> decoded to `str` |
| 104 | + """ |
| 105 | + if not isinstance(s, (text_type, binary_type)): |
| 106 | + raise TypeError("not expecting type '%s'" % type(s)) |
| 107 | + if PY2 and isinstance(s, text_type): |
| 108 | + s = s.encode(encoding, errors) |
| 109 | + elif PY3 and isinstance(s, binary_type): |
| 110 | + s = s.decode(encoding, errors) |
| 111 | + return s |
| 112 | + |
| 113 | + |
63 | 114 | def deprecated(func=None, replace=None, version=None, category=DeprecationWarning): |
64 | 115 | """ |
65 | 116 | Decorates a function to output a deprecation warning. |
@@ -144,7 +195,7 @@ def comparator(operator): |
144 | 195 |
|
145 | 196 | @wraps(operator) |
146 | 197 | def wrapper(self, other): |
147 | | - comparable_types = (VersionInfo, dict, tuple, list, str) |
| 198 | + comparable_types = (VersionInfo, dict, tuple, list, text_type, binary_type) |
148 | 199 | if not isinstance(other, comparable_types): |
149 | 200 | raise TypeError( |
150 | 201 | "other type %r must be in %r" % (type(other), comparable_types) |
@@ -423,7 +474,7 @@ def compare(self, other): |
423 | 474 | 0 |
424 | 475 | """ |
425 | 476 | cls = type(self) |
426 | | - if isinstance(other, str): |
| 477 | + if isinstance(other, string_types): |
427 | 478 | other = cls.parse(other) |
428 | 479 | elif isinstance(other, dict): |
429 | 480 | other = cls(**other) |
@@ -651,7 +702,7 @@ def parse(version): |
651 | 702 | VersionInfo(major=3, minor=4, patch=5, \ |
652 | 703 | prerelease='pre.2', build='build.4') |
653 | 704 | """ |
654 | | - match = VersionInfo._REGEX.match(version) |
| 705 | + match = VersionInfo._REGEX.match(ensure_str(version)) |
655 | 706 | if match is None: |
656 | 707 | raise ValueError("%s is not valid SemVer string" % version) |
657 | 708 |
|
@@ -825,7 +876,7 @@ def max_ver(ver1, ver2): |
825 | 876 | >>> semver.max_ver("1.0.0", "2.0.0") |
826 | 877 | '2.0.0' |
827 | 878 | """ |
828 | | - if isinstance(ver1, str): |
| 879 | + if isinstance(ver1, string_types): |
829 | 880 | ver1 = VersionInfo.parse(ver1) |
830 | 881 | elif not isinstance(ver1, VersionInfo): |
831 | 882 | raise TypeError() |
|
0 commit comments