Repository: omni-us/jsonargparse
Pull request #194 (2022-11-16 19:48:25)

Fix list append in default_config_files defined in subcommand subparser
## What does this PR do?

Fixes https://github.com/Lightning-AI/lightning/issues/15256

## Before submitting

- [x] Did you read the [contributing guideline](https://github.com/omni-us/jsonargparse/blob/master/CONTRIBUTING.rst)?
- [x] Did you update **the documentation**? (readme and public docstrings)
- [x] Did you write **unit tests** such that there is 100% coverage on related code? (required for bug fixes and new features)
- [x] Did you verify that new and existing **tests pass locally**?
- [x] Did you make sure that all changes preserve **backward compatibility**?
- [x] Did you update **the CHANGELOG**? (not for typos, docs, test updates, or minor internal changes/refactors)


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=194)

[![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=194&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=194&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=194&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=194&resolved=false&types=CODE_SMELL) [![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=194&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194) 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=194&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=194&metric=new_duplicated_lines_density&view=list)


codecov-commenter: # [Codecov](https://codecov.io/gh/omni-us/jsonargparse/pull/194?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) Report
Base: **100.00**% // Head: **100.00**% // No change to project coverage :thumbsup:
> Coverage data is based on head [(`a75ccb5`)](https://codecov.io/gh/omni-us/jsonargparse/pull/194?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) compared to base [(`0499981`)](https://codecov.io/gh/omni-us/jsonargparse/commit/04999813e290fb2186d7e7496a48afea59092015?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).
> Patch coverage: 100.00% of modified lines in pull request are covered.

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


```diff
@@            Coverage Diff            @@
##            master      #194   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           17        17           
  Lines         4479      4487    +8     
=========================================
+ Hits          4479      4487    +8     
```

| Flag | Coverage Δ | |
|---|---|---|
| py3.10 | `91.33% <100.00%> (+0.01%)` | :arrow_up: |
| py3.10_all | `99.93% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.6 | `90.96% <100.00%> (+0.01%)` | :arrow_up: |
| py3.6_all | `99.64% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.7 | `91.05% <100.00%> (+0.01%)` | :arrow_up: |
| py3.7_all | `99.84% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.8 | `91.30% <100.00%> (+0.01%)` | :arrow_up: |
| py3.8_all | `99.91% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.9 | `91.33% <100.00%> (+0.01%)` | :arrow_up: |
| py3.9_all | `99.91% <100.00%> (+<0.01%)` | :arrow_up: |

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/194?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) | Coverage Δ | |
|---|---|---|
| [jsonargparse/actions.py](https://codecov.io/gh/omni-us/jsonargparse/pull/194/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL2FjdGlvbnMucHk=) | `100.00% <100.00%> (ø)` | |
| [jsonargparse/core.py](https://codecov.io/gh/omni-us/jsonargparse/pull/194/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL2NvcmUucHk=) | `100.00% <100.00%> (ø)` | |
| [jsonargparse/typehints.py](https://codecov.io/gh/omni-us/jsonargparse/pull/194/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL3R5cGVoaW50cy5weQ==) | `100.00% <100.00%> (ø)` | |

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 at Codecov](https://codecov.io/gh/omni-us/jsonargparse/pull/194?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=194)

[![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=194&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=194&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=194&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=194&resolved=false&types=CODE_SMELL) [![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=194&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194) 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=194&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=194&metric=new_duplicated_lines_density&view=list)


tshu-w: Hi, this PR fix https://github.com/Lightning-AI/lightning/issues/15256. I briefly skimmed the code, LGTM.
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=194)

[![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=194&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=194&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194&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=194&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=194&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=194&resolved=false&types=CODE_SMELL) [![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=194&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=194&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=194) 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=194&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=194&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 005aa34..6eba696 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -23,6 +23,9 @@ Fixed
   subcommands.
 - Parsing fails for registered types that can't be cast to boolean `#196
   <https://github.com/omni-us/jsonargparse/issues/196>`__.
+- List append not working for ``default_config_files`` set in a subcommand
+  subparser `pytorch-lightning#15256
+  <https://github.com/Lightning-AI/lightning/issues/15256>`__.
 
 Changed
 ^^^^^^^
diff --git a/jsonargparse/actions.py b/jsonargparse/actions.py
index e9ee140..a5a1d37 100644
--- a/jsonargparse/actions.py
+++ b/jsonargparse/actions.py
@@ -294,9 +294,13 @@ class _ActionConfigLoad(Action):
             kwargs['_basetype'] = self._basetype
             return _ActionConfigLoad(**kwargs)
         parser, namespace, value = args[:3]
-        cfg_file = Namespace()
-        cfg_file[self.dest] = self._load_config(value, parser)
-        namespace.update(cfg_file)
+        loaded_value = self._load_config(value, parser)
+        if isinstance(namespace.get(self.dest), Namespace):
+            loaded_value = parser.merge_config(
+                Namespace({self.dest: loaded_value}),
+                Namespace({self.dest: namespace[self.dest]})
+            )[self.dest]
+        namespace[self.dest] = loaded_value
 
     def _load_config(self, value, parser):
         try:
@@ -547,8 +551,8 @@ class ActionParser:
 
 
 single_subcommand: ContextVar = ContextVar('single_subcommand', default=True)
-
 parent_parsers: ContextVar = ContextVar('parent_parsers', default=[])
+parse_kwargs: ContextVar = ContextVar('parse_kwargs', default={})
 
 
 @contextmanager
@@ -588,6 +592,7 @@ class _ActionSubCommands(_SubParsersAction):
         parser.default_env = self.parent_parser.default_env
         parser.parent_parser = self.parent_parser
         parser.parser_mode = self.parent_parser.parser_mode
+        parser.error_handler = self.parent_parser.error_handler
         parser.subcommand = name
 
         # create a pseudo-action to hold the choice help
@@ -617,10 +622,15 @@ class _ActionSubCommands(_SubParsersAction):
         if subcommand in self._name_parser_map:
             subparser = self._name_parser_map[subcommand]
             subnamespace = namespace.get(subcommand).clone() if subcommand in namespace else None
-            subnamespace, unk = subparser.parse_known_args(arg_strings, namespace=subnamespace)
-            if unk:
-                raise ParserError(f'Unrecognized arguments: {" ".join(unk)}')
-            namespace.update(subnamespace, subcommand)
+            kwargs = dict(_skip_check=True, **parse_kwargs.get())
+            namespace[subcommand] = subparser.parse_args(arg_strings, namespace=subnamespace, **kwargs)
+
+
+    @staticmethod
+    @contextmanager
+    def parse_kwargs_context(kwargs):
+        parse_kwargs.set(kwargs)
+        yield
 
 
     @staticmethod
diff --git a/jsonargparse/core.py b/jsonargparse/core.py
index f700fdc..04472f6 100644
--- a/jsonargparse/core.py
+++ b/jsonargparse/core.py
@@ -241,9 +241,6 @@ class ArgumentParser(ActionsContainer, ArgumentLinking, argparse.ArgumentParser)
                 self.error(f'All arguments are expected to be strings: {args}')
         self.args = args
 
-        if namespace is None:
-            namespace = Namespace()
-
         namespace = argcomplete_namespace(caller, self, namespace)
 
         try:
@@ -375,7 +372,8 @@ class ArgumentParser(ActionsContainer, ArgumentLinking, argparse.ArgumentParser)
             if namespace:
                 cfg = self.merge_config(namespace, cfg)
 
-            cfg, unk = self.parse_known_args(args=args, namespace=cfg)
+            with _ActionSubCommands.parse_kwargs_context({'env': env, 'defaults': defaults}):
+                cfg, unk = self.parse_known_args(args=args, namespace=cfg)
             if unk:
                 self.error(f'Unrecognized arguments: {" ".join(unk)}')
 
@@ -1390,6 +1388,9 @@ class ArgumentParser(ActionsContainer, ArgumentLinking, argparse.ArgumentParser)
             self._default_env = default_env
         else:
             raise ValueError('default_env has to be a boolean.')
+        if self._subcommands_action:
+            for subparser in self._subcommands_action._name_parser_map.values():
+                subparser.default_env = self._default_env
 
 
     @property
diff --git a/jsonargparse/typehints.py b/jsonargparse/typehints.py
index f3344ce..0e22099 100644
--- a/jsonargparse/typehints.py
+++ b/jsonargparse/typehints.py
@@ -357,16 +357,14 @@ class ActionTypeHint(Action):
             if 'nargs' in kwargs and kwargs['nargs'] == 0:
                 raise ValueError('ActionTypeHint does not allow nargs=0.')
             return ActionTypeHint(**kwargs)
-        if self.nargs == '?' and args[2] is None:
-            val = None
-        else:
-            cfg, val, opt_str = args[1:]
+        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}.'):]
                 val = NestedArg(key=sub_opt, val=val)
             append = opt_str == f'--{self.dest}+'
             val = self._check_type(val, append=append, cfg=cfg)
-        args[1].update(val, self.dest)
+        cfg.update(val, self.dest)
 
 
     def _check_type(self, value, append=False, cfg=None):
@@ -599,6 +597,7 @@ def adapt_typehints(val, typehint, serialize=False, instantiate_classes=False, p
     # List, Iterable or Sequence
     elif typehint_origin in sequence_origin_types:
         if append:
+            adapt_kwargs.pop('prev_val')
             if prev_val is None:
                 prev_val = []
             elif not isinstance(prev_val, list):


Test patch:
diff --git a/jsonargparse_tests/test_typehints.py b/jsonargparse_tests/test_typehints.py
index 669165f..ecbe439 100755
--- a/jsonargparse_tests/test_typehints.py
+++ b/jsonargparse_tests/test_typehints.py
@@ -1466,6 +1466,7 @@ class TypeHintsTmpdirTests(TempDirTestCase):
             self.assertEqual(cfg.nums, [0, 1, 2])
             cfg = parser.parse_args(['--nums+=[2, 3]'])
             self.assertEqual(cfg.nums, [0, 1, 2, 3])
+            self.assertEqual(str(cfg.__default_config__), str(config_path))
 
         with self.subTest('two default config appends'):
             config_path2 = pathlib.Path(self.tmpdir, 'config2.yaml')
@@ -1473,9 +1474,10 @@ class TypeHintsTmpdirTests(TempDirTestCase):
             parser.default_config_files += [str(config_path2)]
             cfg = parser.get_defaults()
             self.assertEqual(cfg.nums, [0, 1, 2])
+            self.assertEqual([str(c) for c in cfg.__default_config__], [str(config_path), str(config_path2)])
 
 
-    def test_list_append_default_config_files_subcommand(self):
+    def test_list_append_subcommand_global_default_config_files(self):
         config_path = pathlib.Path(self.tmpdir, 'config.yaml')
         parser = ArgumentParser(default_config_files=[str(config_path)])
         subcommands = parser.add_subcommands()
@@ -1485,6 +1487,24 @@ class TypeHintsTmpdirTests(TempDirTestCase):
         config_path.write_text('sub:\n  nums: [1]\n')
         cfg = parser.parse_args(['sub', '--nums+=2'])
         self.assertEqual(cfg.sub.nums, [1, 2])
+        self.assertEqual(str(cfg.__default_config__), str(config_path))
+        cfg = parser.parse_args(['sub', '--nums+=2'], defaults=False)
+        self.assertEqual(cfg.sub.nums, [2])
+
+
+    def test_list_append_subcommand_subparser_default_config_files(self):
+        config_path = pathlib.Path(self.tmpdir, 'config.yaml')
+        parser = ArgumentParser()
+        subcommands = parser.add_subcommands()
+        subparser = ArgumentParser(default_config_files=[str(config_path)])
+        subparser.add_argument('--nums', type=List[int], default=[0])
+        subcommands.add_subcommand('sub', subparser)
+        config_path.write_text('nums: [1]\n')
+        cfg = parser.parse_args(['sub', '--nums+=2'])
+        self.assertEqual(cfg.sub.nums, [1, 2])
+        self.assertEqual(str(cfg.sub.__default_config__), str(config_path))
+        cfg = parser.parse_args(['sub', '--nums+=2'], defaults=False)
+        self.assertEqual(cfg.sub.nums, [2])
 
 
     def test_class_type_with_default_config_files(self):