Repository: omni-us/jsonargparse
Pull request #699 (2025-04-02 05:46:11)

shtab hint for positionals in bash now includes the argument name
## Before submitting

- [x] Did you read the [contributing guideline](https://github.com/omni-us/jsonargparse/blob/main/CONTRIBUTING.rst)?
- [n/a] 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)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/omni-us/jsonargparse/pull/699?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`b08a1ca`)](https://app.codecov.io/gh/omni-us/jsonargparse/commit/b08a1cadf67fc2c53b416786786ad6fdf125ba21?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us) to head [(`baffe47`)](https://app.codecov.io/gh/omni-us/jsonargparse/commit/baffe473153983f7538ae75a6e0c39e5de4af3ad?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).

:white_check_mark: All tests successful. No failed tests found.

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


```diff
@@            Coverage Diff            @@
##              main      #699   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines         6755      6757    +2     
=========================================
+ Hits          6755      6757    +2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/omni-us/jsonargparse/pull/699?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=omni-us).   
:loudspeaker: Have feedback on the report? [Share it here](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).

sonarqubecloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=699) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=699&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=omni-us_jsonargparse&pullRequest=699&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=omni-us_jsonargparse&pullRequest=699&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=699&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=omni-us_jsonargparse&pullRequest=699&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=omni-us_jsonargparse&pullRequest=699)



Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 997dc53..be5fe33 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,11 @@ paths are considered internals and can change in minor and patch releases.
 v4.39.0 (2025-03-??)
 --------------------
 
+Added
+^^^^^
+- ``shtab`` hint for positionals in bash now includes the argument name (`#699
+  <https://github.com/omni-us/jsonargparse/pull/699>`__).
+
 Changed
 ^^^^^^^
 - Untyped parameters with ``None`` default no longer skipped when
diff --git a/jsonargparse/_completions.py b/jsonargparse/_completions.py
index d6e7cf4..93fe2e3 100644
--- a/jsonargparse/_completions.py
+++ b/jsonargparse/_completions.py
@@ -166,6 +166,8 @@ def shtab_prepare_action(action, parser) -> None:
         choices = get_typehint_choices(action._typehint, prefix, parser, skip)
         if shtab_shell.get() == "bash":
             message = f"Expected type: {type_to_str(action._typehint)}"
+            if action.option_strings == []:
+                message = f"Argument: {action.dest}; " + message
             add_bash_typehint_completion(parser, action, message, choices)
             choices = None
     elif isinstance(action, _ActionHelpClassPath):


Test patch:
diff --git a/jsonargparse_tests/test_shtab.py b/jsonargparse_tests/test_shtab.py
index 90be331..8c21213 100644
--- a/jsonargparse_tests/test_shtab.py
+++ b/jsonargparse_tests/test_shtab.py
@@ -47,8 +47,17 @@ def get_shtab_script(parser, shell):
     return get_parse_args_stdout(parser, [f"--print_shtab={shell}"])
 
 
+def is_positional(dest, parser):
+    if parser is not None:
+        action = next(a for a in parser._actions if a.dest == dest)
+        return action.option_strings == []
+    return False
+
+
 def assert_bash_typehint_completions(subtests, shtab_script, completions):
+    parser = None
     if isinstance(shtab_script, ArgumentParser):
+        parser = shtab_script
         shtab_script = get_shtab_script(shtab_script, "bash")
     with tempfile.TemporaryDirectory() as tmpdir:
         shtab_script_path = Path(tmpdir) / "comp.sh"
@@ -67,6 +76,8 @@ def assert_bash_typehint_completions(subtests, shtab_script, completions):
                     assert f"Expected type: {typehint}; {extra} matched choices" in err.decode()
                 else:
                     assert f"Expected type: {typehint}; Accepted by subclasses: {extra}" in err.decode()
+                if is_positional(dest, parser):
+                    assert f"Argument: {dest}; Expected type: {typehint}" in err.decode()
 
 
 def test_bash_any(parser, subtests):