Skip to content

Commit dbddfc5

Browse files
committed
Improve server version semver handling
1 parent 4302a50 commit dbddfc5

File tree

1 file changed

+50
-14
lines changed

1 file changed

+50
-14
lines changed

nats/aio/client.py

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import ipaddress
2020
import json
2121
import logging
22+
import re
2223
import ssl
2324
import string
2425
import time
@@ -133,39 +134,74 @@ def __init__(self, server_version: str) -> None:
133134
self._major_version: Optional[int] = None
134135
self._minor_version: Optional[int] = None
135136
self._patch_version: Optional[int] = None
137+
self._prerelease_version: Optional[str] = None
138+
self._build_version: Optional[str] = None
136139
self._dev_version: Optional[str] = None
137140

138141
# TODO(@orsinium): use cached_property
139142
def parse_version(self) -> None:
140-
v = (self._server_version).split("-")
141-
if len(v) > 1:
142-
self._dev_version = v[1]
143-
tokens = v[0].split(".")
144-
n = len(tokens)
145-
if n > 1:
146-
self._major_version = int(tokens[0])
147-
if n > 2:
148-
self._minor_version = int(tokens[1])
149-
if n > 3:
150-
self._patch_version = int(tokens[2])
143+
# https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
144+
_SEMVER_REGEX = r"""
145+
^
146+
(?P<major>0|[1-9]\d*)
147+
\.
148+
(?P<minor>0|[1-9]\d*)
149+
\.
150+
(?P<patch>0|[1-9]\d*)
151+
(?:-(?P<prerelease>
152+
(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)
153+
(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*
154+
))?
155+
(?:\+(?P<buildmetadata>
156+
[0-9a-zA-Z-]+
157+
(?:\.[0-9a-zA-Z-]+)*
158+
))?
159+
$
160+
"""
161+
_REGEX = re.compile(_SEMVER_REGEX, re.VERBOSE)
162+
match = _REGEX.match(self._server_version)
163+
if match is None:
164+
raise ValueError(
165+
f"{self._server_version} is not a valid Semantic Version"
166+
)
167+
matches = match.groupdict()
168+
169+
self._major_version = int(matches["major"])
170+
self._minor_version = int(matches["minor"])
171+
self._patch_version = int(matches["patch"])
172+
self._prerelease_version = matches["prerelease"] or ""
173+
self._build_version = matches["buildmetadata"] or ""
174+
self._dev_version = self._prerelease_version + self._build_version
151175

152176
@property
153177
def major(self) -> int:
154178
if not self._major_version:
155179
self.parse_version()
156-
return self._major_version or 0
180+
return self._major_version
157181

158182
@property
159183
def minor(self) -> int:
160184
if not self._minor_version:
161185
self.parse_version()
162-
return self._minor_version or 0
186+
return self._minor_version
163187

164188
@property
165189
def patch(self) -> int:
166190
if not self._patch_version:
167191
self.parse_version()
168-
return self._patch_version or 0
192+
return self._patch_version
193+
194+
@property
195+
def prerelease(self) -> int:
196+
if not self._prerelease_version:
197+
self.parse_version()
198+
return self._prerelease_version
199+
200+
@property
201+
def build(self) -> int:
202+
if not self._build_version:
203+
self.parse_version()
204+
return self._build_version
169205

170206
@property
171207
def dev(self) -> str:

0 commit comments

Comments
 (0)