|
1 | 1 | """DiffSync front-end classes and logic. |
2 | 2 |
|
3 | | -Copyright (c) 2020 Network To Code, LLC <[email protected]> |
| 3 | +Copyright (c) 2020-2021 Network To Code, LLC <[email protected]> |
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