diff --git a/diffsync/diff.py b/diffsync/diff.py index 412924ea..70029c84 100644 --- a/diffsync/diff.py +++ b/diffsync/diff.py @@ -20,6 +20,7 @@ from .exceptions import ObjectAlreadyExists from .utils import intersection, OrderedDefaultDict +from .enum import DiffSyncActions class Diff: @@ -105,9 +106,9 @@ def order_children_default(cls, children: Mapping) -> Iterator["DiffElement"]: def summary(self) -> Mapping[Text, int]: """Build a dict summary of this Diff and its child DiffElements.""" summary = { - "create": 0, - "update": 0, - "delete": 0, + DiffSyncActions.CREATE.value: 0, + DiffSyncActions.UPDATE.value: 0, + DiffSyncActions.DELETE.value: 0, "no-change": 0, } for child in self.get_children(): @@ -220,22 +221,22 @@ def __len__(self): return total @property - def action(self) -> Optional[Text]: + def action(self) -> Optional[DiffSyncActions]: """Action, if any, that should be taken to remediate the diffs described by this element. Returns: - str: "create", "update", "delete", or None + DiffSyncActions ("create", "update", "delete", or None) """ if self.source_attrs is not None and self.dest_attrs is None: - return "create" + return DiffSyncActions.CREATE if self.source_attrs is None and self.dest_attrs is not None: - return "delete" + return DiffSyncActions.DELETE if ( self.source_attrs is not None and self.dest_attrs is not None and any(self.source_attrs[attr_key] != self.dest_attrs[attr_key] for attr_key in self.get_attrs_keys()) ): - return "update" + return DiffSyncActions.UPDATE return None @@ -328,13 +329,13 @@ def has_diffs(self, include_children: bool = True) -> bool: def summary(self) -> Mapping[Text, int]: """Build a summary of this DiffElement and its children.""" summary = { - "create": 0, - "update": 0, - "delete": 0, + DiffSyncActions.CREATE.value: 0, + DiffSyncActions.UPDATE.value: 0, + DiffSyncActions.DELETE.value: 0, "no-change": 0, } if self.action: - summary[self.action] += 1 + summary[self.action.value] += 1 else: summary["no-change"] += 1 child_summary = self.child_diff.summary() diff --git a/diffsync/enum.py b/diffsync/enum.py index 29c1046e..5cd60ff7 100644 --- a/diffsync/enum.py +++ b/diffsync/enum.py @@ -73,3 +73,12 @@ class DiffSyncStatus(enum.Enum): SUCCESS = "success" FAILURE = "failure" ERROR = "error" + + +class DiffSyncActions(enum.Enum): + """List of valid Action for DiffSyncModel.""" + + CREATE = "create" + UPDATE = "update" + DELETE = "delete" + NO_CHANGE = None diff --git a/diffsync/helpers.py b/diffsync/helpers.py index 9d509226..11886407 100644 --- a/diffsync/helpers.py +++ b/diffsync/helpers.py @@ -20,7 +20,7 @@ import structlog # type: ignore from .diff import Diff, DiffElement -from .enum import DiffSyncModelFlags, DiffSyncFlags, DiffSyncStatus +from .enum import DiffSyncModelFlags, DiffSyncFlags, DiffSyncStatus, DiffSyncActions from .exceptions import ObjectNotFound, ObjectNotCreated, ObjectNotUpdated, ObjectNotDeleted, ObjectCrudException from .utils import intersection, symmetric_difference @@ -296,7 +296,7 @@ def __init__( # pylint: disable=too-many-arguments # Local state maintained during synchronization self.logger: structlog.BoundLogger = self.base_logger self.model_class: Type["DiffSyncModel"] - self.action: Optional[str] = None + self.action: Optional[DiffSyncActions] = None def incr_elements_processed(self, delta: int = 1): """Increment self.elements_processed, then call self.callback if present.""" @@ -353,11 +353,11 @@ def sync_diff_element(self, element: DiffElement, parent_model: "DiffSyncModel" self.logger.warning("No object resulted from sync, will not process child objects.") return changed - if self.action == "create": + if self.action == DiffSyncActions.CREATE: if parent_model: parent_model.add_child(model) self.dst_diffsync.add(model) - elif self.action == "delete": + elif self.action == DiffSyncActions.DELETE: if parent_model: parent_model.remove_child(model) if model.model_flags & DiffSyncModelFlags.SKIP_CHILDREN_ON_DELETE: @@ -390,16 +390,16 @@ def sync_model( return (False, model) try: - self.logger.debug(f"Attempting model {self.action}") - if self.action == "create": + self.logger.debug(f"Attempting model {self.action.value}") + if self.action == DiffSyncActions.CREATE: if model is not None: raise ObjectNotCreated(f"Failed to create {self.model_class.get_type()} {ids} - it already exists!") model = self.model_class.create(diffsync=self.dst_diffsync, ids=ids, attrs=attrs) - elif self.action == "update": + elif self.action == DiffSyncActions.UPDATE: if model is None: raise ObjectNotUpdated(f"Failed to update {self.model_class.get_type()} {ids} - not found!") model = model.update(attrs=attrs) - elif self.action == "delete": + elif self.action == DiffSyncActions.DELETE: if model is None: raise ObjectNotDeleted(f"Failed to delete {self.model_class.get_type()} {ids} - not found!") model = model.delete() @@ -410,7 +410,7 @@ def sync_model( status, message = model.get_status() else: status = DiffSyncStatus.FAILURE - message = f"{self.model_class.get_type()} {self.action} did not return the model object." + message = f"{self.model_class.get_type()} {self.action.value} did not return the model object." except ObjectCrudException as exception: status = DiffSyncStatus.ERROR @@ -424,7 +424,7 @@ def sync_model( return (True, model) - def log_sync_status(self, action: Optional[str], status: DiffSyncStatus, message: str): + def log_sync_status(self, action: Optional[DiffSyncActions], status: DiffSyncStatus, message: str): """Log the current sync status at the appropriate verbosity with appropriate context. Helper method to `sync_diff_element`/`sync_model`. diff --git a/tests/unit/test_diffsync.py b/tests/unit/test_diffsync.py index 43068ecc..ea15da1e 100644 --- a/tests/unit/test_diffsync.py +++ b/tests/unit/test_diffsync.py @@ -619,7 +619,7 @@ def check_sync_logs_against_diff(diffsync, diff, log, errors_permitted=False): assert { ("action", element.action), - ("event", f"Attempting model {element.action}"), + ("event", f"Attempting model {element.action.value}"), ("level", "debug"), } <= begin_event.items() # attrs_diffs dict is unhashable so we can't include it in the above set comparison @@ -632,7 +632,7 @@ def check_sync_logs_against_diff(diffsync, diff, log, errors_permitted=False): if complete_event["status"] == "success": assert { ("action", element.action), - ("event", f"{element.action.title()}d successfully"), + ("event", f"{element.action.value.title()}d successfully"), ("level", "info"), ("status", "success"), } <= complete_event.items()