Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 13ad4ab

Browse filesBrowse files
authored
Merge pull request #320 from tomschr/feature/309-private-functions
Fix #309: Make some functions private
2 parents dc1e110 + 201d783 commit 13ad4ab
Copy full SHA for 13ad4ab

File tree

4 files changed

+64
-158
lines changed
Filter options

4 files changed

+64
-158
lines changed

‎changelog.d/309.trivial.rst

Copy file name to clipboard
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Some (private) functions from the :mod:`semver.version`
2+
module has been changed.
3+
4+
The following functions got renamed:
5+
6+
* function ``semver.version.comparator`` got renamed to
7+
:func:`semver.version._comparator` as it is only useful
8+
inside the :class:`~semver.version.Version` class.
9+
* function ``semver.version.cmp`` got renamed to
10+
:func:`semver.version._cmp` as it is only useful
11+
inside the :class:`~semver.version.Version` class.
12+
13+
The following functions got integrated into the
14+
:class:`~semver.version.Version` class:
15+
16+
* function ``semver.version._nat_cmd`` as a classmethod
17+
* function ``semver.version.ensure_str``

‎docs/api.rst

Copy file name to clipboardExpand all lines: docs/api.rst
-6Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,6 @@ Version Handling :mod:`semver.version`
5050

5151
.. automodule:: semver.version
5252

53-
.. autofunction:: semver.version.cmp
54-
55-
.. autofunction:: semver.version.ensure_str
56-
57-
.. autofunction:: semver.version.comparator
58-
5953
.. autoclass:: semver.version.VersionInfo
6054

6155
.. autoclass:: semver.version.Version

‎src/semver/version.py

Copy file name to clipboardExpand all lines: src/semver/version.py
+43-67Lines changed: 43 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,7 @@
2929
Comparator = Callable[["Version", Comparable], bool]
3030

3131

32-
def cmp(a, b): # TODO: type hints
33-
"""Return negative if a<b, zero if a==b, positive if a>b."""
34-
return (a > b) - (a < b)
35-
36-
37-
def ensure_str(s: String, encoding="utf-8", errors="strict") -> str:
38-
# Taken from six project
39-
"""
40-
Coerce *s* to `str`.
41-
42-
* `str` -> `str`
43-
* `bytes` -> decoded to `str`
44-
45-
:param s: the string to convert
46-
:param encoding: the encoding to apply, defaults to "utf-8"
47-
:param errors: set a different error handling scheme,
48-
defaults to "strict".
49-
Other possible values are `ignore`, `replace`, and
50-
`xmlcharrefreplace` as well as any other name
51-
registered with :func:`codecs.register_error`.
52-
:raises TypeError: if ``s`` is not str or bytes type
53-
:return: the converted string
54-
"""
55-
if isinstance(s, bytes):
56-
s = s.decode(encoding, errors)
57-
elif not isinstance(s, String.__args__): # type: ignore
58-
raise TypeError("not expecting type '%s'" % type(s))
59-
return s
60-
61-
62-
def comparator(operator: Comparator) -> Comparator:
32+
def _comparator(operator: Comparator) -> Comparator:
6333
"""Wrap a Version binary op method in a type-check."""
6434

6535
@wraps(operator)
@@ -78,31 +48,9 @@ def wrapper(self: "Version", other: Comparable) -> bool:
7848
return wrapper
7949

8050

81-
def _nat_cmp(a, b): # TODO: type hints
82-
def convert(text):
83-
return int(text) if re.match("^[0-9]+$", text) else text
84-
85-
def split_key(key):
86-
return [convert(c) for c in key.split(".")]
87-
88-
def cmp_prerelease_tag(a, b):
89-
if isinstance(a, int) and isinstance(b, int):
90-
return cmp(a, b)
91-
elif isinstance(a, int):
92-
return -1
93-
elif isinstance(b, int):
94-
return 1
95-
else:
96-
return cmp(a, b)
97-
98-
a, b = a or "", b or ""
99-
a_parts, b_parts = split_key(a), split_key(b)
100-
for sub_a, sub_b in zip(a_parts, b_parts):
101-
cmp_result = cmp_prerelease_tag(sub_a, sub_b)
102-
if cmp_result != 0:
103-
return cmp_result
104-
else:
105-
return cmp(len(a), len(b))
51+
def _cmp(a, b): # TODO: type hints
52+
"""Return negative if a<b, zero if a==b, positive if a>b."""
53+
return (a > b) - (a < b)
10654

