Repository: BAMWelDX/weldx

Issue:
Compare_nested doesn't take additional dict items of RHS into account
~~~ python
from weldx.util import compare_nested

d1 = dict(a=1)
d2 = dict(a=1, b=1)

print(compare_nested(d1, d2))
print(compare_nested(d2, d1))
~~~

returns:

~~~
True
False
~~~

So the additional member `b` of `d2` is not considered when `d2` is the rhs operand. 

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX) Report
> Merging [#377](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX) (a297639) into [master](https://codecov.io/gh/BAMWelDX/weldx/commit/e19fbc491b5f92b87f18810cc71a9164e0a42abd?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX) (e19fbc4) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/BAMWelDX/weldx/pull/377/graphs/tree.svg?width=650&height=150&src=pr&token=wdof1qQTsn&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX)](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX)

```diff
@@           Coverage Diff           @@
##           master     #377   +/-   ##
=======================================
  Coverage   97.61%   97.61%           
=======================================
  Files          86       86           
  Lines        5366     5368    +2     
=======================================
+ Hits         5238     5240    +2     
  Misses        128      128           
```


| [Impacted Files](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX) | Coverage Δ | |
|---|---|---|
| [weldx/util.py](https://codecov.io/gh/BAMWelDX/weldx/pull/377/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX#diff-d2VsZHgvdXRpbC5weQ==) | `98.97% <100.00%> (+<0.01%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX). Last update [e19fbc4...a297639](https://codecov.io/gh/BAMWelDX/weldx/pull/377?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=BAMWelDX).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e0056d..0160192 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,10 @@
   structures. [[#328]](https://github.com/BAMWelDX/weldx/pull/328)
 - added `WeldxFile` wrapper to handle asdf files with history and schemas more
   easily. [[#341]](https://github.com/BAMWelDX/weldx/pull/341).
-- added `WeldxFile` wrapper to handle asdf files with
-  history and schemas more easily. [[#341]](https://github.com/BAMWelDX/weldx/pull/341).
+- added `WeldxFile` wrapper to handle asdf files with history and schemas more
+  easily. [[#341]](https://github.com/BAMWelDX/weldx/pull/341).
 - add `"step"` as additional method to `util.xr_interp_like` [[#363]](https://github.com/BAMWelDX/weldx/pull/363)
 
-
 ### changes
 
 - `WXRotation.from_euler()` now accepts a `pint.Quantity` as input. [[#318]](https://github.com/BAMWelDX/weldx/pull/318)
@@ -21,15 +20,14 @@
 - `get_yaml_header` received a new option parse, which optionally returns the parsed YAML header
   as `asdf.tagged.TaggedDict`. [[#338]](https://github.com/BAMWelDX/weldx/pull/338)
 - refactor `asdf_json_repr` into `view_tree` [[#339]](https://github.com/BAMWelDX/weldx/pull/339)
-- The `MeasurementChain` is now internally based on a `networkx.DiGraph`. New functions are also added to the class to 
+- The `MeasurementChain` is now internally based on a `networkx.DiGraph`. New functions are also added to the class to
   simplify its usage. [[#326]](https://github.com/BAMWelDX/weldx/pull/326)
   The following additional changes were applied during the update of the `MeasurementChain`:
-   - renamed `DataTransformation` class to `SignalTransformation`
-   - renamed `Source` to `SignalSource`
-   - Added additional functionality to `Signal`, `SignalTransformation` and `GenericEquipment`
-   - Removed `Data` class
-   - Updated asdf schemas of all modified classes and the ones that contained references to those classes
-   
+    - renamed `DataTransformation` class to `SignalTransformation`
+    - renamed `Source` to `SignalSource`
+    - Added additional functionality to `Signal`, `SignalTransformation` and `GenericEquipment`
+    - Removed `Data` class
+    - Updated asdf schemas of all modified classes and the ones that contained references to those classes
 
 ### documentation
 
@@ -49,6 +47,11 @@
 - update `single-pass-weldx.1.0.0.schema` to allow groove types by
   wildcard [[#373]](https://github.com/BAMWelDX/weldx/pull/373)
 
+### fixes
+
+- added check for symmetric key difference for mappings
+  with `util.compare_nested` [[#377]](https://github.com/BAMWelDX/weldx/pull/377)
+
 ## 0.3.3 (30.03.2021)
 
 This is a bugfix release to correctly include the asdf schema files in conda
diff --git a/weldx/util.py b/weldx/util.py
index 9539268..d303ab3 100644
--- a/weldx/util.py
+++ b/weldx/util.py
@@ -1295,6 +1295,10 @@ class _Eq_compare_nested:
                 other_data_structure
             ) != len(iterutils.get_path(a, path)):
                 raise RuntimeError("len does not match")
+            if isinstance(other_data_structure, Mapping) and any(
+                other_data_structure.keys() ^ iterutils.get_path(a, path).keys()
+            ):
+                raise RuntimeError("keys do not match")
             if not _Eq_compare_nested._compare(value, other_value):
                 raise RuntimeError("not equal")
         return True


Test patch:
diff --git a/weldx/tests/test_utility.py b/weldx/tests/test_utility.py
index 273e9b6..d51902f 100644
--- a/weldx/tests/test_utility.py
+++ b/weldx/tests/test_utility.py
@@ -640,6 +640,12 @@ class TestCompareNested:
         b["y"] = x
         assert not ut.compare_nested(a, b)
 
+    @staticmethod
+    def test_key_added(_default_dicts):  # noqa: D102
+        a, b = (dict(a=1), dict(a=1, b=1))
+        assert not ut.compare_nested(a, b)
+        assert not ut.compare_nested(b, a)
+
     @staticmethod
     def test_array_accessible_by_two_roots():  # noqa: D102
         a = {"l1": {"l2": np.arange(5)}}