0
# Flags and Configuration
1
2
Behavioral control flags and configuration options for customizing diff calculation and synchronization behavior, including error handling, skipping patterns, and logging verbosity.
3
4
## Capabilities
5
6
### DiffSyncFlags
7
8
Flags that can be passed to sync_* or diff_* calls to affect their behavior.
9
10
```python { .api }
11
class DiffSyncFlags(enum.Flag):
12
"""Flags that can be passed to a sync_* or diff_* call to affect its behavior."""
13
14
NONE = 0
15
CONTINUE_ON_FAILURE = 0b1
16
SKIP_UNMATCHED_SRC = 0b10
17
SKIP_UNMATCHED_DST = 0b100
18
SKIP_UNMATCHED_BOTH = SKIP_UNMATCHED_SRC | SKIP_UNMATCHED_DST
19
LOG_UNCHANGED_RECORDS = 0b1000
20
```
21
22
#### Flag Descriptions
23
24
```python { .api }
25
NONE = 0
26
```
27
No special flags - default behavior.
28
29
```python { .api }
30
CONTINUE_ON_FAILURE = 0b1
31
```
32
Continue synchronizing even if failures are encountered when syncing individual models. Without this flag, any failure will stop the entire sync operation.
33
34
```python { .api }
35
SKIP_UNMATCHED_SRC = 0b10
36
```
37
Ignore objects that only exist in the source/"from" DiffSync when determining diffs and syncing. If this flag is set, no new objects will be created in the target/"to" DiffSync.
38
39
```python { .api }
40
SKIP_UNMATCHED_DST = 0b100
41
```
42
Ignore objects that only exist in the target/"to" DiffSync when determining diffs and syncing. If this flag is set, no objects will be deleted from the target/"to" DiffSync.
43
44
```python { .api }
45
SKIP_UNMATCHED_BOTH = SKIP_UNMATCHED_SRC | SKIP_UNMATCHED_DST
46
```
47
Combination flag - ignore objects that exist only in source OR only in target. Only update existing objects that are present in both.
48
49
```python { .api }
50
LOG_UNCHANGED_RECORDS = 0b1000
51
```
52
If this flag is set, a log message will be generated during synchronization for each model, even unchanged ones. By default, only models that have actual changes to synchronize will be logged. This flag is off by default to reduce verbosity but can be enabled for debugging.
53
54
#### DiffSyncFlags Usage Examples
55
56
```python
57
from diffsync import DiffSyncFlags
58
59
# Basic synchronization with default behavior
60
diff = target.sync_from(source)
61
62
# Continue sync even if some operations fail
63
diff = target.sync_from(source, flags=DiffSyncFlags.CONTINUE_ON_FAILURE)
64
65
# Only update existing objects, don't create new ones
66
diff = target.sync_from(source, flags=DiffSyncFlags.SKIP_UNMATCHED_SRC)
67
68
# Only update existing objects, don't delete missing ones
69
diff = target.sync_from(source, flags=DiffSyncFlags.SKIP_UNMATCHED_DST)
70
71
# Only update objects that exist in both source and target
72
diff = target.sync_from(source, flags=DiffSyncFlags.SKIP_UNMATCHED_BOTH)
73
74
# Enable verbose logging for debugging
75
diff = target.sync_from(source, flags=DiffSyncFlags.LOG_UNCHANGED_RECORDS)
76
77
# Combine multiple flags using bitwise OR
78
diff = target.sync_from(source,
79
flags=DiffSyncFlags.CONTINUE_ON_FAILURE | DiffSyncFlags.LOG_UNCHANGED_RECORDS)
80
```
81
82
### DiffSyncModelFlags
83
84
Flags that can be set on a DiffSyncModel class or instance to affect its usage during diff and sync operations.
85
86
```python { .api }
87
class DiffSyncModelFlags(enum.Flag):
88
"""Flags that can be set on a DiffSyncModel class or instance to affect its usage."""
89
90
NONE = 0
91
IGNORE = 0b1
92
SKIP_CHILDREN_ON_DELETE = 0b10
93
SKIP_UNMATCHED_SRC = 0b100
94
SKIP_UNMATCHED_DST = 0b1000
95
NATURAL_DELETION_ORDER = 0b10000
96
SKIP_UNMATCHED_BOTH = SKIP_UNMATCHED_SRC | SKIP_UNMATCHED_DST
97
```
98
99
#### Model Flag Descriptions
100
101
```python { .api }
102
NONE = 0
103
```
104
No special flags - default behavior.
105
106
```python { .api }
107
IGNORE = 0b1
108
```
109
Do not render diffs containing this model; do not make any changes to this model when synchronizing. Can be used to indicate a model instance that exists but should not be changed by DiffSync.
110
111
```python { .api }
112
SKIP_CHILDREN_ON_DELETE = 0b10
113
```
114
When deleting this model, do not recursively delete its children. Can be used for the case where deletion of a model results in the automatic deletion of all its children.
115
116
```python { .api }
117
SKIP_UNMATCHED_SRC = 0b100
118
```
119
Ignore the model if it only exists in the source/"from" DiffSync when determining diffs and syncing. If this flag is set, no new model will be created in the target/"to" DiffSync.
120
121
```python { .api }
122
SKIP_UNMATCHED_DST = 0b1000
123
```
124
Ignore the model if it only exists in the target/"to" DiffSync when determining diffs and syncing. If this flag is set, the model will not be deleted from the target/"to" DiffSync.
125
126
```python { .api }
127
NATURAL_DELETION_ORDER = 0b10000
128
```
129
When deleting, delete children before instances of this element. If this flag is set, the model's children will be deleted from the target/"to" DiffSync before the model instances themselves.
130
131
```python { .api }
132
SKIP_UNMATCHED_BOTH = SKIP_UNMATCHED_SRC | SKIP_UNMATCHED_DST
133
```
134
Combination flag - ignore the model if it exists only in source OR only in target.
135
136
#### DiffSyncModelFlags Usage Examples
137
138
```python
139
from diffsync import DiffSyncModel, DiffSyncModelFlags
140
141
# Set flags as class attribute
142
class ReadOnlyDevice(DiffSyncModel):
143
_modelname = "readonly_device"
144
_identifiers = ("name",)
145
_attributes = ("status",)
146
147
# This model will be ignored during sync operations
148
model_flags = DiffSyncModelFlags.IGNORE
149
150
name: str
151
status: str
152
153
# Set flags dynamically on instance
154
device = Device(name="critical_device", vendor="cisco")
155
device.model_flags = DiffSyncModelFlags.IGNORE
156
157
# Model that automatically deletes children when deleted
158
class Site(DiffSyncModel):
159
_modelname = "site"
160
_identifiers = ("name",)
161
_children = {"device": "devices"}
162
163
# When site is deleted, devices are automatically removed by the system
164
model_flags = DiffSyncModelFlags.SKIP_CHILDREN_ON_DELETE
165
166
name: str
167
devices: List[str] = []
168
169
# Model with natural deletion order
170
class Database(DiffSyncModel):
171
_modelname = "database"
172
_identifiers = ("name",)
173
_children = {"table": "tables"}
174
175
# Delete tables before deleting database
176
model_flags = DiffSyncModelFlags.NATURAL_DELETION_ORDER
177
178
name: str
179
tables: List[str] = []
180
181
# Conditional flags based on instance state
182
class Device(DiffSyncModel):
183
_modelname = "device"
184
_identifiers = ("name",)
185
_attributes = ("status", "maintenance_mode")
186
187
name: str
188
status: str
189
maintenance_mode: bool = False
190
191
def __post_init__(self):
192
# Don't sync devices in maintenance mode
193
if self.maintenance_mode:
194
self.model_flags = DiffSyncModelFlags.IGNORE
195
```
196
197
### DiffSyncStatus
198
199
Enumeration of status values that can be set on a DiffSyncModel's status to indicate the result of create/update/delete operations.
200
201
```python { .api }
202
class DiffSyncStatus(enum.Enum):
203
"""Flag values to set as a DiffSyncModel's _status when performing a sync; values are logged by DiffSyncSyncer."""
204
205
UNKNOWN = "unknown"
206
SUCCESS = "success"
207
FAILURE = "failure"
208
ERROR = "error"
209
```
210
211
#### Status Usage Examples
212
213
```python
214
from diffsync import DiffSyncStatus
215
216
class NetworkDevice(DiffSyncModel):
217
_modelname = "device"
218
_identifiers = ("name",)
219
_attributes = ("ip_address",)
220
221
name: str
222
ip_address: str
223
224
@classmethod
225
def create(cls, adapter, ids, attrs):
226
device = super().create(adapter, ids, attrs)
227
228
try:
229
# Attempt to configure device
230
result = configure_network_device(device.name, device.ip_address)
231
if result.success:
232
device.set_status(DiffSyncStatus.SUCCESS, "Device configured successfully")
233
else:
234
device.set_status(DiffSyncStatus.FAILURE, f"Configuration failed: {result.error}")
235
except Exception as e:
236
device.set_status(DiffSyncStatus.ERROR, f"Unexpected error: {e}")
237
238
return device
239
240
def update(self, attrs):
241
device = super().update(attrs)
242
243
if 'ip_address' in attrs:
244
try:
245
update_device_ip(self.name, self.ip_address)
246
device.set_status(DiffSyncStatus.SUCCESS, "IP address updated")
247
except ValidationError:
248
device.set_status(DiffSyncStatus.FAILURE, "Invalid IP address")
249
except NetworkError as e:
250
device.set_status(DiffSyncStatus.ERROR, f"Network error: {e}")
251
252
return device
253
254
# Check status after sync operations
255
diff = target.sync_from(source)
256
for element in diff.get_children():
257
if element.action:
258
try:
259
obj = target.get(element.type, element.keys)
260
status, message = obj.get_status()
261
print(f"{element.type} {element.name}: {status.value} - {message}")
262
except ObjectNotFound:
263
print(f"{element.type} {element.name}: Object not found after sync")
264
```
265
266
### Configuration Patterns
267
268
#### Environment-Based Configuration
269
270
```python
271
import os
272
from diffsync import DiffSyncFlags
273
274
def get_sync_flags():
275
"""Get sync flags based on environment variables."""
276
flags = DiffSyncFlags.NONE
277
278
if os.getenv("DIFFSYNC_CONTINUE_ON_FAILURE", "false").lower() == "true":
279
flags |= DiffSyncFlags.CONTINUE_ON_FAILURE
280
281
if os.getenv("DIFFSYNC_SKIP_CREATES", "false").lower() == "true":
282
flags |= DiffSyncFlags.SKIP_UNMATCHED_SRC
283
284
if os.getenv("DIFFSYNC_SKIP_DELETES", "false").lower() == "true":
285
flags |= DiffSyncFlags.SKIP_UNMATCHED_DST
286
287
if os.getenv("DIFFSYNC_VERBOSE", "false").lower() == "true":
288
flags |= DiffSyncFlags.LOG_UNCHANGED_RECORDS
289
290
return flags
291
292
# Usage
293
flags = get_sync_flags()
294
diff = target.sync_from(source, flags=flags)
295
```
296
297
#### Configuration Classes
298
299
```python
300
from dataclasses import dataclass
301
from diffsync import DiffSyncFlags, DiffSyncModelFlags
302
303
@dataclass
304
class SyncConfig:
305
"""Configuration for DiffSync operations."""
306
continue_on_failure: bool = False
307
skip_creates: bool = False
308
skip_deletes: bool = False
309
verbose_logging: bool = False
310
dry_run: bool = False
311
312
@property
313
def flags(self) -> DiffSyncFlags:
314
"""Convert configuration to DiffSyncFlags."""
315
flags = DiffSyncFlags.NONE
316
317
if self.continue_on_failure:
318
flags |= DiffSyncFlags.CONTINUE_ON_FAILURE
319
if self.skip_creates:
320
flags |= DiffSyncFlags.SKIP_UNMATCHED_SRC
321
if self.skip_deletes:
322
flags |= DiffSyncFlags.SKIP_UNMATCHED_DST
323
if self.verbose_logging:
324
flags |= DiffSyncFlags.LOG_UNCHANGED_RECORDS
325
326
return flags
327
328
# Usage
329
config = SyncConfig(
330
continue_on_failure=True,
331
verbose_logging=True
332
)
333
334
if config.dry_run:
335
# Just calculate diff without applying
336
diff = target.diff_from(source)
337
print("Dry run - would apply these changes:")
338
print(diff.str())
339
else:
340
# Apply changes
341
diff = target.sync_from(source, flags=config.flags)
342
```
343
344
#### Conditional Flag Application
345
346
```python
347
def smart_sync(source_adapter, target_adapter, safety_mode=True):
348
"""Perform sync with intelligent flag selection based on conditions."""
349
350
# Start with basic flags
351
flags = DiffSyncFlags.NONE
352
353
# In safety mode, be more conservative
354
if safety_mode:
355
flags |= DiffSyncFlags.CONTINUE_ON_FAILURE
356
flags |= DiffSyncFlags.LOG_UNCHANGED_RECORDS
357
358
# Calculate diff first to analyze changes
359
diff = target_adapter.diff_from(source_adapter)
360
summary = diff.summary()
361
362
# If there are many deletions, ask for confirmation
363
if summary['delete'] > 10:
364
print(f"Warning: {summary['delete']} objects will be deleted")
365
if input("Continue? (y/n): ").lower() != 'y':
366
flags |= DiffSyncFlags.SKIP_UNMATCHED_DST
367
368
# If there are many creates, be cautious about resources
369
if summary['create'] > 100:
370
print(f"Warning: {summary['create']} objects will be created")
371
# Could add resource checks here
372
373
# Perform sync with selected flags
374
return target_adapter.sync_from(source_adapter, flags=flags, diff=diff)
375
```
376
377
### Logging Configuration
378
379
DiffSync uses structured logging through the `structlog` library. Configure logging verbosity and format using the logging utilities.
380
381
```python { .api }
382
def enable_console_logging(verbosity: int = 0) -> None:
383
"""
384
Enable formatted logging to console with the specified verbosity.
385
386
Args:
387
verbosity: 0 for WARNING logs, 1 for INFO logs, 2 for DEBUG logs
388
"""
389
```
390
391
#### Logging Usage Examples
392
393
```python
394
from diffsync.logging import enable_console_logging
395
396
# Enable INFO level logging
397
enable_console_logging(verbosity=1)
398
399
# Enable DEBUG level logging for detailed troubleshooting
400
enable_console_logging(verbosity=2)
401
402
# Perform sync with verbose logging
403
diff = target.sync_from(source, flags=DiffSyncFlags.LOG_UNCHANGED_RECORDS)
404
```
405
406
### DiffSyncActions
407
408
Constants representing valid actions for DiffSyncModel operations during synchronization.
409
410
```python { .api }
411
class DiffSyncActions:
412
"""List of valid Action for DiffSyncModel."""
413
414
CREATE = "create"
415
UPDATE = "update"
416
DELETE = "delete"
417
SKIP = "skip"
418
NO_CHANGE = None
419
```
420
421
These constants are used internally by DiffSync to represent the different types of operations that can be performed on models during synchronization. Import from the enum module:
422
423
```python
424
from diffsync.enum import DiffSyncActions
425
426
# Usage example - these values appear in DiffElement.action property
427
for element in diff.get_children():
428
if element.action == DiffSyncActions.CREATE:
429
print(f"Will create {element.name}")
430
elif element.action == DiffSyncActions.UPDATE:
431
print(f"Will update {element.name}")
432
elif element.action == DiffSyncActions.DELETE:
433
print(f"Will delete {element.name}")
434
```
435
436
## Types
437
438
```python { .api }
439
import enum
440
from typing import Union
441
442
# Flag types for type hints
443
SyncFlags = Union[DiffSyncFlags, int]
444
ModelFlags = Union[DiffSyncModelFlags, int]
445
446
# Status enumeration
447
StatusValue = DiffSyncStatus
448
```