1
1
"""
2
2
Python helper for Semantic Versioning (http://semver.org/)
3
+
4
+ Examples:
5
+ >>> import semver
6
+ >>> semver.compare("1.0.0", "2.0.0")
7
+ -1
8
+ >>> semver.compare("2.0.0", "1.0.0")
9
+ 1
10
+ >>> semver.compare("2.0.0", "2.0.0")
11
+ 0
12
+ >>> semver.match("2.0.0", ">=1.0.0")
13
+ True
14
+ >>> semver.match("1.0.0", ">1.0.0")
15
+ False
16
+ >>> semver.format_version(3, 4, 5, 'pre.2', 'build.4')
17
+ '3.4.5-pre.2+build.4'
18
+ >>> version_parts = semver.parse("3.4.5-pre.2+build.4")
19
+ >>> version_parts == {
20
+ ... 'major': 3, 'minor': 4, 'patch': 5,
21
+ ... 'prerelease': 'pre.2', 'build': 'build.4'}
22
+ True
23
+ >>> version_info = semver.parse_version_info("3.4.5-pre.2+build.4")
24
+ >>> version_info
25
+ VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
26
+ >>> version_info.major
27
+ 3
28
+ >>> version_info > (1, 0)
29
+ True
30
+ >>> version_info < (3, 5)
31
+ True
32
+ >>> semver.bump_major("3.4.5")
33
+ '4.0.0'
34
+ >>> semver.bump_minor("3.4.5")
35
+ '3.5.0'
36
+ >>> semver.bump_patch("3.4.5")
37
+ '3.4.6'
38
+ >>> semver.max_ver("1.0.0", "2.0.0")
39
+ '2.0.0'
40
+ >>> semver.min_ver("1.0.0", "2.0.0")
41
+ '1.0.0'
3
42
"""
4
43
5
44
import collections
6
45
import re
46
+ import sys
7
47
8
48
9
49
__version__ = '2.7.2'
@@ -37,8 +77,13 @@ def cmp(a, b):
37
77
38
78
39
79
def parse (version ):
40
- """
41
- Parse version to major, minor, patch, pre-release, build parts.
80
+ """Parse version to major, minor, patch, pre-release, build parts.
81
+
82
+ :param version: version string
83
+ :return: dictionary with the keys 'build', 'major', 'minor', 'patch',
84
+ and 'prerelease'. The prerelease or build keys can be None
85
+ if not provided
86
+ :rtype: dict
42
87
"""
43
88
match = _REGEX .match (version )
44
89
if match is None :
@@ -56,10 +101,31 @@ def parse(version):
56
101
VersionInfo = collections .namedtuple (
57
102
'VersionInfo' , 'major minor patch prerelease build' )
58
103
104
+ # Only change it for Python > 3 as it is readonly
105
+ # for version 2
106
+ if sys .version_info > (3 , 0 ):
107
+ VersionInfo .__doc__ = """
108
+ :param int major: version when you make incompatible API changes.
109
+ :param int minor: version when you add functionality in
110
+ a backwards-compatible manner.
111
+ :param int patch: version when you make backwards-compatible bug fixes.
112
+ :param str prerelease: an optional prerelease string
113
+ :param str build: an optional build string
114
+
115
+ >>> import semver
116
+ >>> ver = semver.parse('3.4.5-pre.2+build.4')
117
+ >>> ver
118
+ {'build': 'build.4', 'major': 3, 'minor': 4, 'patch': 5,
119
+ 'prerelease': 'pre.2'}
120
+ """
121
+
59
122
60
123
def parse_version_info (version ):
61
- """
62
- Parse version string to a VersionInfo instance.
124
+ """Parse version string to a VersionInfo instance.
125
+
126
+ :param version: version string
127
+ :return: a :class:`VersionInfo` instance
128
+ :rtype: :class:`VersionInfo`
63
129
"""
64
130
parts = parse (version )
65
131
version_info = VersionInfo (
@@ -70,6 +136,14 @@ def parse_version_info(version):
70
136
71
137
72
138
def compare (ver1 , ver2 ):
139
+ """Compare two versions
140
+
141
+ :param ver1: version string 1
142
+ :param ver2: version string 2
143
+ :return: The return value is negative if ver1 < ver2,
144
+ zero if ver1 == ver2 and strictly positive if ver1 > ver2
145
+ :rtype: int
146
+ """
73
147
def nat_cmp (a , b ):
74
148
def convert (text ):
75
149
return (2 , int (text )) if re .match ('[0-9]+' , text ) else (1 , text )
@@ -104,6 +178,19 @@ def compare_by_keys(d1, d2):
104
178
105
179
106
180
def match (version , match_expr ):
181
+ """Compare two versions through a comparison
182
+
183
+ :param str version: a version string
184
+ :param str match_expr: operator and version; valid operators are
185
+ < smaller than
186
+ > greater than
187
+ >= greator or equal than
188
+ <= smaller or equal than
189
+ == equal
190
+ != not equal
191
+ :return: True if the expression matches the version, otherwise False
192
+ :rtype: bool
193
+ """
107
194
prefix = match_expr [:2 ]
108
195
if prefix in ('>=' , '<=' , '==' , '!=' ):
109
196
match_version = match_expr [2 :]
@@ -132,6 +219,13 @@ def match(version, match_expr):
132
219
133
220
134
221
def max_ver (ver1 , ver2 ):
222
+ """Returns the greater version of two versions
223
+
224
+ :param ver1: version string 1
225
+ :param ver2: version string 2
226
+ :return: the greater version of the two
227
+ :rtype: :class:`VersionInfo`
228
+ """
135
229
cmp_res = compare (ver1 , ver2 )
136
230
if cmp_res == 0 or cmp_res == 1 :
137
231
return ver1
@@ -140,6 +234,13 @@ def max_ver(ver1, ver2):
140
234
141
235
142
236
def min_ver (ver1 , ver2 ):
237
+ """Returns the smaller version of two versions
238
+
239
+ :param ver1: version string 1
240
+ :param ver2: version string 2
241
+ :return: the smaller version of the two
242
+ :rtype: :class:`VersionInfo`
243
+ """
143
244
cmp_res = compare (ver1 , ver2 )
144
245
if cmp_res == 0 or cmp_res == - 1 :
145
246
return ver1
@@ -148,6 +249,16 @@ def min_ver(ver1, ver2):
148
249
149
250
150
251
def format_version (major , minor , patch , prerelease = None , build = None ):
252
+ """Format a version according to the Semantic Versioning specification
253
+
254
+ :param str major: the required major part of a version
255
+ :param str minor: the required minor part of a version
256
+ :param str patch: the required patch part of a version
257
+ :param str prerelease: the optional prerelease part of a version
258
+ :param str build: the optional build part of a version
259
+ :return: the formatted string
260
+ :rtype: str
261
+ """
151
262
version = "%d.%d.%d" % (major , minor , patch )
152
263
if prerelease is not None :
153
264
version = version + "-%s" % prerelease
@@ -172,29 +283,59 @@ def _increment_string(string):
172
283
173
284
174
285
def bump_major (version ):
286
+ """Raise the major part of the version
287
+
288
+ :param: version string
289
+ :return: the raised version string
290
+ :rtype: str
291
+ """
175
292
verinfo = parse (version )
176
293
return format_version (verinfo ['major' ] + 1 , 0 , 0 )
177
294
178
295
179
296
def bump_minor (version ):
297
+ """Raise the minor part of the version
298
+
299
+ :param: version string
300
+ :return: the raised version string
301
+ :rtype: str
302
+ """
180
303
verinfo = parse (version )
181
304
return format_version (verinfo ['major' ], verinfo ['minor' ] + 1 , 0 )
182
305
183
306
184
307
def bump_patch (version ):
308
+ """Raise the patch part of the version
309
+
310
+ :param: version string
311
+ :return: the raised version string
312
+ :rtype: str
313
+ """
185
314
verinfo = parse (version )
186
315
return format_version (verinfo ['major' ], verinfo ['minor' ],
187
316
verinfo ['patch' ] + 1 )
188
317
189
318
190
319
def bump_prerelease (version ):
320
+ """Raise the prerelease part of the version
321
+
322
+ :param: version string
323
+ :return: the raised version string
324
+ :rtype: str
325
+ """
191
326
verinfo = parse (version )
192
327
verinfo ['prerelease' ] = _increment_string (verinfo ['prerelease' ] or 'rc.0' )
193
328
return format_version (verinfo ['major' ], verinfo ['minor' ], verinfo ['patch' ],
194
329
verinfo ['prerelease' ])
195
330
196
331
197
332
def bump_build (version ):
333
+ """Raise the build part of the version
334
+
335
+ :param: version string
336
+ :return: the raised version string
337
+ :rtype: str
338
+ """
198
339
verinfo = parse (version )
199
340
verinfo ['build' ] = _increment_string (verinfo ['build' ] or 'build.0' )
200
341
return format_version (verinfo ['major' ], verinfo ['minor' ], verinfo ['patch' ],
0 commit comments