Repository: omni-us/jsonargparse
Pull request #224 (2022-12-26 13:54:10)

Diverse fixes
## What does this PR do?

- Separate readme section for override order.
- Fixed failure when using a sequence type and the default is a tuple.
- Fixed incorrect error line breaks and indentation.
- Exclude non-public objects from jsonargparse.typing documentation.
- Enable python 3.11 testing on circleci.
- Only run tests for master branch and pull requests that merge to master.
- Several other minor fixes and improvements.

## 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=224)

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


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

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


codecov-commenter: # [Codecov](https://codecov.io/gh/omni-us/jsonargparse/pull/224?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 [(`bb48f92`)](https://codecov.io/gh/omni-us/jsonargparse/pull/224?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) compared to base [(`e64ff29`)](https://codecov.io/gh/omni-us/jsonargparse/commit/e64ff29a5ab8a68613485d82e699448d17f8a450?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      #224   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           19        19           
  Lines         5074      5076    +2     
=========================================
+ Hits          5074      5076    +2     
```

| Flag | Coverage Δ | |
|---|---|---|
| py3.10 | `87.62% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.10_all | `99.88% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.6 | `87.27% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.6_all | `99.62% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.7 | `87.29% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.7_all | `99.80% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.8 | `87.60% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.8_all | `99.84% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.9 | `87.60% <100.00%> (+<0.01%)` | :arrow_up: |
| py3.9_all | `99.86% <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/224?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/224/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% <ø> (ø)` | |
| [jsonargparse/core.py](https://codecov.io/gh/omni-us/jsonargparse/pull/224/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/224/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%> (ø)` | |
| [jsonargparse/typing.py](https://codecov.io/gh/omni-us/jsonargparse/pull/224/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us#diff-anNvbmFyZ3BhcnNlL3R5cGluZy5weQ==) | `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/224?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).


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6380e1d..6af1c86 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -3,7 +3,7 @@ version: 2.1
 jobs:
   build:
     docker:
-      - image: circleci/python:3.8
+      - image: cimg/python:3.8
     steps:
       - checkout
       - run:
@@ -16,7 +16,7 @@ jobs:
             - ./dist/*.tar.gz
   test-py38: &test-py38
     docker:
-      - image: circleci/python:3.8
+      - image: cimg/python:3.8
     steps:
       - attach_workspace:
           at: .
@@ -34,29 +34,29 @@ jobs:
           root: .
           paths:
             - ./coverage_*.xml
-  #test-py311:
-  #  <<: *test-py38
-  #  docker:
-  #    - image: circleci/python:3.11
+  test-py311:
+    <<: *test-py38
+    docker:
+      - image: cimg/python:3.11
   test-py310:
     <<: *test-py38
     docker:
-      - image: circleci/python:3.10
+      - image: cimg/python:3.10
   test-py39:
     <<: *test-py38
     docker:
-      - image: circleci/python:3.9
+      - image: cimg/python:3.9
   test-py37:
     <<: *test-py38
     docker:
-      - image: circleci/python:3.7
+      - image: cimg/python:3.7
   test-py36:
     <<: *test-py38
     docker:
-      - image: circleci/python:3.6
+      - image: cimg/python:3.6
   codecov:
     docker:
-      - image: circleci/python:3.8
+      - image: cimg/python:3.8
     steps:
       - checkout
       - attach_workspace:
@@ -99,8 +99,8 @@ workflows:
           <<: *buildreq
           requires:
             - build
-      #- test-py311:
-      #    <<: *testreq
+      - test-py311:
+          <<: *testreq
       - test-py310:
           <<: *testreq
       - test-py39:
@@ -112,7 +112,7 @@ workflows:
       - codecov:
           <<: *testreq
           requires:
-            #- test-py311
+            - test-py311
             - test-py310
             - test-py39
             - test-py38
diff --git a/.github/workflows/code-checks.yml b/.github/workflows/code-checks.yml
index 52d3ccd..77b0223 100644
--- a/.github/workflows/code-checks.yml
+++ b/.github/workflows/code-checks.yml
@@ -1,5 +1,9 @@
 name: code-checks
-on: [push, pull_request]
+on:
+  push:
+    branches: [ "master" ]
+  pull_request:
+    branches: [ "master" ]
 
 jobs:
   mypy:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 688ae1c..0468ec3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -45,6 +45,7 @@ Fixed
 - Incorrect value when ``Path`` is cast to ``str`` and ``rel_path`` was changed.
 - Argument links with target a subclass mixed with other types not working `#208
   <https://github.com/omni-us/jsonargparse/issues/208>`__.
+- Failures when using a sequence type and the default is a tuple.
 
 Changed
 ^^^^^^^
diff --git a/README.rst b/README.rst
index c6046b5..b3b20d4 100644
--- a/README.rst
+++ b/README.rst
@@ -60,15 +60,6 @@ Features
 - Support for command line tab argument completion using `argcomplete
   <https://pypi.org/project/argcomplete/>`__.
 
-- Configuration values are overridden based on the following precedence.
-
-  - **Parsing command line:** command line arguments (might include config
-    files) > environment variables > default config files > defaults.
-  - **Parsing files:** config file > environment variables > default config
-    files > defaults.
-  - **Parsing environment:** environment variables > default config files >
-    defaults.
-
 
 .. _installation:
 
@@ -329,6 +320,29 @@ If the parsing fails the standard behavior is that the usage is printed and the
 program is terminated. Alternatively you can initialize the parser with
 ``error_handler=None`` in which case a :class:`.ParserError` is raised.
 
+
+Override order
+--------------
+
+Final parsed values depend on different sources, namely: source code, command
+line arguments, :ref:`configuration-files` and :ref:`environment-variables`.
+Values are overridden based on the following precedence:
+
+1. Defaults defined in the source code.
+2. Existing default config files in the order defined in
+   ``default_config_files``, e.g. ``~/.config/myapp.yaml``.
+3. Full config environment variable, e.g. ``APP_CONFIG``.
+4. Individual key environment variables, e.g. ``APP_OPT1``.
+5. Command line arguments in order left to right (might include config files).
+
+Depending on the parse method used (see :class:`.ArgumentParser`) and how the
+parser was built, some of the options above might not apply. Parsing of
+environment variables must be explicitly enabled, except if using
+:py:meth:`.ArgumentParser.parse_env`. If the parser does not have an
+:class:`.ActionConfigFile` argument, then there is no parsing of a full config
+environment variable or a way to provide a config file from command line.
+
+
 Capturing parsers
 -----------------
 
@@ -516,9 +530,6 @@ that exists and is readable, the following could be done:
 
 .. testsetup:: paths
 
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
@@ -576,9 +587,6 @@ string for reading the list from stdin. Example:
 
 .. testsetup:: path_list
 
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
@@ -743,7 +751,6 @@ can be achieved by adding ``+`` as suffix to the argument key, for example:
 
 .. testsetup:: append
 
-    from typing import List
     parser = ArgumentParser()
 
 .. doctest:: append
@@ -813,7 +820,6 @@ option is the import path of a callable object, for example:
 
 .. testsetup:: callable
 
-    from typing import Callable, Iterable
     parser = ArgumentParser()
 
 .. testcode:: callable
@@ -1066,9 +1072,6 @@ the following would be observed:
 
 .. testsetup:: config
 
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
@@ -1391,7 +1394,6 @@ Take for example the following parsing and instantiation:
 
 .. testsetup:: unresolved
 
-    import jsonargparse_tests
     sys.argv = ['', '--myclass=MyClass']
 
     class MyClass:
@@ -1452,7 +1454,6 @@ unrelated to these variables.
 
 .. testsetup:: ast_resolver
 
-    from typing import Callable
     class BaseClass: pass
     class SomeClass:
         def __init__(self, **kwargs):
@@ -1665,9 +1666,6 @@ Then in python:
 
 .. testsetup:: subclasses
 
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
@@ -1775,10 +1773,6 @@ debug.
 Since there are some legitimate use cases for class instances in defaults, they
 are supported with a particular behavior and recommendations. An example is:
 
-.. testsetup:: instance_default
-
-    from calendar import Calendar
-
 .. testcode:: instance_default
 
     class MyClass:
@@ -1835,10 +1829,6 @@ corresponding yaml structure.
 
 .. testsetup:: final_classes
 
-    import os
-    import shutil
-    import tempfile
-    from calendar import Calendar
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
@@ -1964,15 +1954,11 @@ Take for example a yaml file as:
     client:
       url: http://${server.host}:${server.port}/
     """
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
     with open('example.yaml', 'w') as f:
         f.write(example)
-    from dataclasses import dataclass
 
 .. testcleanup:: omegaconf
 
@@ -2032,7 +2018,6 @@ command line arguments, that is:
 
 .. testsetup:: env
 
-    import os
     os.environ['APP_LEV1__OPT1'] = 'from env 1'
     os.environ['APP_LEV1__OPT2'] = 'from env 2'
 
@@ -2189,9 +2174,6 @@ config files to be in jsonnet format instead. Example:
 
 .. testsetup:: jsonnet
 
-    import os
-    import shutil
-    import tempfile
     cwd = os.getcwd()
     tmpdir = tempfile.mkdtemp(prefix='_jsonargparse_doctest_')
     os.chdir(tmpdir)
diff --git a/jsonargparse/actions.py b/jsonargparse/actions.py
index 04f52a8..29083ff 100644
--- a/jsonargparse/actions.py
+++ b/jsonargparse/actions.py
@@ -230,7 +230,7 @@ class _ActionPrintConfig(Action):
             metavar='\b[=flags]',
             help=(
                 'Print the configuration after applying all other arguments and exit. The optional '
-                'flags are one or more keywords separated by comma which modify the output. The '
+                'flags customizes the output and are one or more keywords separated by comma. The '
                 'supported flags are: comments, skip_default, skip_null.'
             ),
         )
diff --git a/jsonargparse/core.py b/jsonargparse/core.py
index ad1d0a0..5901e00 100644
--- a/jsonargparse/core.py
+++ b/jsonargparse/core.py
@@ -676,7 +676,7 @@ class ArgumentParser(ActionsContainer, ArgumentLinking, argparse.ArgumentParser)
             **kwargs: All options that `argparse.ArgumentParser.add_subparsers` accepts.
         """
         if 'description' not in kwargs:
-            kwargs['description'] = 'For more details of each subcommand add it as argument followed by --help.'
+            kwargs['description'] = 'For more details of each subcommand, add it as an argument followed by --help.'
         with formatter_context(self):
             subcommands: _ActionSubCommands = super().add_subparsers(dest=dest, **kwargs)  # type: ignore
         if required:
diff --git a/jsonargparse/typehints.py b/jsonargparse/typehints.py
index 485468a..f322407 100644
--- a/jsonargparse/typehints.py
+++ b/jsonargparse/typehints.py
@@ -537,7 +537,7 @@ def raise_unexpected_value(message: str, val: Any = inspect._empty, exception: O
 
 
 def raise_union_unexpected_value(uniontype, val: Any, exceptions: List[Exception]) -> NoReturn:
-    errors = indent_text('- '.join(str(e) for e in [''] + exceptions))
+    errors = indent_text('- ' + '\n- '.join(map(str, exceptions)))
     errors = errors.replace(f'. Got value: {val}', '').replace(f' {val} ', ' ')
     subtypes = uniontype.__args__
     raise ValueError(
@@ -670,6 +670,8 @@ def adapt_typehints(val, typehint, serialize=False, instantiate_classes=False, p
             prev_val = prev_val + [None] * (len(val)-len(prev_val) if val_is_list else 1)
         if isinstance(val, NestedArg) and subtypehints is not None:
             val = (prev_val[:-1] if isinstance(prev_val, list) else []) + [val]
+        elif isinstance(val, Iterable) and not isinstance(val, (list, str)) and type(val) not in mapping_origin_types:
+            val = list(val)
         elif not isinstance(val, list):
             raise_unexpected_value(f'Expected a {typehint_origin}', val)
         if subtypehints is not None:
diff --git a/jsonargparse/typing.py b/jsonargparse/typing.py
index e5d7cf9..b28eac5 100644
--- a/jsonargparse/typing.py
+++ b/jsonargparse/typing.py
@@ -4,7 +4,6 @@ import operator
 import os
 import pathlib
 import re
-from contextlib import suppress
 from typing import Any, Callable, Dict, List, Optional, Pattern, Tuple, Type, Union
 
 from .optionals import final
@@ -14,7 +13,6 @@ __all__ = [
     'final',
     'is_final_class',
     'register_type',
-    'registered_types',
     'restricted_number_type',
     'restricted_string_type',
     'path_type',
@@ -307,6 +305,7 @@ def register_type_on_first_use(import_path: str, *args, **kwargs):
 
 def get_registered_type(type_class) -> Optional[RegisteredType]:
     if type_class not in registered_type_handlers:
+        from contextlib import suppress
         with suppress(AttributeError, ValueError):
             import_path = get_import_path(type_class)
             if import_path in registration_pending:
@@ -360,8 +359,8 @@ register_type(os.PathLike, str, str)
 register_type(complex)
 register_type_on_first_use('uuid.UUID')
 
-for path in [pathlib.Path, pathlib.PosixPath, pathlib.WindowsPath]:
-    register_type(path, str, path, type_check=isinstance)
+for _path in [pathlib.Path, pathlib.PosixPath, pathlib.WindowsPath]:
+    register_type(_path, str, _path, type_check=isinstance)
 
 
 def timedelta_deserializer(value):
diff --git a/setup.cfg b/setup.cfg
index 7d791d1..500130d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -71,7 +71,6 @@ doc =
     sphinx-autodoc-typehints>=1.19.5
 maintainer =
     bump2version>=0.5.11
-    twine>=4.0.0
 
 
 [options.package_data]
@@ -83,7 +82,7 @@ jsonargparse =
 [metadata]
 name = jsonargparse
 version = 4.18.0
-description = Parsing of command line options, yaml/jsonnet config files and/or environment variables based on argparse.
+description = Implement minimal boilerplate CLIs derived from type hints and parse from command line, config files and environment variables.
 long_description_content_type = text/x-rst
 author = Mauricio Villegas
 author_email = mauricio@omnius.com
diff --git a/sphinx/conf.py b/sphinx/conf.py
index 132107c..9fdab54 100644
--- a/sphinx/conf.py
+++ b/sphinx/conf.py
@@ -69,7 +69,14 @@ class CustomOutputChecker(OutputChecker):
 doctest.OutputChecker = CustomOutputChecker
 
 doctest_global_setup = '''
+import os
+import shutil
 import sys
+import tempfile
+from calendar import Calendar
+from dataclasses import dataclass
+from typing import Callable, Iterable, List
+import jsonargparse_tests
 from jsonargparse import *
 from jsonargparse.typing import *
 from jsonargparse_tests.base import doctest_mock_class_in_main
diff --git a/sphinx/index.rst b/sphinx/index.rst
index 8aa99b3..eb4caa6 100644
--- a/sphinx/index.rst
+++ b/sphinx/index.rst
@@ -22,6 +22,7 @@ jsonargparse
 jsonargparse.typing
 -------------------
 .. automodule:: jsonargparse.typing
+    :exclude-members: get_import_path, import_object, Path
 
 
 Index


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 944a758..c439698 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,5 +1,9 @@
 name: tests
-on: [push, pull_request]
+on:
+  push:
+    branches: [ "master" ]
+  pull_request:
+    branches: [ "master" ]
 
 jobs:
   unittest:
diff --git a/jsonargparse_tests/test_signatures.py b/jsonargparse_tests/test_signatures.py
index c3e8490..179f9b1 100755
--- a/jsonargparse_tests/test_signatures.py
+++ b/jsonargparse_tests/test_signatures.py
@@ -3,6 +3,7 @@
 import dataclasses
 import json
 import os
+import textwrap
 import unittest
 import warnings
 from calendar import Calendar, January  # type: ignore
@@ -1161,6 +1162,32 @@ class SignaturesTests(unittest.TestCase):
             self.assertEqual(cfg.model.as_dict(), yaml.safe_load(config)['model'])
 
 
+    def test_subclass_nested_error_message_indentation(self):
+        class Class:
+            def __init__(self, val: Optional[Union[int, dict]] = None):
+                pass
+
+        with mock_module(Class):
+            parser = ArgumentParser()
+            parser.add_subclass_arguments(Class, 'cls')
+            err = StringIO()
+            with redirect_stderr(err), self.assertRaises(SystemExit):
+                parser.parse_args(['--cls=Class', '--cls.init_args.val=abc'])
+            expected = textwrap.dedent('''
+            - Parser key "val":
+              Does not validate against any of the Union subtypes
+              Subtypes: (<class 'int'>, <class 'dict'>, <class 'NoneType'>)
+              Errors:
+                - Expected a <class 'int'>
+                - Expected a <class 'dict'>
+                - Expected a <class 'NoneType'>
+              Given value type: <class 'str'>
+              Given value: abc
+            ''').strip()
+            expected = textwrap.indent(expected, '    ')
+            self.assertIn(expected, err.getvalue())
+
+
 class SignaturesConfigTests(TempDirTestCase):
 
     def test_add_function_arguments_config(self):
diff --git a/jsonargparse_tests/test_typehints.py b/jsonargparse_tests/test_typehints.py
index da66315..b8edcd5 100755
--- a/jsonargparse_tests/test_typehints.py
+++ b/jsonargparse_tests/test_typehints.py
@@ -304,6 +304,13 @@ class TypeHintsTests(unittest.TestCase):
         self.assertEqual(cfg.list, ['a', 'b'])
 
 
+    def test_sequence_tuple_default(self):
+        parser = ArgumentParser()
+        parser.add_argument('--seq', type=Sequence[str], default=('one', 'two'))
+        cfg = parser.parse_args([])
+        self.assertEqual(cfg, parser.get_defaults())
+
+
     def test_tuple_ellipsis(self):
         parser = ArgumentParser(error_handler=None)
         parser.add_argument('--tuple', type=Tuple[float, ...])