10755

10856
class Version:
@@ -165,6 +113,29 @@ def __init__(
165113
self._prerelease = None if prerelease is None else str(prerelease)
166114
self._build = None if build is None else str(build)
167115

116+
@classmethod
117+
def _nat_cmp(cls, a, b): # TODO: type hints
118+
def cmp_prerelease_tag(a, b):
119+
if isinstance(a, int) and isinstance(b, int):
120+
return _cmp(a, b)
121+
elif isinstance(a, int):
122+
return -1
123+
elif isinstance(b, int):
124+
return 1
125+
else:
126+
return _cmp(a, b)
127+
128+
a, b = a or "", b or ""
129+
a_parts, b_parts = a.split("."), b.split(".")
130+
a_parts = [int(x) if re.match(r"^\d+$", x) else x for x in a_parts]
131+
b_parts = [int(x) if re.match(r"^\d+$", x) else x for x in b_parts]
132+
for sub_a, sub_b in zip(a_parts, b_parts):
133+
cmp_result = cmp_prerelease_tag(sub_a, sub_b)
134+
if cmp_result != 0:
135+
return cmp_result
136+
else:
137+
return _cmp(len(a), len(b))
138+
168139
@property
169140
def major(self) -> int:
170141
"""The major part of a version (read-only)."""
@@ -381,12 +352,12 @@ def compare(self, other: Comparable) -> int:
381352

382353
v1 = self.to_tuple()[:3]
383354
v2 = other.to_tuple()[:3]
384-
x = cmp(v1, v2)
355+
x = _cmp(v1, v2)
385356
if x:
386357
return x
387358

388359
rc1, rc2 = self.prerelease, other.prerelease
389-
rccmp = _nat_cmp(rc1, rc2)
360+
rccmp = self._nat_cmp(rc1, rc2)
390361

391362
if not rccmp:
392363
return 0
@@ -444,27 +415,27 @@ def next_version(self, part: str, prerelease_token: str = "rc") -> "Version":
444415
version = version.bump_patch()
445416
return version.bump_prerelease(prerelease_token)
446417

447-
@comparator
418+
@_comparator
448419
def __eq__(self, other: Comparable) -> bool: # type: ignore
449420
return self.compare(other) == 0
450421

451-
@comparator
422+
@_comparator
452423
def __ne__(self, other: Comparable) -> bool: # type: ignore
453424
return self.compare(other) != 0
454425

455-
@comparator
426+
@_comparator
456427
def __lt__(self, other: Comparable) -> bool:
457428
return self.compare(other) < 0
458429

459-
@comparator
430+
@_comparator
460431
def __le__(self, other: Comparable) -> bool:
461432
return self.compare(other) <= 0
462433

463-
@comparator
434+
@_comparator
464435
def __gt__(self, other: Comparable) -> bool:
465436
return self.compare(other) > 0
466437

467-
@comparator
438+
@_comparator
468439
def __ge__(self, other: Comparable) -> bool:
469440
return self.compare(other) >= 0
470441

@@ -593,15 +564,20 @@ def parse(cls, version: String) -> "Version":
593564
:param version: version string
594565
:return: a new :class:`Version` instance
595566
:raises ValueError: if version is invalid
567+
:raises TypeError: if version contains the wrong type
596568
597569
>>> semver.Version.parse('3.4.5-pre.2+build.4')
598570
Version(major=3, minor=4, patch=5, \
599571
prerelease='pre.2', build='build.4')
600572
"""
601-
version_str = ensure_str(version)
602-
match = cls._REGEX.match(version_str)
573+
if isinstance(version, bytes):
574+
version = version.decode("UTF-8")
575+
elif not isinstance(version, String.__args__): # type: ignore
576+
raise TypeError("not expecting type '%s'" % type(version))
577+
578+
match = cls._REGEX.match(version)
603579
if match is None:
604-
raise ValueError(f"{version_str} is not valid SemVer string")
580+
raise ValueError(f"{version} is not valid SemVer string")
605581

606582
matched_version_parts: Dict[str, Any] = match.groupdict()
607583

‎tests/test_typeerror-274.py

Copy file name to clipboard
+4-85Lines changed: 4 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,14 @@
1-
import sys
2-
31
import pytest
4-
52
import semver
6-
import semver.version
7-
8-
PY2 = sys.version_info[0] == 2
9-
PY3 = sys.version_info[0] == 3
10-
11-
12-
def ensure_binary(s, encoding="utf-8", errors="strict"):
13-
"""
14-
Coerce ``s`` to bytes.
15-
16-
* `str` -> encoded to `bytes`
17-
* `bytes` -> `bytes`
18-
19-
:param s: the string to convert
20-
:type s: str | bytes
21-
:param encoding: the encoding to apply, defaults to "utf-8"
22-
:type encoding: str
23-
:param errors: set a different error handling scheme;
24-
other possible values are `ignore`, `replace`, and
25-
`xmlcharrefreplace` as well as any other name
26-
registered with :func:`codecs.register_error`.
27-
Defaults to "strict".
28-
:type errors: str
29-
:raises TypeError: if ``s`` is not str or bytes type
30-
:return: the converted string
31-
:rtype: str
32-
"""
33-
if isinstance(s, str):
34-
return s.encode(encoding, errors)
35-
elif isinstance(s, bytes):
36-
return s
37-
else:
38-
raise TypeError("not expecting type '%s'" % type(s))
393

404

41-
def test_should_work_with_string_and_unicode():
5+
def test_should_work_with_string_and_bytes():
426
result = semver.compare("1.1.0", b"1.2.2")
437
assert result == -1
448
result = semver.compare(b"1.1.0", "1.2.2")
459
assert result == -1
4610

4711

48-
class TestEnsure:
49-
# From six project
50-
# grinning face emoji
51-
UNICODE_EMOJI = "\U0001F600"
52-
BINARY_EMOJI = b"\xf0\x9f\x98\x80"
53-
54-
def test_ensure_binary_raise_type_error(self):
55-
with pytest.raises(TypeError):
56-
semver.version.ensure_str(8)
57-
58-
def test_errors_and_encoding(self):
59-
ensure_binary(self.UNICODE_EMOJI, encoding="latin-1", errors="ignore")
60-
with pytest.raises(UnicodeEncodeError):
61-
ensure_binary(self.UNICODE_EMOJI, encoding="latin-1", errors="strict")
62-
63-
def test_ensure_binary_raise(self):
64-
converted_unicode = ensure_binary(
65-
self.UNICODE_EMOJI, encoding="utf-8", errors="strict"
66-
)
67-
converted_binary = ensure_binary(
68-
self.BINARY_EMOJI, encoding="utf-8", errors="strict"
69-
)
70-
71-
# PY3: str -> bytes
72-
assert converted_unicode == self.BINARY_EMOJI and isinstance(
73-
converted_unicode, bytes
74-
)
75-
# PY3: bytes -> bytes
76-
assert converted_binary == self.BINARY_EMOJI and isinstance(
77-
converted_binary, bytes
78-
)
79-
80-
def test_ensure_str(self):
81-
converted_unicode = semver.version.ensure_str(
82-
self.UNICODE_EMOJI, encoding="utf-8", errors="strict"
83-
)
84-
converted_binary = semver.version.ensure_str(
85-
self.BINARY_EMOJI, encoding="utf-8", errors="strict"
86-
)
87-
88-
# PY3: str -> str
89-
assert converted_unicode == self.UNICODE_EMOJI and isinstance(
90-
converted_unicode, str
91-
)
92-
# PY3: bytes -> str
93-
assert converted_binary == self.UNICODE_EMOJI and isinstance(
94-
converted_unicode, str
95-
)
12+
def test_should_not_work_with_invalid_args():
13+
with pytest.raises(TypeError):
14+
semver.version.Version.parse(8)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.