diffsync 2.0.1__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diffsync-2.0.1 → diffsync-2.2.0}/LICENSE +4 -4
- {diffsync-2.0.1 → diffsync-2.2.0}/PKG-INFO +40 -24
- {diffsync-2.0.1 → diffsync-2.2.0}/README.md +33 -16
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/__init__.py +31 -18
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/diff.py +5 -6
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/exceptions.py +2 -1
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/helpers.py +11 -9
- diffsync-2.2.0/diffsync/log.py +74 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/404.html +1505 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/install.html +1628 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/index.html +1607 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.0.html +1637 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.1.html +1678 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.10.html +1665 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.2.html +1656 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.3.html +1656 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.4.html +1738 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.5.html +1678 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.6.html +1656 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.7.html +1686 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.8.html +1671 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_1.9.html +1662 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_2.0.html +1707 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_2.1.html +1671 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/release_notes/version_2.2.html +1636 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/uninstall.html +1619 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/admin/upgrade.html +1619 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/_mkdocstrings.css +143 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/extra.css +152 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/favicon.ico +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/images/favicon.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/bundle.56ea9cef.min.js +16 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/bundle.56ea9cef.min.js.map +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/glightbox.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ar.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.da.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.de.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.du.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.el.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.es.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.fi.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.fr.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.he.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.hi.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.hu.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.hy.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.it.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ja.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.jp.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.kn.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ko.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.multi.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.nl.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.no.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.pt.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ro.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ru.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.sa.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.stemmer.support.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.sv.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.ta.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.te.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.th.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.tr.min.js +18 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.vi.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/min/lunr.zh.min.js +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/tinyseg.js +206 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/lunr/wordcut.js +6708 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/workers/search.d50fe291.min.js +42 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/javascripts/workers/search.d50fe291.min.js.map +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/networktocode_bw.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/networktocode_logo.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/overrides/partials/copyright.html +21 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/stylesheets/glightbox.min.css +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/stylesheets/main.342714a4.min.css +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/stylesheets/main.342714a4.min.css.map +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/stylesheets/palette.06af60db.min.css +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/assets/stylesheets/palette.06af60db.min.css.map +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/__init__.html +6026 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/diff.html +3063 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/enum.html +2343 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/exceptions.html +2226 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/helpers.html +2423 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/log.html +1796 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/logging.html +1770 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/store/__init__.html +2934 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/store/local.html +2376 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/store/redis.html +2393 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/code-reference/diffsync/utils.html +2022 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/dev/arch_decision.html +1617 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/dev/contributing.html +1775 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/dev/dev_environment.html +1913 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/dev/extending.html +1617 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/dev/release_checklist.html +2037 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/generate_code_reference_pages.py +38 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/images/diffsync_components.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/images/diffsync_diff_creation.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/images/diffsync_sync.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/images/networktocode_logo.svg +150 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/images/preorder-tree-traversal.drawio.png +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/index.html +1906 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/objects.inv +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/requirements.txt +5 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/search/search_index.json +1 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/sitemap.xml +179 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/sitemap.xml.gz +0 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.diff.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.enum.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.exceptions.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.helpers.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.logging.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.rst +26 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.store.local.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.store.redis.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.store.rst +14 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/api/diffsync.utils.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/conf.py +99 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/core_engine/01-flags.html +1989 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/core_engine/02-customize-diff-class.html +1734 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/core_engine/03-store.html +1729 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/core_engine/index.rst +11 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/examples/index.rst +12 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/getting_started/01-getting-started.html +1861 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/getting_started/index.rst +5 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/index.rst +22 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/license/index.rst +5 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/overview/index.rst +7 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/static/schema-page.css +62 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/static/theme_overrides.css +13 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/template/api/module.rst_t +9 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/template/api/package.rst_t +51 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/upgrading/01-upgrading-to-2.0.html +1721 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/source/upgrading/index.rst +5 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/user/faq.html +1616 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/user/lib_getting_started.html +1724 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/user/lib_overview.html +1722 -0
- diffsync-2.2.0/diffsync/static/diffsync/docs/user/lib_use_cases.html +1718 -0
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/store/__init__.py +4 -3
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/store/local.py +2 -3
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/store/redis.py +7 -6
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/utils.py +3 -2
- diffsync-2.2.0/pyproject.toml +235 -0
- diffsync-2.0.1/CHANGELOG.md +0 -198
- diffsync-2.0.1/pyproject.toml +0 -113
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/enum.py +0 -0
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/logging.py +0 -0
- {diffsync-2.0.1 → diffsync-2.2.0}/diffsync/py.typed +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
Apache Software License 2.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Network to Code, LLC
|
|
3
4
|
|
|
4
5
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
6
|
you may not use this file except in compliance with the License.
|
|
6
|
-
|
|
7
7
|
You may obtain a copy of the License at
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
10
|
|
|
11
11
|
Unless required by applicable law or agreed to in writing, software
|
|
12
12
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: diffsync
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Library to easily sync/diff/update 2 different data sources
|
|
5
|
-
Home-page: https://diffsync.readthedocs.io
|
|
6
5
|
License: Apache-2.0
|
|
7
6
|
Keywords: source-of-truth,synchronization
|
|
8
7
|
Author: Network to Code, LLC
|
|
9
8
|
Author-email: info@networktocode.com
|
|
10
|
-
Requires-Python: >=3.
|
|
9
|
+
Requires-Python: >=3.10,<3.14
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
11
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
13
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Provides-Extra: redis
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist: packaging (>=21.3,<24.0)
|
|
19
|
+
Requires-Dist: packaging (>=21.3)
|
|
22
20
|
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
|
|
23
21
|
Requires-Dist: redis (>=4.3,<5.0) ; extra == "redis"
|
|
24
22
|
Requires-Dist: structlog (>=20.1.0)
|
|
25
23
|
Requires-Dist: typing-extensions (>=4.0.1) ; python_version < "3.11"
|
|
26
24
|
Project-URL: Documentation, https://diffsync.readthedocs.io
|
|
25
|
+
Project-URL: Homepage, https://diffsync.readthedocs.io
|
|
27
26
|
Project-URL: Repository, https://github.com/networktocode/diffsync
|
|
28
27
|
Description-Content-Type: text/markdown
|
|
29
28
|
|
|
@@ -33,7 +32,7 @@ DiffSync is a utility library that can be used to compare and synchronize differ
|
|
|
33
32
|
|
|
34
33
|
For example, it can be used to compare a list of devices from 2 inventory systems and, if required, synchronize them in either direction.
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
## Primary Use Cases
|
|
37
36
|
|
|
38
37
|
DiffSync is at its most useful when you have multiple sources or sets of data to compare and/or synchronize, and especially if any of the following are true:
|
|
39
38
|
|
|
@@ -42,7 +41,7 @@ DiffSync is at its most useful when you have multiple sources or sets of data to
|
|
|
42
41
|
- If various types of data in your data set naturally form a tree-like or parent-child relationship with other data.
|
|
43
42
|
- If the different data sets have some attributes in common and other attributes that are exclusive to one or the other.
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
## Overview of DiffSync
|
|
46
45
|
|
|
47
46
|
DiffSync acts as an intermediate translation layer between all of the data sets you are diffing and/or syncing. In practical terms, this means that to use DiffSync, you will define a set of data models as well as the “adapters” needed to translate between each base data source and the data model. In Python terms, the adapters will be subclasses of the `Adapter` class, and each data model class will be a subclass of the `DiffSyncModel` class.
|
|
48
47
|
|
|
@@ -57,7 +56,7 @@ You can also ask DiffSync to “sync” one data set onto the other, and it will
|
|
|
57
56
|
|
|
58
57
|

