0
# File Management
1
2
File modification and restoration functionality for applying dynamic versions to project files. Handles version substitution in source code, pyproject.toml updates, and automatic cleanup with comprehensive backup and restoration capabilities.
3
4
## Capabilities
5
6
### Main Version Application
7
8
Core function that detects project configuration, extracts version information, and applies it to project files with automatic state management and cleanup preparation.
9
10
```python { .api }
11
def _get_and_apply_version(
12
pyproject_path: Optional[Path] = None,
13
retain: bool = False,
14
force: bool = False,
15
io: bool = True
16
) -> Optional[str]:
17
"""
18
Main function to get version and apply it to project files.
19
20
Parameters:
21
- pyproject_path: Path to pyproject.toml (auto-detected if None)
22
- retain: If True, don't disable plugin in pyproject.toml during application
23
- force: Apply even if plugin is disabled in configuration
24
- io: If True, actually modify files (False for in-memory only)
25
26
Returns:
27
Optional[str]: Project name if successful, None if no project detected
28
29
Raises:
30
- RuntimeError: Unable to find pyproject.toml or determine version
31
"""
32
```
33
34
### Version Application to Files
35
36
Apply version information to pyproject.toml and configured source files, handling both Classic Poetry and PEP 621 project formats with comprehensive file creation and substitution.
37
38
```python { .api }
39
def _apply_version(
40
name: str,
41
version: str,
42
instance: Version,
43
config: _Config,
44
pyproject_path: Path,
45
mode: _Mode,
46
retain: bool = False
47
) -> None:
48
"""
49
Apply version to pyproject.toml and configured files.
50
51
Parameters:
52
- name: Project name for state tracking
53
- version: Formatted version string to apply
54
- instance: Dunamai Version object for template rendering
55
- config: Configuration containing file and substitution settings
56
- pyproject_path: Path to project's pyproject.toml
57
- mode: Project mode (Classic or PEP 621)
58
- retain: Don't disable plugin after application if True
59
"""
60
```
61
62
### Version Restoration
63
64
Restore all modified files to their original state, removing version changes and re-enabling plugin configuration to maintain repository cleanliness.
65
66
```python { .api }
67
def _revert_version(retain: bool = False) -> None:
68
"""
69
Revert all version changes back to original state.
70
71
Parameters:
72
- retain: Don't re-enable plugin configuration if True
73
"""
74
```
75
76
### File Substitution System
77
78
Apply version substitution to multiple files using configurable patterns and folder structures with support for different substitution modes and file creation.
79
80
```python { .api }
81
def _substitute_version(name: str, version: str, folders: Sequence[_FolderConfig]) -> None:
82
"""
83
Substitute version in specified files using configured patterns.
84
85
Parameters:
86
- name: Project name for state tracking
87
- version: Version string to substitute into files
88
- folders: Folder configurations with file patterns and substitution rules
89
"""
90
```
91
92
### Text Pattern Substitution
93
94
Core text substitution functionality supporting string and tuple modes for different version placeholder formats commonly used in Python projects.
95
96
```python { .api }
97
def _substitute_version_in_text(version: str, content: str, patterns: Sequence[_SubPattern]) -> str:
98
"""
99
Perform text substitution with version using configured patterns.
100
101
Parameters:
102
- version: Version string to substitute
103
- content: Original text content
104
- patterns: Substitution patterns with mode specifications
105
106
Returns:
107
str: Modified content with version substitutions applied
108
"""
109
```
110
111
## Configuration Classes
112
113
### Folder Configuration
114
115
```python { .api }
116
class _FolderConfig:
117
def __init__(self, path: Path, files: Sequence[str], patterns: Sequence[_SubPattern]):
118
"""
119
Configuration for folder-specific substitution settings.
120
121
Parameters:
122
- path: Base path for file pattern matching
123
- files: File glob patterns to process
124
- patterns: Substitution patterns to apply
125
"""
126
127
@staticmethod
128
def from_config(config: _Config, root: Path) -> Sequence["_FolderConfig"]:
129
"""
130
Create folder configurations from main configuration and project root.
131
132
Parameters:
133
- config: Main configuration object
134
- root: Project root path for relative path resolution
135
136
Returns:
137
Sequence[_FolderConfig]: List of folder configurations
138
"""
139
```
140
141
### Substitution Patterns
142
143
```python { .api }
144
class _SubPattern:
145
def __init__(self, value: str, mode: str):
146
"""
147
Individual substitution pattern with mode specification.
148
149
Parameters:
150
- value: Regular expression pattern with two capture groups
151
- mode: Substitution mode ("str" or "tuple")
152
"""
153
154
@staticmethod
155
def from_config(config: Sequence[Union[str, Mapping]]) -> Sequence["_SubPattern"]:
156
"""
157
Create substitution patterns from configuration.
158
159
Parameters:
160
- config: Pattern configuration (strings or mappings with value/mode)
161
162
Returns:
163
Sequence[_SubPattern]: List of substitution pattern objects
164
"""
165
```
166
167
## Project State Management
168
169
### State Tracking
170
171
```python { .api }
172
class _ProjectState:
173
def __init__(
174
self,
175
path: Path,
176
original_version: Optional[str],
177
version: str,
178
mode: _Mode,
179
dynamic_array: Optional[tomlkit.items.Array],
180
substitutions: Optional[MutableMapping[Path, str]] = None,
181
) -> None:
182
"""
183
Track state for a single project during version application.
184
185
Parameters:
186
- path: Path to project's pyproject.toml
187
- original_version: Original version before modification
188
- version: Applied dynamic version
189
- mode: Project configuration mode (Classic or PEP 621)
190
- dynamic_array: PEP 621 dynamic array for restoration
191
- substitutions: Map of modified files to original content
192
"""
193
```
194
195
### Global State
196
197
```python { .api }
198
class _State:
199
def __init__(self) -> None:
200
"""Global plugin state management."""
201
202
patched_core_poetry_create: bool # Whether Poetry core has been patched
203
cli_mode: bool # Whether running in CLI mode
204
projects: MutableMapping[str, _ProjectState] # Active project states
205
```
206
207
## Substitution Modes
208
209
The substitution system supports different modes for version placeholder replacement:
210
211
### String Mode (default)
212
213
```python
214
# Pattern captures quotes around version string
215
pattern = r"(^__version__\s*(?::.*?)?=\s*['\"])[^'\"]*(['\"])"
216
# Substitutes: __version__ = "1.2.3"
217
```
218
219
### Tuple Mode
220
221
```python
222
# Pattern captures parentheses around version tuple
223
pattern = r"(^__version_tuple__\s*(?::.*?)?=\s*\()[^)]*(\))"
224
# Substitutes: __version_tuple__ = (1, 2, 3)
225
# With pre-release: __version_tuple__ = (1, 2, 3, "dev0", "abc123")
226
```
227
228
## Usage Examples
229
230
### Basic Version Application
231
232
```python
233
from poetry_dynamic_versioning import _get_and_apply_version
234
from pathlib import Path
235
236
# Apply version to current project
237
project_name = _get_and_apply_version()
238
if project_name:
239
print(f"Applied version to project: {project_name}")
240
241
# Apply with specific path and options
242
project_name = _get_and_apply_version(
243
pyproject_path=Path("./my-project/pyproject.toml"),
244
retain=True, # Don't disable plugin
245
force=True, # Apply even if disabled
246
io=True # Actually modify files
247
)
248
```
249
250
### Manual Version Application
251
252
```python
253
from poetry_dynamic_versioning import (
254
_apply_version, _get_version, _get_config, _Mode
255
)
256
from pathlib import Path
257
258
# Get configuration and version
259
config = _get_config_from_path()
260
version_str, version_obj = _get_version(config)
261
262
# Apply to specific project
263
pyproject_path = Path("./pyproject.toml")
264
_apply_version(
265
name="my-project",
266
version=version_str,
267
instance=version_obj,
268
config=config,
269
pyproject_path=pyproject_path,
270
mode=_Mode.Classic,
271
retain=False
272
)
273
```
274
275
### Custom Substitution Patterns
276
277
```python
278
from poetry_dynamic_versioning import _substitute_version_in_text, _SubPattern
279
280
# Define custom patterns
281
patterns = [
282
_SubPattern(r'(VERSION = ")[^"]*(")', "str"),
283
_SubPattern(r'(version_info = \()[^)]*(\))', "tuple")
284
]
285
286
# Apply substitution to content
287
original_content = '''
288
VERSION = "0.0.0"
289
version_info = (0, 0, 0)
290
'''
291
292
new_content = _substitute_version_in_text("1.2.3", original_content, patterns)
293
print(new_content)
294
# VERSION = "1.2.3"
295
# version_info = (1, 2, 3)
296
```
297
298
### File Restoration
299
300
```python
301
from poetry_dynamic_versioning import _revert_version, _state
302
303
# Check current project states
304
for name, state in _state.projects.items():
305
print(f"Project: {name}, Modified files: {len(state.substitutions)}")
306
307
# Revert all changes
308
_revert_version(retain=False) # Re-enable plugin after revert
309
print("All version changes reverted")
310
```
311
312
### Folder Configuration
313
314
```python
315
from poetry_dynamic_versioning import _FolderConfig, _SubPattern
316
from pathlib import Path
317
318
# Create custom folder configuration
319
patterns = [_SubPattern(r'(__version__ = ")[^"]*(")', "str")]
320
folder_config = _FolderConfig(
321
path=Path("./src"),
322
files=["**/*.py"],
323
patterns=patterns
324
)
325
326
# Apply substitution to folder
327
from poetry_dynamic_versioning import _substitute_version
328
_substitute_version("my-project", "1.2.3", [folder_config])
329
```
330
331
### File Creation with Initial Content
332
333
Configuration in pyproject.toml can create files with initial content:
334
335
```toml
336
[tool.poetry-dynamic-versioning.files."src/mypackage/_version.py"]
337
initial-content = """
338
# This file is automatically generated by poetry-dynamic-versioning
339
__version__ = "0.0.0"
340
__version_tuple__ = (0, 0, 0)
341
"""
342
persistent-substitution = true
343
```
344
345
The system will create the file with initial content, then apply version substitution patterns to update the placeholders.