Repository: wandb/wandb

Issue:
[CLI] [Bug] KeyError when adding a new dictionary as statistic to existing run
**Description**
I'm adding a new summary to the existing run following the docs https://docs.wandb.ai/library/public-api-guide.
If a new summary is a scalar value, everything works fine, but if it's a dictionary, I get the following:

```
$ python tmp_wandb.py 
Traceback (most recent call last):
  File "tmp_wandb.py", line 5, in <module>
    run.summary.update({'new_metric_d': {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'}})
  File "C:\Users\Maria\.conda\envs\Garments\lib\site-packages\wandb\old\summary.py", line 179, in update
    write_items = self._update(key_vals, overwrite)
  File "C:\Users\Maria\.conda\envs\Garments\lib\site-packages\wandb\old\summary.py", line 198, in _update
    self._dict[key] = SummarySubDict(
  File "C:\Users\Maria\.conda\envs\Garments\lib\site-packages\wandb\old\summary.py", line 48, in __init__
    json_dict = json_dict[k]
KeyError: 'new_metric_d'
```

**Wandb features**
`run.summary.update()` according to the docs https://docs.wandb.ai/library/public-api-guide.

**How to reproduce**
This is the minimum script: 
```
import wandb

run = wandb.Api().run(<run_path>)
run.summary.update({'new_metric_d': {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'}})
run.summary.update()

```
The run at <run_path> already exists and has a "failed" state (in case it's important)
Here is the run I work with: https://wandb.ai/maria_korosteleva/Garments-Reconstruction/runs/5cnaly5h/

**Environment**
- OS: Win 10
- Environment: Anaconda + Visual Code
- Python Version: 3.8.5
- wandb Version: 0.10.21 



Discussion:
Hey @maria-korosteleva we'll look into the root cause.  Until then you should be able to do the following:

```
run.summary["new_metric_d"] = {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'}
run.summary.update()
```
Hey @vanpelt 

Just letting you know that the issue is still there in 0.10.25. And both of the methods don't work (the one in the issue description and the one that you proposed).

>
> ```
> run = wandb.Api().run(<run_path>)
> run.summary.update({'new_metric_d': {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'}})
> run.summary.update() 
> ```
>

> ```
> run = wandb.Api().run(<run_path>)
> run.summary["new_metric_d"] = {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'}
> run.summary.update()
> ```

Both fail with the same `KeyError: 'new_metric_d'`  😥

----

For now, the workaround that worked for me is recording each dictionary entry one by one as individual scalar values with extended names, e.g.
```
import wandb

def add_statistic(run, tag, info):
    """Add info the run summary (e.g. stats on test set)"""
    if isinstance(info, dict):
        for key in info:
            add_statistic(run, tag + '.' + key, info[key])
    else:
        run.summary[tag] = info
        run.summary.update()

run = wandb.Api().run('maria_korosteleva/Test-Garments-Reconstruction/2ckc3ecs')
add_statistic(run, 'new_metric_d2',  {'full_loss': 2.5, 'Extra_loss': 1.5, 'type': 'dict_metric'})
```


This issue is stale because it has been open 60 days with no activity.
I just reproduced this issue on `0.10.27`. From what I can tell, a fix might be swapping lines 144 and 145 here, so that the key is added to `root._json_dict` before `SummarySubDict` tries to access it in `__init__`: https://github.com/wandb/client/blob/321654aea55440622371594da9279f4e97f25607/wandb/old/summary.py#L137-L149
Something similar would also need to be done for the `update` method.

In the meantime, this workaround did the trick for me:
```python
def update_run(run, k, v):
    if (isinstance(run.summary, wandb.old.summary.Summary) and k not in run.summary):
        run.summary._root_set(run.summary._path, [(k, {})])
    run.summary[k] = v
```
This issue is stale because it has been open 60 days with no activity.
Same issue in `0.12.7`. @corneliusboehm's workaround works for me, thank you! 
Yeah, same for me. @corneliusboehm 's workaround did the trick. Thanks a lot!
The issue still persists.
Issue still persists
Do not close this issue please because it still persists and causes inconvenience.

Resolving patch:
diff --git a/wandb/old/summary.py b/wandb/old/summary.py
--- a/wandb/old/summary.py
+++ b/wandb/old/summary.py
@@ -31,7 +31,8 @@ def __init__(self, root=None, path=()):
             self._root = root
             json_dict = root._json_dict
             for k in path:
-                json_dict = json_dict[k]
+                json_dict = json_dict.get(k, {})
+
             self._json_dict = json_dict
         self._dict = {}
 
@@ -175,9 +176,7 @@ def update(self, key_vals=None, overwrite=True):
     def _update(self, key_vals, overwrite):
         if not key_vals:
             return
-
         key_vals = {k.strip(): v for k, v in key_vals.items()}
-
         if overwrite:
             write_items = list(key_vals.items())
             self._locked_keys.update(key_vals.keys())


Test patch:
diff --git a/tests/pytest_tests/unit_tests/test_wandb_summary.py b/tests/pytest_tests/unit_tests/test_wandb_summary.py
--- a/tests/pytest_tests/unit_tests/test_wandb_summary.py
+++ b/tests/pytest_tests/unit_tests/test_wandb_summary.py
@@ -118,3 +118,9 @@ def test_cb_delete_item():
     m.reset({"this": {"nest1": 2}})
     del s["this"]["nest1"]
     m.check_removes(("this", "nest1"))
+
+
+def test_update_with_nested_dict():
+    s, m = create_summary_and_mock({})
+    s.update(dict(that=dict(nest1=dict(nest2=4, nest2b=5))))
+    m.check_updates(("that",), dict(nest1=dict(nest2=4, nest2b=5)))