|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
## Simple Example
|
|
61
60
|
|
|
62
61
|
```python
|
|
63
62
|
A = DiffSyncSystemA()
|
|
@@ -79,34 +78,51 @@ A.sync_to(B)
|
|
|
79
78
|
|
|
80
79
|
> You may wish to peruse the `diffsync` [GitHub topic](https://github.com/topics/diffsync) for examples of projects using this library.
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
## Documentation
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
Full documentation for this library can be found over on the [Diffsync Docs](https://diffsync.readthedocs.io/) website:
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
- [User Guide](https://diffsync.readthedocs.io/user/app_overview/) - Overview, Using the Library, Getting Started.
|
|
86
|
+
- [Administrator Guide](https://diffsync.readthedocs.io/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library.
|
|
87
|
+
- [Developer Guide](https://diffsync.readthedocs.io/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide.
|
|
88
|
+
- [Release Notes / Changelog](https://diffsync.readthedocs.io/admin/release_notes/).
|
|
89
|
+
- [Frequently Asked Questions](https://diffsync.readthedocs.io/user/faq/).
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
## Installation
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
### Option 1: Install from PyPI
|
|
94
|
+
|
|
95
|
+
```shell
|
|
96
|
+
pip install diffsync
|
|
92
97
|
```
|
|
93
98
|
|
|
94
99
|
### Option 2: Install from a GitHub branch, such as main as shown below.
|
|
100
|
+
|
|
101
|
+
```shell
|
|
102
|
+
pip install git+https://github.com/networktocode/diffsync.git@main
|
|
95
103
|
```
|
|
96
|
-
$ pip install git+https://github.com/networktocode/diffsync.git@main
|
|
97
|
-
```
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
## Contributing
|
|
106
|
+
|
|
100
107
|
Pull requests are welcomed and automatically built and tested against multiple versions of Python through GitHub Actions.
|
|
101
108
|
|
|
102
|
-
The project is following Network to Code software development guidelines and
|
|
109
|
+
The project is following Network to Code software development guidelines and is leveraging the following:
|
|
103
110
|
|
|
104
|
-
-
|
|
111
|
+
- Ruff, mypy for Python linting, formatting and type hint checking.
|
|
105
112
|
- pytest, coverage, and unittest for unit tests.
|
|
106
113
|
|
|
107
114
|
You can ensure your contribution adheres to these checks by running `invoke tests` from the CLI.
|
|
108
115
|
The command `invoke build` builds a docker container with all the necessary dependencies (including the redis backend) locally to facilitate the execution of these tests.
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
## Contributing to the Documentation
|
|
118
|
+
|
|
119
|
+
You can find all the Markdown source for the App documentation under the [`docs`](https://github.com/networktocode/diffsync/tree/develop/docs) folder in this repository. For simple edits, a Markdown capable editor is sufficient: clone the repository and edit away.
|
|
120
|
+
|
|
121
|
+
If you need to view the fully-generated documentation site, you can build it with [MkDocs](https://www.mkdocs.org/). A container hosting the documentation can be started using the `invoke` commands (details in the [Development Environment Guide](https://diffsync/dev/dev_environment/#docker-development-environment)) on [http://localhost:8001](http://localhost:8001). Using this container, as your changes to the documentation are saved, they will be automatically rebuilt and any pages currently being viewed will be reloaded in your browser.
|
|
122
|
+
|
|
123
|
+
Any PRs with fixes or improvements are very welcome!
|
|
124
|
+
|
|
125
|
+
## Questions
|
|
126
|
+
|
|
127
|
+
For any questions or comments, please check the [FAQ](https://diffsync.readthedocs.io/en/latest/user/faq/) first. Feel free to also swing by the [Network to Code Slack](https://networktocode.slack.com/) (channel `#networktocode`), sign up [here](http://slack.networktocode.com/) if you don't have an account.
|
|
112
128
|
|
|
@@ -4,7 +4,7 @@ DiffSync is a utility library that can be used to compare and synchronize differ
|
|
|
4
4
|
|
|
5
5
|
For example, it can be used to compare a list of devices from 2 inventory systems and, if required, synchronize them in either direction.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Primary Use Cases
|
|
8
8
|
|
|
9
9
|
DiffSync is at its most useful when you have multiple sources or sets of data to compare and/or synchronize, and especially if any of the following are true:
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ DiffSync is at its most useful when you have multiple sources or sets of data to
|
|
|
13
13
|
- If various types of data in your data set naturally form a tree-like or parent-child relationship with other data.
|
|
14
14
|
- If the different data sets have some attributes in common and other attributes that are exclusive to one or the other.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Overview of DiffSync
|
|
17
17
|
|
|
18
18
|
DiffSync acts as an intermediate translation layer between all of the data sets you are diffing and/or syncing. In practical terms, this means that to use DiffSync, you will define a set of data models as well as the “adapters” needed to translate between each base data source and the data model. In Python terms, the adapters will be subclasses of the `Adapter` class, and each data model class will be a subclass of the `DiffSyncModel` class.
|
|
19
19
|
|
|
@@ -28,7 +28,7 @@ You can also ask DiffSync to “sync” one data set onto the other, and it will
|
|
|
28
28
|
|
|
29
29
|

|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
## Simple Example
|
|
32
32
|
|
|
33
33
|
```python
|
|
34
34
|
A = DiffSyncSystemA()
|
|
@@ -50,33 +50,50 @@ A.sync_to(B)
|
|
|
50
50
|
|
|
51
51
|
> You may wish to peruse the `diffsync` [GitHub topic](https://github.com/topics/diffsync) for examples of projects using this library.
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
## Documentation
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Full documentation for this library can be found over on the [Diffsync Docs](https://diffsync.readthedocs.io/) website:
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
- [User Guide](https://diffsync.readthedocs.io/user/app_overview/) - Overview, Using the Library, Getting Started.
|
|
58
|
+
- [Administrator Guide](https://diffsync.readthedocs.io/admin/install/) - How to Install, Configure, Upgrade, or Uninstall the Library.
|
|
59
|
+
- [Developer Guide](https://diffsync.readthedocs.io/dev/contributing/) - Extending the Library, Code Reference, Contribution Guide.
|
|
60
|
+
- [Release Notes / Changelog](https://diffsync.readthedocs.io/admin/release_notes/).
|
|
61
|
+
- [Frequently Asked Questions](https://diffsync.readthedocs.io/user/faq/).
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
## Installation
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
### Option 1: Install from PyPI
|
|
66
|
+
|
|
67
|
+
```shell
|
|
68
|
+
pip install diffsync
|
|
63
69
|
```
|
|
64
70
|
|
|
65
71
|
### Option 2: Install from a GitHub branch, such as main as shown below.
|
|
72
|
+
|
|
73
|
+
```shell
|
|
74
|
+
pip install git+https://github.com/networktocode/diffsync.git@main
|
|
66
75
|
```
|
|
67
|
-
$ pip install git+https://github.com/networktocode/diffsync.git@main
|
|
68
|
-
```
|
|
69
76
|
|
|
70
|
-
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
71
79
|
Pull requests are welcomed and automatically built and tested against multiple versions of Python through GitHub Actions.
|
|
72
80
|
|
|
73
|
-
The project is following Network to Code software development guidelines and
|
|
81
|
+
The project is following Network to Code software development guidelines and is leveraging the following:
|
|
74
82
|
|
|
75
|
-
-
|
|
83
|
+
- Ruff, mypy for Python linting, formatting and type hint checking.
|
|
76
84
|
- pytest, coverage, and unittest for unit tests.
|
|
77
85
|
|
|
78
86
|
You can ensure your contribution adheres to these checks by running `invoke tests` from the CLI.
|
|
79
87
|
The command `invoke build` builds a docker container with all the necessary dependencies (including the redis backend) locally to facilitate the execution of these tests.
|
|
80
88
|
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
## Contributing to the Documentation
|
|
90
|
+
|
|
91
|
+
You can find all the Markdown source for the App documentation under the [`docs`](https://github.com/networktocode/diffsync/tree/develop/docs) folder in this repository. For simple edits, a Markdown capable editor is sufficient: clone the repository and edit away.
|
|
92
|
+
|
|
93
|
+
If you need to view the fully-generated documentation site, you can build it with [MkDocs](https://www.mkdocs.org/). A container hosting the documentation can be started using the `invoke` commands (details in the [Development Environment Guide](https://diffsync/dev/dev_environment/#docker-development-environment)) on [http://localhost:8001](http://localhost:8001). Using this container, as your changes to the documentation are saved, they will be automatically rebuilt and any pages currently being viewed will be reloaded in your browser.
|
|
94
|
+
|
|
95
|
+
Any PRs with fixes or improvements are very welcome!
|
|
96
|
+
|
|
97
|
+
## Questions
|
|
98
|
+
|
|
99
|
+
For any questions or comments, please check the [FAQ](https://diffsync.readthedocs.io/en/latest/user/faq/) first. Feel free to also swing by the [Network to Code Slack](https://networktocode.slack.com/) (channel `#networktocode`), sign up [here](http://slack.networktocode.com/) if you don't have an account.
|
|
@@ -14,32 +14,34 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
14
14
|
See the License for the specific language governing permissions and
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
|
+
|
|
17
18
|
import sys
|
|
19
|
+
from copy import deepcopy
|
|
18
20
|
from inspect import isclass
|
|
19
21
|
from typing import (
|
|
22
|
+
Any,
|
|
20
23
|
Callable,
|
|
21
24
|
ClassVar,
|
|
22
25
|
Dict,
|
|
23
26
|
List,
|
|
24
27
|
Optional,
|
|
28
|
+
Set,
|
|
25
29
|
Tuple,
|
|
26
30
|
Type,
|
|
27
31
|
Union,
|
|
28
|
-
Any,
|
|
29
|
-
Set,
|
|
30
32
|
)
|
|
31
|
-
from typing_extensions import deprecated
|
|
32
33
|
|
|
33
|
-
from pydantic import ConfigDict, BaseModel, PrivateAttr
|
|
34
34
|
import structlog # type: ignore
|
|
35
|
+
from pydantic import BaseModel, ConfigDict, PrivateAttr
|
|
36
|
+
from typing_extensions import deprecated
|
|
35
37
|
|
|
36
38
|
from diffsync.diff import Diff
|
|
37
|
-
from diffsync.enum import
|
|
39
|
+
from diffsync.enum import DiffSyncFlags, DiffSyncModelFlags, DiffSyncStatus
|
|
38
40
|
from diffsync.exceptions import (
|
|
39
41
|
DiffClassMismatch,
|
|
40
42
|
ObjectAlreadyExists,
|
|
41
|
-
ObjectStoreWrongType,
|
|
42
43
|
ObjectNotFound,
|
|
44
|
+
ObjectStoreWrongType,
|
|
43
45
|
)
|
|
44
46
|
from diffsync.helpers import DiffSyncDiffer, DiffSyncSyncer
|
|
45
47
|
from diffsync.store import BaseStore
|
|
@@ -59,7 +61,7 @@ StrType = str
|
|
|
59
61
|
class DiffSyncModel(BaseModel):
|
|
60
62
|
"""Base class for all DiffSync object models.
|
|
61
63
|
|
|
62
|
-
Note that read-only APIs of this class are implemented as `get_*()`
|
|
64
|
+
Note that read-only APIs of this class are implemented as `get_*()` methods rather than as properties;
|
|
63
65
|
this is intentional as specific model classes may want to use these names (`type`, `keys`, `attrs`, etc.)
|
|
64
66
|
as model attributes and we want to avoid any ambiguity or collisions.
|
|
65
67
|
|
|
@@ -69,7 +71,7 @@ class DiffSyncModel(BaseModel):
|
|
|
69
71
|
be included in **at most** one of these three tuples.
|
|
70
72
|
"""
|
|
71
73
|
|
|
72
|
-
_modelname: ClassVar[str] = "diffsyncmodel"
|
|
74
|
+
_modelname: ClassVar[str] = "diffsyncmodel" # pylint: disable=used-before-assignment
|
|
73
75
|
"""Name of this model, used by DiffSync to store and look up instances of this model or its equivalents.
|
|
74
76
|
|
|
75
77
|
Lowercase by convention; typically corresponds to the class name, but that is not enforced.
|
|
@@ -133,16 +135,16 @@ class DiffSyncModel(BaseModel):
|
|
|
133
135
|
"""
|
|
134
136
|
# Make sure that any field referenced by name actually exists on the model
|
|
135
137
|
for attr in cls._identifiers:
|
|
136
|
-
if attr not in cls.model_fields and not hasattr(cls, attr):
|
|
138
|
+
if attr not in cls.model_fields and not hasattr(cls, attr): # pylint: disable=unsupported-membership-test
|
|
137
139
|
raise AttributeError(f"_identifiers {cls._identifiers} references missing or un-annotated attr {attr}")
|
|
138
140
|
for attr in cls._shortname:
|
|
139
|
-
if attr not in cls.model_fields:
|
|
141
|
+
if attr not in cls.model_fields: # pylint: disable=unsupported-membership-test
|
|
140
142
|
raise AttributeError(f"_shortname {cls._shortname} references missing or un-annotated attr {attr}")
|
|
141
143
|
for attr in cls._attributes:
|
|
142
|
-
if attr not in cls.model_fields:
|
|
144
|
+
if attr not in cls.model_fields: # pylint: disable=unsupported-membership-test
|
|
143
145
|
raise AttributeError(f"_attributes {cls._attributes} references missing or un-annotated attr {attr}")
|
|
144
146
|
for attr in cls._children.values():
|
|
145
|
-
if attr not in cls.model_fields:
|
|
147
|
+
if attr not in cls.model_fields: # pylint: disable=unsupported-membership-test
|
|
146
148
|
raise AttributeError(f"_children {cls._children} references missing or un-annotated attr {attr}")
|
|
147
149
|
|
|
148
150
|
# Any given field can only be in one of (_identifiers, _attributes, _children)
|
|
@@ -157,9 +159,11 @@ class DiffSyncModel(BaseModel):
|
|
|
157
159
|
raise AttributeError(f"Fields {attr_child_overlap} are included in both _attributes and _children.")
|
|
158
160
|
|
|
159
161
|
def __repr__(self) -> str:
|
|
162
|
+
"""Return a string representation of this DiffSyncModel."""
|
|
160
163
|
return f'{self.get_type()} "{self.get_unique_id()}"'
|
|
161
164
|
|
|
162
165
|
def __str__(self) -> str:
|
|
166
|
+
"""Return a string representation of this DiffSyncModel."""
|
|
163
167
|
return self.get_unique_id()
|
|
164
168
|
|
|
165
169
|
def dict(self, **kwargs: Any) -> Dict:
|
|
@@ -304,7 +308,7 @@ class DiffSyncModel(BaseModel):
|
|
|
304
308
|
|
|
305
309
|
@classmethod
|
|
306
310
|
def get_type(cls) -> StrType:
|
|
307
|
-
"""Return the type AKA modelname of the object or the class
|
|
311
|
+
"""Return the type AKA modelname of the object or the class.
|
|
308
312
|
|
|
309
313
|
Returns:
|
|
310
314
|
str: modelname of the class, used in to store all objects
|
|
@@ -431,7 +435,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
431
435
|
# modelname1 = MyModelClass1
|
|
432
436
|
# modelname2 = MyModelClass2
|
|
433
437
|
|
|
434
|
-
type: Optional[str] = None
|
|
438
|
+
type: Optional[str] = None # pylint: disable=used-before-assignment
|
|
435
439
|
"""Type of the object, will default to the name of the class if not provided."""
|
|
436
440
|
|
|
437
441
|
top_level: ClassVar[List[str]] = []
|
|
@@ -446,7 +450,6 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
446
450
|
|
|
447
451
|
Subclasses should be careful to call super().__init__() if they override this method.
|
|
448
452
|
"""
|
|
449
|
-
|
|
450
453
|
if isinstance(internal_storage_engine, BaseStore):
|
|
451
454
|
self.store = internal_storage_engine
|
|
452
455
|
self.store.adapter = self
|
|
@@ -479,6 +482,13 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
479
482
|
if not isclass(value) or not issubclass(value, DiffSyncModel):
|
|
480
483
|
raise AttributeError(f'top_level references attribute "{name}" but it is not a DiffSyncModel subclass!')
|
|
481
484
|
|
|
485
|
+
def __new__(cls, **kwargs): # type: ignore[no-untyped-def]
|
|
486
|
+
"""Document keyword arguments that were used to initialize Adapter."""
|
|
487
|
+
meta_kwargs = deepcopy(kwargs)
|
|
488
|
+
instance = super().__new__(cls)
|
|
489
|
+
instance._meta_kwargs = meta_kwargs
|
|
490
|
+
return instance
|
|
491
|
+
|
|
482
492
|
def __str__(self) -> StrType:
|
|
483
493
|
"""String representation of an Adapter."""
|
|
484
494
|
if self.type != self.name:
|
|
@@ -486,6 +496,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
486
496
|
return self.type
|
|
487
497
|
|
|
488
498
|
def __repr__(self) -> StrType:
|
|
499
|
+
"""Representation of an Adapter."""
|
|
489
500
|
return f"<{str(self)}>"
|
|
490
501
|
|
|
491
502
|
def __len__(self) -> int:
|
|
@@ -557,7 +568,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
557
568
|
# Synchronization between DiffSync instances
|
|
558
569
|
# ------------------------------------------------------------------------------
|
|
559
570
|
|
|
560
|
-
def sync_from( # pylint: disable=too-many-arguments
|
|
571
|
+
def sync_from( # pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
561
572
|
self,
|
|
562
573
|
source: "Adapter",
|
|
563
574
|
diff_class: Type[Diff] = Diff,
|
|
@@ -574,6 +585,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
574
585
|
callback: Function with parameters (stage, current, total), to be called at intervals as the calculation of
|
|
575
586
|
the diff and subsequent sync proceed.
|
|
576
587
|
diff: An existing diff to be used rather than generating a completely new diff.
|
|
588
|
+
|
|
577
589
|
Returns:
|
|
578
590
|
Diff between origin object and source
|
|
579
591
|
Raises:
|
|
@@ -601,7 +613,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
601
613
|
|
|
602
614
|
return diff
|
|
603
615
|
|
|
604
|
-
def sync_to( # pylint: disable=too-many-arguments
|
|
616
|
+
def sync_to( # pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
605
617
|
self,
|
|
606
618
|
target: "Adapter",
|
|
607
619
|
diff_class: Type[Diff] = Diff,
|
|
@@ -618,6 +630,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
618
630
|
callback: Function with parameters (stage, current, total), to be called at intervals as the calculation of
|
|
619
631
|
the diff and subsequent sync proceed.
|
|
620
632
|
diff: An existing diff that will be used when determining what needs to be synced.
|
|
633
|
+
|
|
621
634
|
Returns:
|
|
622
635
|
Diff between origin object and target
|
|
623
636
|
Raises:
|
|
@@ -728,7 +741,7 @@ class Adapter: # pylint: disable=too-many-public-methods
|
|
|
728
741
|
obj: Union[StrType, DiffSyncModel, Type[DiffSyncModel]],
|
|
729
742
|
identifier: Union[StrType, Dict],
|
|
730
743
|
) -> Optional[DiffSyncModel]:
|
|
731
|
-
"""Get one object from the data store based on its unique id or get a None
|
|
744
|
+
"""Get one object from the data store based on its unique id or get a None.
|
|
732
745
|
|
|
733
746
|
Args:
|
|
734
747
|
obj: DiffSyncModel class or instance, or modelname string, that defines the type of the object to retrieve
|
|
@@ -16,11 +16,11 @@ limitations under the License.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from functools import total_ordering
|
|
19
|
-
from typing import Any,
|
|
19
|
+
from typing import Any, Dict, Iterable, Iterator, List, Optional, Type
|
|
20
20
|
|
|
21
|
-
from .exceptions import ObjectAlreadyExists
|
|
22
|
-
from .utils import intersection, OrderedDefaultDict
|
|
23
21
|
from .enum import DiffSyncActions
|
|
22
|
+
from .exceptions import ObjectAlreadyExists
|
|
23
|
+
from .utils import OrderedDefaultDict, intersection
|
|
24
24
|
|
|
25
25
|
# This workaround is used because we are defining a method called `str` in our class definition, which therefore renders
|
|
26
26
|
# the builtin `str` type unusable.
|
|
@@ -105,8 +105,7 @@ class Diff:
|
|
|
105
105
|
|
|
106
106
|
Since children is already an OrderedDefaultDict, this method is not doing anything special.
|
|
107
107
|
"""
|
|
108
|
-
|
|
109
|
-
yield child
|
|
108
|
+
yield from children.values()
|
|
110
109
|
|
|
111
110
|
def summary(self) -> Dict[StrType, int]:
|
|
112
111
|
"""Build a dict summary of this Diff and its child DiffElements."""
|
|
@@ -161,7 +160,7 @@ class Diff:
|
|
|
161
160
|
class DiffElement: # pylint: disable=too-many-instance-attributes
|
|
162
161
|
"""DiffElement object, designed to represent a single item/object that may or may not have any diffs."""
|
|
163
162
|
|
|
164
|
-
def __init__(
|
|
163
|
+
def __init__( # pylint: disable=too-many-positional-arguments
|
|
165
164
|
self,
|
|
166
165
|
obj_type: StrType,
|
|
167
166
|
name: StrType,
|
|
@@ -14,7 +14,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
14
14
|
See the License for the specific language governing permissions and
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
from typing import TYPE_CHECKING, Any, Union
|
|
18
19
|
|
|
19
20
|
if TYPE_CHECKING:
|
|
20
21
|
from diffsync import DiffSyncModel
|
|
@@ -14,14 +14,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
14
14
|
See the License for the specific language governing permissions and
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
|
-
|
|
18
|
-
from
|
|
17
|
+
|
|
18
|
+
from collections.abc import Iterable as ABCIterable
|
|
19
|
+
from collections.abc import Mapping as ABCMapping
|
|
20
|
+
from typing import TYPE_CHECKING, Callable, Dict, Iterable, List, Optional, Tuple, Type
|
|
19
21
|
|
|
20
22
|
import structlog # type: ignore
|
|
21
23
|
|
|
22
24
|
from .diff import Diff, DiffElement
|
|
23
|
-
from .enum import
|
|
24
|
-
from .exceptions import
|
|
25
|
+
from .enum import DiffSyncActions, DiffSyncFlags, DiffSyncModelFlags, DiffSyncStatus
|
|
26
|
+
from .exceptions import ObjectCrudException, ObjectNotCreated, ObjectNotDeleted, ObjectNotFound, ObjectNotUpdated
|
|
25
27
|
from .utils import intersection, symmetric_difference
|
|
26
28
|
|
|
27
29
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -35,7 +37,7 @@ class DiffSyncDiffer: # pylint: disable=too-many-instance-attributes
|
|
|
35
37
|
Independent from Diff and DiffElement as those classes are purely data objects, while this stores some state.
|
|
36
38
|
"""
|
|
37
39
|
|
|
38
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
40
|
+
def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
39
41
|
self,
|
|
40
42
|
src_diffsync: "Adapter",
|
|
41
43
|
dst_diffsync: "Adapter",
|
|
@@ -114,9 +116,9 @@ class DiffSyncDiffer: # pylint: disable=too-many-instance-attributes
|
|
|
114
116
|
|
|
115
117
|
combined_dict = {}
|
|
116
118
|
for uid in dict_src:
|
|
117
|
-
combined_dict[uid] = (dict_src.get(uid), dict_dst.get(uid))
|
|
119
|
+
combined_dict[uid] = (dict_src.get(uid), dict_dst.get(uid)) # type: ignore
|
|
118
120
|
for uid in dict_dst:
|
|
119
|
-
combined_dict[uid] = (dict_src.get(uid), dict_dst.get(uid))
|
|
121
|
+
combined_dict[uid] = (dict_src.get(uid), dict_dst.get(uid)) # type: ignore
|
|
120
122
|
else:
|
|
121
123
|
# In the future we might support set, etc...
|
|
122
124
|
raise TypeError(f"Type combination {type(src)}/{type(dst)} is not supported... for now")
|
|
@@ -137,7 +139,7 @@ class DiffSyncDiffer: # pylint: disable=too-many-instance-attributes
|
|
|
137
139
|
|
|
138
140
|
@staticmethod
|
|
139
141
|
def validate_objects_for_diff(
|
|
140
|
-
object_pairs: Iterable[Tuple[Optional["DiffSyncModel"], Optional["DiffSyncModel"]]]
|
|
142
|
+
object_pairs: Iterable[Tuple[Optional["DiffSyncModel"], Optional["DiffSyncModel"]]],
|
|
141
143
|
) -> None:
|
|
142
144
|
"""Check whether all DiffSyncModels in the given dictionary are valid for comparison to one another.
|
|
143
145
|
|
|
@@ -285,7 +287,7 @@ class DiffSyncSyncer: # pylint: disable=too-many-instance-attributes
|
|
|
285
287
|
Independent from DiffSync and DiffSyncModel as those classes are purely data objects, while this stores some state.
|
|
286
288
|
"""
|
|
287
289
|
|
|
288
|
-
def __init__( # pylint: disable=too-many-arguments
|
|
290
|
+
def __init__( # pylint: disable=too-many-arguments, too-many-positional-arguments
|
|
289
291
|
self,
|
|
290
292
|
diff: Diff,
|
|
291
293
|
src_diffsync: "Adapter",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Logging utilities for diffsync.
|
|
3
|
+
|
|
4
|
+
This module contains helpers and wrappers for making logging more consistent across applications.
|
|
5
|
+
|
|
6
|
+
How to use me:
|
|
7
|
+
|
|
8
|
+
>>> from diffsync.log import initialize_logging
|
|
9
|
+
>>> log = initialize_logging(level="debug")
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import logging.config
|
|
13
|
+
|
|
14
|
+
APP = "diffsync"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def initialize_logging(config=None, level="INFO", filename=None):
|
|
18
|
+
"""Initialize logging using sensible defaults.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
config (dict): User provided configuration dictionary.
|
|
22
|
+
level (str): The level of logging for STDOUT logging.
|
|
23
|
+
filename (str): Where to output debug logging to file.
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
if not config:
|
|
27
|
+
config = {
|
|
28
|
+
"version": 1,
|
|
29
|
+
"disable_existing_loggers": False,
|
|
30
|
+
"formatters": {
|
|
31
|
+
"standard": {
|
|
32
|
+
"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
33
|
+
"datefmt": "%Y-%m-%dT%H:%M:%S%z",
|
|
34
|
+
},
|
|
35
|
+
"debug": {
|
|
36
|
+
"format": "%(asctime)s [%(levelname)s] [%(module)s] [%(funcName)s] %(name)s: %(message)s",
|
|
37
|
+
"datefmt": "%Y-%m-%dT%H:%M:%S%z",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
"handlers": {
|
|
41
|
+
"standard": {
|
|
42
|
+
"class": "logging.StreamHandler",
|
|
43
|
+
"formatter": "standard",
|
|
44
|
+
"level": level.upper(),
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
"loggers": {
|
|
48
|
+
"": {
|
|
49
|
+
"handlers": ["standard"],
|
|
50
|
+
"level": "DEBUG",
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# If a filename is passed in, let's add a FileHandler
|
|
56
|
+
if filename:
|
|
57
|
+
config["handlers"].update(
|
|
58
|
+
{
|
|
59
|
+
"file_output": {
|
|
60
|
+
"class": "logging.FileHandler",
|
|
61
|
+
"formatter": "debug",
|
|
62
|
+
"level": "DEBUG",
|
|
63
|
+
"filename": filename,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
config["loggers"][""]["handlers"].append("file_output")
|
|
68
|
+
|
|
69
|
+
# Configure the logging
|
|
70
|
+
logging.config.dictConfig(config)
|
|
71
|
+
|
|
72
|
+
# Initialize root logger and advise logging has been initialized
|
|
73
|
+
log = logging.getLogger(APP)
|
|
74
|
+
log.debug("Logging initialized.")
|