|
1 | 1 | """DiffSync front-end classes and logic.
|
2 | 2 |
|
3 |
| -Copyright (c) 2020 Network To Code, LLC <info@networktocode.com> |
| 3 | +Copyright (c) 2020-2021 Network To Code, LLC <info@networktocode.com> |
4 | 4 |
|
5 | 5 | Licensed under the Apache License, Version 2.0 (the "License");
|
6 | 6 | you may not use this file except in compliance with the License.
|
|
16 | 16 | """
|
17 | 17 | from collections import defaultdict
|
18 | 18 | from inspect import isclass
|
19 |
| -from typing import ClassVar, Dict, List, Mapping, MutableMapping, Optional, Text, Tuple, Type, Union |
| 19 | +from typing import Callable, ClassVar, Dict, List, Mapping, MutableMapping, Optional, Text, Tuple, Type, Union |
20 | 20 |
|
21 | 21 | from pydantic import BaseModel, PrivateAttr
|
22 | 22 | import structlog # type: ignore
|
@@ -359,7 +359,7 @@ def remove_child(self, child: "DiffSyncModel"):
|
359 | 359 | class DiffSync:
|
360 | 360 | """Class for storing a group of DiffSyncModel instances and diffing/synchronizing to another DiffSync instance."""
|
361 | 361 |
|
362 |
| - # Add mapping of names to specific model classes here: |
| 362 | + # In any subclass, you would add mapping of names to specific model classes here: |
363 | 363 | # modelname1 = MyModelClass1
|
364 | 364 | # modelname2 = MyModelClass2
|
365 | 365 |
|
@@ -418,6 +418,10 @@ def __str__(self):
|
418 | 418 | def __repr__(self):
|
419 | 419 | return f"<{str(self)}>"
|
420 | 420 |
|
| 421 | + def __len__(self): |
| 422 | + """Total number of elements stored in self._data.""" |
| 423 | + return sum(len(entries) for entries in self._data.values()) |
| 424 | + |
421 | 425 | def load(self):
|
422 | 426 | """Load all desired data from whatever backend data source into this instance."""
|
423 | 427 | # No-op in this generic class
|
@@ -451,29 +455,45 @@ def str(self, indent: int = 0) -> str:
|
451 | 455 | # Synchronization between DiffSync instances
|
452 | 456 | # ------------------------------------------------------------------------------
|
453 | 457 |
|
454 |
| - def sync_from(self, source: "DiffSync", diff_class: Type[Diff] = Diff, flags: DiffSyncFlags = DiffSyncFlags.NONE): |
| 458 | + def sync_from( |
| 459 | + self, |
| 460 | + source: "DiffSync", |
| 461 | + diff_class: Type[Diff] = Diff, |
| 462 | + flags: DiffSyncFlags = DiffSyncFlags.NONE, |
| 463 | + callback: Optional[Callable[[Text, int, int], None]] = None, |
| 464 | + ): |
455 | 465 | """Synchronize data from the given source DiffSync object into the current DiffSync object.
|
456 | 466 |
|
457 | 467 | Args:
|
458 | 468 | source (DiffSync): object to sync data from into this one
|
459 | 469 | diff_class (class): Diff or subclass thereof to use to calculate the diffs to use for synchronization
|
460 | 470 | flags (DiffSyncFlags): Flags influencing the behavior of this sync.
|
| 471 | + callback (function): Function with parameters (stage, current, total), to be called at intervals as the |
| 472 | + calculation of the diff and subsequent sync proceed. |
461 | 473 | """
|
462 |
| - diff = self.diff_from(source, diff_class=diff_class, flags=flags) |
463 |
| - syncer = DiffSyncSyncer(diff=diff, src_diffsync=source, dst_diffsync=self, flags=flags) |
| 474 | + diff = self.diff_from(source, diff_class=diff_class, flags=flags, callback=callback) |
| 475 | + syncer = DiffSyncSyncer(diff=diff, src_diffsync=source, dst_diffsync=self, flags=flags, callback=callback) |
464 | 476 | result = syncer.perform_sync()
|
465 | 477 | if result:
|
466 | 478 | self.sync_complete(source, diff, flags, syncer.base_logger)
|
467 | 479 |
|
468 |
| - def sync_to(self, target: "DiffSync", diff_class: Type[Diff] = Diff, flags: DiffSyncFlags = DiffSyncFlags.NONE): |
| 480 | + def sync_to( |
| 481 | + self, |
| 482 | + target: "DiffSync", |
| 483 | + diff_class: Type[Diff] = Diff, |
| 484 | + flags: DiffSyncFlags = DiffSyncFlags.NONE, |
| 485 | + callback: Optional[Callable[[Text, int, int], None]] = None, |
| 486 | + ): |
469 | 487 | """Synchronize data from the current DiffSync object into the given target DiffSync object.
|
470 | 488 |
|
471 | 489 | Args:
|
472 | 490 | target (DiffSync): object to sync data into from this one.
|
473 | 491 | diff_class (class): Diff or subclass thereof to use to calculate the diffs to use for synchronization
|
474 | 492 | flags (DiffSyncFlags): Flags influencing the behavior of this sync.
|
| 493 | + callback (function): Function with parameters (stage, current, total), to be called at intervals as the |
| 494 | + calculation of the diff and subsequent sync proceed. |
475 | 495 | """
|
476 |
| - target.sync_from(self, diff_class=diff_class, flags=flags) |
| 496 | + target.sync_from(self, diff_class=diff_class, flags=flags, callback=callback) |
477 | 497 |
|
478 | 498 | def sync_complete(
|
479 | 499 | self,
|
@@ -502,29 +522,43 @@ def sync_complete(
|
502 | 522 | # ------------------------------------------------------------------------------
|
503 | 523 |
|
504 | 524 | def diff_from(
|
505 |
| - self, source: "DiffSync", diff_class: Type[Diff] = Diff, flags: DiffSyncFlags = DiffSyncFlags.NONE |
| 525 | + self, |
| 526 | + source: "DiffSync", |
| 527 | + diff_class: Type[Diff] = Diff, |
| 528 | + flags: DiffSyncFlags = DiffSyncFlags.NONE, |
| 529 | + callback: Optional[Callable[[Text, int, int], None]] = None, |
506 | 530 | ) -> Diff:
|
507 | 531 | """Generate a Diff describing the difference from the other DiffSync to this one.
|
508 | 532 |
|
509 | 533 | Args:
|
510 | 534 | source (DiffSync): Object to diff against.
|
511 | 535 | diff_class (class): Diff or subclass thereof to use for diff calculation and storage.
|
512 | 536 | flags (DiffSyncFlags): Flags influencing the behavior of this diff operation.
|
| 537 | + callback (function): Function with parameters (stage, current, total), to be called at intervals as the |
| 538 | + calculation of the diff proceeds. |
513 | 539 | """
|
514 |
| - differ = DiffSyncDiffer(src_diffsync=source, dst_diffsync=self, flags=flags, diff_class=diff_class) |
| 540 | + differ = DiffSyncDiffer( |
| 541 | + src_diffsync=source, dst_diffsync=self, flags=flags, diff_class=diff_class, callback=callback |
| 542 | + ) |
515 | 543 | return differ.calculate_diffs()
|
516 | 544 |
|
517 | 545 | def diff_to(
|
518 |
| - self, target: "DiffSync", diff_class: Type[Diff] = Diff, flags: DiffSyncFlags = DiffSyncFlags.NONE |
| 546 | + self, |
| 547 | + target: "DiffSync", |
| 548 | + diff_class: Type[Diff] = Diff, |
| 549 | + flags: DiffSyncFlags = DiffSyncFlags.NONE, |
| 550 | + callback: Optional[Callable[[Text, int, int], None]] = None, |
519 | 551 | ) -> Diff:
|
520 | 552 | """Generate a Diff describing the difference from this DiffSync to another one.
|
521 | 553 |
|
522 | 554 | Args:
|
523 | 555 | target (DiffSync): Object to diff against.
|
524 | 556 | diff_class (class): Diff or subclass thereof to use for diff calculation and storage.
|
525 | 557 | flags (DiffSyncFlags): Flags influencing the behavior of this diff operation.
|
| 558 | + callback (function): Function with parameters (stage, current, total), to be called at intervals as the |
| 559 | + calculation of the diff proceeds. |
526 | 560 | """
|
527 |
| - return target.diff_from(self, diff_class=diff_class, flags=flags) |
| 561 | + return target.diff_from(self, diff_class=diff_class, flags=flags, callback=callback) |
528 | 562 |
|
529 | 563 | # ------------------------------------------------------------------------------
|
530 | 564 | # Object Storage Management
|
@@ -567,21 +601,21 @@ def get(
|
567 | 601 | raise ObjectNotFound(f"{modelname} {uid} not present in {self.name}")
|
568 | 602 | return self._data[modelname][uid]
|
569 | 603 |
|
570 |
| - def get_all(self, obj: Union[Text, DiffSyncModel, Type[DiffSyncModel]]): |
| 604 | + def get_all(self, obj: Union[Text, DiffSyncModel, Type[DiffSyncModel]]) -> List[DiffSyncModel]: |
571 | 605 | """Get all objects of a given type.
|
572 | 606 |
|
573 | 607 | Args:
|
574 | 608 | obj: DiffSyncModel class or instance, or modelname string, that defines the type of the objects to retrieve
|
575 | 609 |
|
576 | 610 | Returns:
|
577 |
| - ValuesList[DiffSyncModel]: List of Object |
| 611 | + List[DiffSyncModel]: List of Object |
578 | 612 | """
|
579 | 613 | if isinstance(obj, str):
|
580 | 614 | modelname = obj
|
581 | 615 | else:
|
582 | 616 | modelname = obj.get_type()
|
583 | 617 |
|
584 |
| - return self._data[modelname].values() |
| 618 | + return list(self._data[modelname].values()) |
585 | 619 |
|
586 | 620 | def get_by_uids(
|
587 | 621 | self, uids: List[Text], obj: Union[Text, DiffSyncModel, Type[DiffSyncModel]]
|
|
0 commit comments