0
# Utility Functions
1
2
Standalone helper functions for version manipulation, validation, and dynamic version detection.
3
4
## Capabilities
5
6
### Version Bumping
7
8
Increment numerical components of version strings without requiring Version objects.
9
10
```python { .api }
11
def bump_version(base: str, index: int = -1, increment: int = 1) -> str
12
```
13
14
**Parameters**:
15
- `base`: Version core like "1.2.3" (without pre-release identifiers)
16
- `index`: Position to increment using Python indexing (0+ from left, -1 from right)
17
- `increment`: Amount to increment by (default: 1)
18
19
**Returns**: Bumped version string
20
21
**Usage Examples**:
22
23
```python
24
from dunamai import bump_version
25
26
# Bump patch version (rightmost, default)
27
print(bump_version("1.2.3"))
28
# "1.2.4"
29
30
# Bump minor version
31
print(bump_version("1.2.3", index=1))
32
# "1.3.0"
33
34
# Bump major version
35
print(bump_version("1.2.3", index=0))
36
# "2.0.0"
37
38
# Bump by custom amount
39
print(bump_version("1.2.3", increment=5))
40
# "1.2.8"
41
42
# Bump minor by 2
43
print(bump_version("1.2.3", index=1, increment=2))
44
# "1.4.0"
45
46
# Working with longer version strings
47
print(bump_version("1.2.3.4", index=2))
48
# "1.2.4.0"
49
```
50
51
### Version Validation
52
53
Validate version strings against specific versioning standards.
54
55
```python { .api }
56
def check_version(version: str, style: Style = Style.Pep440) -> None
57
```
58
59
**Parameters**:
60
- `version`: Version string to validate
61
- `style`: Versioning style to check against (default: PEP 440)
62
63
**Raises**: `ValueError` if version is invalid for the specified style
64
65
**Usage Examples**:
66
67
```python
68
from dunamai import check_version, Style
69
70
# Valid PEP 440 versions
71
check_version("1.2.3") # OK
72
check_version("1.2.3rc1") # OK
73
check_version("1.2.3.post7.dev0") # OK
74
check_version("2!1.2.3+local.version") # OK
75
76
# Invalid PEP 440 version
77
try:
78
check_version("v1.2.3") # 'v' prefix not allowed in PEP 440
79
except ValueError as e:
80
print(f"Invalid: {e}")
81
82
# Semantic Versioning validation
83
check_version("1.2.3", Style.SemVer) # OK
84
check_version("1.2.3-alpha.1", Style.SemVer) # OK
85
check_version("1.2.3+build.metadata", Style.SemVer) # OK
86
87
try:
88
check_version("1.2", Style.SemVer) # Missing patch version
89
except ValueError as e:
90
print(f"Invalid SemVer: {e}")
91
92
# Haskell PVP validation
93
check_version("1.2.3", Style.Pvp) # OK
94
check_version("1.2.3-alpha", Style.Pvp) # OK
95
96
try:
97
check_version("1.2.3+build", Style.Pvp) # '+' not allowed in PVP
98
except ValueError as e:
99
print(f"Invalid PVP: {e}")
100
```
101
102
### Dynamic Version Detection
103
104
Determine version for installed packages with fallback strategies.
105
106
```python { .api }
107
def get_version(
108
name: str,
109
first_choice: Optional[Callable[[], Optional[Version]]] = None,
110
third_choice: Optional[Callable[[], Optional[Version]]] = None,
111
fallback: Version = Version("0.0.0"),
112
ignore: Optional[Sequence[Version]] = None,
113
parser: Callable[[str], Version] = Version,
114
) -> Version
115
```
116
117
**Parameters**:
118
- `name`: Installed package name
119
- `first_choice`: Primary version detection callback
120
- `third_choice`: Tertiary fallback if package not found in metadata
121
- `fallback`: Ultimate fallback version (default: "0.0.0")
122
- `ignore`: List of versions to ignore
123
- `parser`: Function to convert strings to Version objects
124
125
**Returns**: First available valid version
126
127
**Usage Examples**:
128
129
```python
130
from dunamai import get_version, Version
131
132
# Basic usage - get version from package metadata
133
version = get_version("dunamai")
134
print(version.serialize())
135
136
# With VCS fallback
137
def vcs_fallback():
138
try:
139
return Version.from_any_vcs()
140
except:
141
return None
142
143
version = get_version(
144
"my-package",
145
first_choice=vcs_fallback,
146
fallback=Version("0.0.1")
147
)
148
149
# Complex fallback strategy
150
def git_version():
151
try:
152
return Version.from_git(strict=True)
153
except:
154
return None
155
156
def any_vcs_version():
157
try:
158
return Version.from_any_vcs(strict=True)
159
except:
160
return None
161
162
version = get_version(
163
"my-package",
164
first_choice=git_version,
165
third_choice=any_vcs_version,
166
fallback=Version("0.0.0", distance=1),
167
ignore=[Version("0.0.0")]
168
)
169
170
# Custom parser
171
def custom_parser(version_str):
172
# Custom logic to parse version strings
173
return Version.parse(version_str, pattern="custom-pattern")
174
175
version = get_version("my-package", parser=custom_parser)
176
```
177
178
### Package Version Setting
179
180
Common pattern for setting `__version__` in Python packages.
181
182
**Usage Examples**:
183
184
```python
185
# In your package's __init__.py
186
from dunamai import get_version, Version
187
188
def _get_version():
189
try:
190
return Version.from_any_vcs()
191
except:
192
return None
193
194
__version__ = get_version(
195
"my-package",
196
first_choice=_get_version,
197
fallback=Version("0.0.0")
198
).serialize()
199
200
# For development versions
201
def _get_dev_version():
202
try:
203
version = Version.from_git()
204
return version if version.distance > 0 else None
205
except:
206
return None
207
208
__version__ = get_version(
209
"my-package",
210
first_choice=_get_dev_version,
211
fallback=Version("0.0.0", distance=1)
212
).serialize()
213
```
214
215
## Batch Operations
216
217
### Multiple Version Validation
218
219
```python
220
from dunamai import check_version, Style
221
222
versions_to_check = [
223
("1.2.3", Style.Pep440),
224
("1.2.3-alpha.1", Style.SemVer),
225
("1.2.3-test", Style.Pvp),
226
]
227
228
for version, style in versions_to_check:
229
try:
230
check_version(version, style)
231
print(f"✓ {version} is valid {style.value}")
232
except ValueError as e:
233
print(f"✗ {version} is invalid {style.value}: {e}")
234
```
235
236
### Version Range Bumping
237
238
```python
239
from dunamai import bump_version
240
241
base_versions = ["1.2.3", "2.0.0", "0.1.0"]
242
243
# Bump all patch versions
244
patch_bumped = [bump_version(v) for v in base_versions]
245
print(patch_bumped) # ["1.2.4", "2.0.1", "0.1.1"]
246
247
# Bump all minor versions
248
minor_bumped = [bump_version(v, index=1) for v in base_versions]
249
print(minor_bumped) # ["1.3.0", "2.1.0", "0.2.0"]
250
```
251
252
### Fallback Chain Pattern
253
254
```python
255
from dunamai import get_version, Version
256
257
def create_fallback_chain(*fallback_funcs):
258
"""Create a fallback chain of version detection functions"""
259
def chain():
260
for func in fallback_funcs:
261
try:
262
result = func()
263
if result:
264
return result
265
except:
266
continue
267
return None
268
return chain
269
270
# Define fallback functions
271
def git_version():
272
return Version.from_git(strict=True)
273
274
def any_vcs_version():
275
return Version.from_any_vcs(strict=True)
276
277
def tagged_version():
278
return Version("1.0.0") # From some configuration
279
280
# Create chain
281
fallback_chain = create_fallback_chain(git_version, any_vcs_version, tagged_version)
282
283
# Use in get_version
284
version = get_version(
285
"my-package",
286
first_choice=fallback_chain,
287
fallback=Version("0.0.0")
288
)
289
```