0
# Version Operations
1
2
Comprehensive functionality for creating, manipulating, comparing, and validating semantic version objects. The Version class provides complete SemVer 2.0.0 compliance with parsing, validation, comparison, and version bumping capabilities.
3
4
## Capabilities
5
6
### Version Creation
7
8
Create Version objects from strings or individual components with full SemVer 2.0.0 validation.
9
10
```python { .api }
11
class Version:
12
def __init__(
13
self,
14
version_string=None,
15
major=None,
16
minor=None,
17
patch=None,
18
prerelease=None,
19
build=None,
20
partial=False
21
):
22
"""
23
Create a Version object from string or components.
24
25
Args:
26
version_string: SemVer string like '1.2.3-alpha.1+build.456'
27
major: Major version number (required if using components)
28
minor: Minor version number (required if using components)
29
patch: Patch version number (required if using components)
30
prerelease: Tuple of prerelease identifiers
31
build: Tuple of build metadata identifiers
32
partial: Allow partial versions (deprecated)
33
34
Raises:
35
ValueError: If version string is invalid or components are invalid
36
"""
37
```
38
39
**Usage Examples:**
40
41
```python
42
# From version string
43
v1 = Version('1.2.3')
44
v2 = Version('1.2.3-alpha.1')
45
v3 = Version('1.2.3-alpha.1+build.456')
46
47
# From components
48
v4 = Version(major=1, minor=2, patch=3)
49
v5 = Version(major=1, minor=2, patch=3, prerelease=('alpha', '1'))
50
v6 = Version(major=1, minor=2, patch=3, prerelease=('alpha', '1'), build=('build', '456'))
51
52
# Invalid versions raise ValueError
53
try:
54
invalid = Version('1.2') # Missing patch version
55
except ValueError as e:
56
print(f"Invalid version: {e}")
57
```
58
59
### Version Parsing
60
61
Parse version strings with optional coercion for non-standard formats.
62
63
```python { .api }
64
@classmethod
65
def parse(cls, version_string, partial=False, coerce=False):
66
"""
67
Parse a version string into components.
68
69
Args:
70
version_string: Version string to parse
71
partial: Allow partial versions (deprecated)
72
coerce: Attempt to coerce invalid formats
73
74
Returns:
75
Tuple of (major, minor, patch, prerelease, build)
76
77
Raises:
78
ValueError: If version string cannot be parsed
79
"""
80
81
@classmethod
82
def coerce(cls, version_string, partial=False):
83
"""
84
Coerce a version-like string into a valid SemVer version.
85
86
Args:
87
version_string: Version-like string to coerce
88
partial: Allow partial versions (deprecated)
89
90
Returns:
91
Valid Version object
92
93
Examples:
94
Version.coerce('1') -> Version('1.0.0')
95
Version.coerce('1.2.3.4.5') -> Version('1.2.3+4.5')
96
Version.coerce('1.2.3a4') -> Version('1.2.3-a4')
97
"""
98
```
99
100
**Usage Examples:**
101
102
```python
103
# Parse version string
104
components = Version.parse('1.2.3-alpha.1+build.456')
105
print(components) # (1, 2, 3, ('alpha', '1'), ('build', '456'))
106
107
# Coerce non-standard formats
108
v1 = Version.coerce('1') # Version('1.0.0')
109
v2 = Version.coerce('1.2') # Version('1.2.0')
110
v3 = Version.coerce('1.2.3.4.5') # Version('1.2.3+4.5')
111
v4 = Version.coerce('1.2.3a4') # Version('1.2.3-a4')
112
```
113
114
### Version Properties
115
116
Access individual components of version objects.
117
118
```python { .api }
119
@property
120
def major(self):
121
"""Major version number."""
122
123
@property
124
def minor(self):
125
"""Minor version number (None only for partial versions - deprecated)."""
126
127
@property
128
def patch(self):
129
"""Patch version number (None only for partial versions - deprecated)."""
130
131
@property
132
def prerelease(self):
133
"""Tuple of prerelease identifiers."""
134
135
@property
136
def build(self):
137
"""Tuple of build metadata identifiers."""
138
139
@property
140
def partial(self):
141
"""Whether this is a partial version (deprecated)."""
142
143
@property
144
def precedence_key(self):
145
"""Key used for version sorting and comparison."""
146
147
def __iter__(self):
148
"""Iterate over version components: (major, minor, patch, prerelease, build)."""
149
150
def __str__(self):
151
"""String representation in SemVer format."""
152
153
def __repr__(self):
154
"""Debug representation of the Version object."""
155
156
def __hash__(self):
157
"""Hash for use in sets and dictionaries."""
158
```
159
160
**Usage Examples:**
161
162
```python
163
version = Version('1.2.3-alpha.1+build.456')
164
165
print(version.major) # 1
166
print(version.minor) # 2
167
print(version.patch) # 3
168
print(version.prerelease) # ('alpha', '1')
169
print(version.build) # ('build', '456')
170
print(version.partial) # False
171
172
# Iterate over components
173
for component in version:
174
print(component)
175
# Output: 1, 2, 3, ('alpha', '1'), ('build', '456')
176
```
177
178
### Version Comparison
179
180
Compare versions using standard Python comparison operators following SemVer precedence rules.
181
182
```python { .api }
183
def __lt__(self, other: 'Version') -> bool: ...
184
def __le__(self, other: 'Version') -> bool: ...
185
def __eq__(self, other: 'Version') -> bool: ...
186
def __ne__(self, other: 'Version') -> bool: ...
187
def __gt__(self, other: 'Version') -> bool: ...
188
def __ge__(self, other: 'Version') -> bool: ...
189
```
190
191
**Usage Examples:**
192
193
```python
194
v1 = Version('1.0.0')
195
v2 = Version('1.0.1')
196
v3 = Version('1.0.0-alpha')
197
v4 = Version('1.0.0+build.1')
198
199
# Basic comparison
200
print(v1 < v2) # True
201
print(v1 > v3) # True (release > prerelease)
202
print(v1 == v4) # True (build metadata ignored in comparison)
203
204
# Sorting versions
205
versions = [Version('2.0.0'), Version('1.0.0'), Version('1.1.0')]
206
sorted_versions = sorted(versions)
207
print([str(v) for v in sorted_versions]) # ['1.0.0', '1.1.0', '2.0.0']
208
```
209
210
### Version Bumping
211
212
Generate new versions by incrementing major, minor, or patch components.
213
214
```python { .api }
215
def next_major(self) -> 'Version':
216
"""
217
Return the next major version.
218
219
Returns:
220
New Version with major incremented, minor/patch reset to 0,
221
prerelease and build metadata removed.
222
"""
223
224
def next_minor(self) -> 'Version':
225
"""
226
Return the next minor version.
227
228
Returns:
229
New Version with minor incremented, patch reset to 0,
230
prerelease and build metadata removed.
231
"""
232
233
def next_patch(self) -> 'Version':
234
"""
235
Return the next patch version.
236
237
Returns:
238
New Version with patch incremented,
239
prerelease and build metadata removed.
240
"""
241
```
242
243
**Usage Examples:**
244
245
```python
246
version = Version('1.2.3-alpha.1+build.456')
247
248
major = version.next_major()
249
print(major) # Version('2.0.0')
250
251
minor = version.next_minor()
252
print(minor) # Version('1.3.0')
253
254
patch = version.next_patch()
255
print(patch) # Version('1.2.4')
256
```
257
258
### Version Truncation
259
260
Truncate versions to specific precision levels.
261
262
```python { .api }
263
def truncate(self, level: str = 'patch') -> 'Version':
264
"""
265
Truncate version to specified level.
266
267
Args:
268
level: Truncation level ('major', 'minor', 'patch', 'prerelease', 'build')
269
270
Returns:
271
New Version truncated to specified level
272
"""
273
```
274
275
**Usage Examples:**
276
277
```python
278
version = Version('1.2.3-alpha.1+build.456')
279
280
major_only = version.truncate('major')
281
print(major_only) # Version('1.0.0')
282
283
minor_only = version.truncate('minor')
284
print(minor_only) # Version('1.2.0')
285
286
no_build = version.truncate('prerelease')
287
print(no_build) # Version('1.2.3-alpha.1')
288
```
289
290
### Utility Functions
291
292
Standalone functions for common version operations.
293
294
```python { .api }
295
def compare(v1: str, v2: str) -> int:
296
"""
297
Compare two version strings.
298
299
Args:
300
v1: First version string
301
v2: Second version string
302
303
Returns:
304
-1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
305
"""
306
307
def validate(version_string: str) -> bool:
308
"""
309
Check if a version string is valid SemVer.
310
311
Args:
312
version_string: Version string to validate
313
314
Returns:
315
True if valid, False otherwise
316
"""
317
```
318
319
**Usage Examples:**
320
321
```python
322
# Compare version strings directly
323
result = compare('1.0.0', '1.0.1')
324
print(result) # -1
325
326
result = compare('2.0.0', '1.9.9')
327
print(result) # 1
328
329
result = compare('1.0.0', '1.0.0+build')
330
print(result) # 0 (build metadata ignored)
331
332
# Validate version strings
333
print(validate('1.2.3')) # True
334
print(validate('1.2.3-alpha.1')) # True
335
print(validate('1.2')) # False
336
print(validate('invalid')) # False
337
```
338
339
## Version Validation Rules
340
341
The semantic_version library enforces strict SemVer 2.0.0 validation:
342
343
### Validation Patterns
344
345
```python { .api }
346
# Internal regex patterns used for validation
347
Version.version_re # Strict SemVer pattern for complete versions
348
Version.partial_version_re # Pattern allowing partial versions (deprecated)
349
```
350
351
### Validation Rules
352
353
- **Major, minor, patch**: Must be non-negative integers
354
- **Leading zeros**: Not allowed in numeric components (except single '0')
355
- **Prerelease identifiers**: Must be non-empty, can contain alphanumeric and hyphen
356
- **Build identifiers**: Must be non-empty, can contain alphanumeric and hyphen
357
- **Missing components**: Minor and patch default to 0 when using components, but string parsing requires all three
358
359
**Examples of validation:**
360
361
```python
362
# Valid versions
363
Version('1.2.3')
364
Version('1.2.3-alpha.1')
365
Version('1.2.3+build.456')
366
Version('1.2.3-alpha.1+build.456')
367
368
# Invalid versions (raise ValueError)
369
Version('1.2') # Missing patch
370
Version('01.2.3') # Leading zero in major
371
Version('1.02.3') # Leading zero in minor
372
Version('1.2.03') # Leading zero in patch
373
Version('1.2.3-') # Empty prerelease identifier
374
Version('1.2.3+') # Empty build identifier
375
```
376
377
## Error Handling
378
379
All version operations follow consistent error handling patterns:
380
381
- **ValueError**: Raised for invalid version strings or components
382
- **TypeError**: Raised for incompatible types in comparisons
383
- **DeprecationWarning**: Issued for deprecated functionality (partial versions)
384
385
```python
386
# Handle invalid versions
387
try:
388
invalid_version = Version('not.a.version')
389
except ValueError as e:
390
print(f"Invalid version: {e}")
391
392
# Handle type errors in comparison
393
try:
394
result = Version('1.0.0') < "1.0.1" # Should use Version object
395
except TypeError as e:
396
print(f"Type error: {e}")
397
398
# Handle leading zero errors
399
try:
400
leading_zero = Version('01.2.3')
401
except ValueError as e:
402
print(f"Leading zero error: {e}")
403
```