Repository: omni-us/jsonargparse

Issue:
CLI modification of dictionary args
## 📚 Documentation improvement

I am struggling to find information on how one should proceed to modify elements from dictionary args.

E.g. consider a class whereby one (for simplicity) input is a dictionary with a couple of keys. How should one proceed to change the value of one of the keys from CLI? It works well from a config file (json or yaml), but I would like to know if there's a way to do so from CLI. Simply doing `--class.init_args.dict.key val` used to work with jsonargparse==4.14.1, but now it leads to the error `Expected a <class 'dict'>. Got value: Namespace`.

I have seen the dict_kwargs option, but it doesn't solve the issue for me (I have multiple dictionaries input). I can come up with workarounds, but I'd like to know if it's still supported or not. 

Discussion:
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=254)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254&metric=new_duplicated_lines_density&view=list)


codecov[bot]: ## [Codecov](https://codecov.io/gh/omni-us/jsonargparse/pull/254?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) Report
Patch coverage: **`100.00`**% and project coverage change: **`-12.12`** :warning:
> Comparison is base [(`3de6d6f`)](https://codecov.io/gh/omni-us/jsonargparse/commit/3de6d6f4a57567e6a63f9e15f8565c4b537bba45?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) 100.00% compared to head [(`55c267e`)](https://codecov.io/gh/omni-us/jsonargparse/pull/254?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) 87.88%.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##            master     #254       +/-   ##
============================================
- Coverage   100.00%   87.88%   -12.12%     
============================================
  Files           20       20               
  Lines         5191     5193        +2     
============================================
- Hits          5191     4564      -627     
- Misses           0      629      +629     
```

| Flag | Coverage Δ | |
|---|---|---|
| py3.10 | `87.88% <100.00%> (-0.06%)` | :arrow_down: |
| py3.10_all | `?` | |
| py3.6 | `?` | |
| py3.6_all | `?` | |
| py3.7 | `?` | |
| py3.7_all | `?` | |
| py3.8 | `?` | |
| py3.8_all | `?` | |
| py3.9 | `?` | |
| py3.9_all | `?` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/omni-us/jsonargparse/pull/254?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | Coverage Δ | |
|---|---|---|
| [jsonargparse/typehints.py](https://codecov.io/gh/omni-us/jsonargparse/pull/254?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL3R5cGVoaW50cy5weQ==) | `96.68% <100.00%> (-3.32%)` | :arrow_down: |

... and [12 files with indirect coverage changes](https://codecov.io/gh/omni-us/jsonargparse/pull/254/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us)

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us)

</details>

[:umbrella: View full report in Codecov by Sentry](https://codecov.io/gh/omni-us/jsonargparse/pull/254?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=254)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=254&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=254&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 1b29009..8bea11a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -24,6 +24,9 @@ Fixed
   contexts `#247 <https://github.com/omni-us/jsonargparse/issues/247>`__.
 - Failure with dataclasses that have field with ``init=False`` `#252
   <https://github.com/omni-us/jsonargparse/issues/252>`__.
+- Failure when setting individual dict key values for subclasses and
+  ``.init_args.`` is included in argument `#251
+  <https://github.com/omni-us/jsonargparse/issues/251>`__.
 
 
 v4.20.0 (2023-02-20)
diff --git a/jsonargparse/typehints.py b/jsonargparse/typehints.py
index 7f67ae1..20ffc69 100644
--- a/jsonargparse/typehints.py
+++ b/jsonargparse/typehints.py
@@ -394,7 +394,10 @@ class ActionTypeHint(Action):
         cfg, val, opt_str = args[1:]
         if not (self.nargs == '?' and val is None):
             if isinstance(opt_str, str) and opt_str.startswith(f'--{self.dest}.'):
-                sub_opt = opt_str[len(f'--{self.dest}.'):]
+                if opt_str.startswith(f'--{self.dest}.init_args.'):
+                    sub_opt = opt_str[len(f'--{self.dest}.init_args.'):]
+                else:
+                    sub_opt = opt_str[len(f'--{self.dest}.'):]
                 val = NestedArg(key=sub_opt, val=val)
             append = opt_str == f'--{self.dest}+'
             val = self._check_type(val, append=append, cfg=cfg)
@@ -806,11 +809,7 @@ def subclass_spec_as_namespace(val, prev_val=None):
         if '.' not in key:
             root_key = key
         else:
-            if key.startswith('init_args.'):
-                root_key = 'init_args'
-                key = key[len('init_args.'):]
-                val = Namespace({key: val})
-            elif key.startswith('dict_kwargs.'):
+            if key.startswith('dict_kwargs.'):
                 root_key = 'dict_kwargs'
                 key = key[len('dict_kwargs.'):]
                 val = {key: val}


Test patch:
diff --git a/jsonargparse_tests/test_typehints.py b/jsonargparse_tests/test_typehints.py
index 003d7dc..469c71c 100755
--- a/jsonargparse_tests/test_typehints.py
+++ b/jsonargparse_tests/test_typehints.py
@@ -230,6 +230,25 @@ class TypeHintsTests(unittest.TestCase):
         self.assertEqual(cfg.dict, {'one': 1, 'two': 2})
 
 
+    def test_subclass_dict_items(self):
+        class Class:
+            def __init__(self, param: Dict[str, int]):
+                pass
+
+        parser = ArgumentParser(exit_on_error=False)
+        parser.add_argument('--val', type=Class)
+
+        with mock_module(Class) as module:
+            for init_args in ['', '.init_args']:
+                cfg = parser.parse_args([
+                    f'--val={module}.Class',
+                    f'--val{init_args}.param.one=1',
+                    f'--val{init_args}.param.two=2',
+                ])
+                self.assertEqual(cfg.val.class_path, f'{module}.Class')
+                self.assertEqual(cfg.val.init_args.param, {'one': 1, 'two': 2})
+
+
     def test_dict_union(self):
         class MyEnum(Enum):
             ab = 1