Skip to content

use jsonargparse#9413

Open
ThomasWaldmann wants to merge 21 commits intoborgbackup:masterfrom
ThomasWaldmann:jsonargparse2
Open

use jsonargparse#9413
ThomasWaldmann wants to merge 21 commits intoborgbackup:masterfrom
ThomasWaldmann:jsonargparse2

Conversation

@ThomasWaldmann
Copy link
Member

@ThomasWaldmann ThomasWaldmann commented Feb 25, 2026

Description

Adopt jsonargparse, fixes #6551.

Checklist

  • PR is against master (or maintenance branch if only applicable there)
  • New code has tests and docs where appropriate
  • Tests pass (run tox or the relevant test subset)
  • Commit messages are clean and reference related issues

@ThomasWaldmann ThomasWaldmann force-pushed the jsonargparse2 branch 2 times, most recently from 89f6898 to 5aa0956 Compare February 25, 2026 14:08
@ThomasWaldmann ThomasWaldmann mentioned this pull request Feb 25, 2026
@codecov
Copy link

codecov bot commented Feb 25, 2026

Codecov Report

❌ Patch coverage is 87.08010% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.45%. Comparing base (0b05b44) to head (e4e484f).
⚠️ Report is 3 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/borg/helpers/parseformat.py 67.21% 30 Missing and 10 partials ⚠️
src/borg/patterns.py 66.66% 3 Missing ⚠️
src/borg/archiver/__init__.py 93.75% 1 Missing and 1 partial ⚠️
src/borg/archiver/diff_cmd.py 66.66% 2 Missing ⚠️
src/borg/archiver/transfer_cmd.py 66.66% 2 Missing ⚠️
src/borg/archiver/completion_cmd.py 95.23% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9413      +/-   ##
==========================================
- Coverage   76.47%   76.45%   -0.03%     
==========================================
  Files          85       86       +1     
  Lines       14803    14905     +102     
  Branches     2213     2248      +35     
==========================================
+ Hits        11321    11396      +75     
- Misses       2803     2820      +17     
- Partials      679      689      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ThomasWaldmann ThomasWaldmann changed the title use jsonargparse, try 2 use jsonargparse Feb 26, 2026
@ThomasWaldmann ThomasWaldmann force-pushed the jsonargparse2 branch 2 times, most recently from 14adfd2 to c6452f7 Compare February 26, 2026 10:44
@ThomasWaldmann
Copy link
Member Author

@mauvilsa can you have a look, please?

maybe look at the individual commits.

is that flatten_namespace code in borg.helpers.argparsing interesting for other jsonargparse users?

had to import some internal stuff to implement borg completion command, guess there is currently no better way?

guess this can soon be merged - it does not use most features of jsonargparse, but that should be in future PRs.

@ThomasWaldmann
Copy link
Member Author

ThomasWaldmann commented Feb 27, 2026

Note: I am currently trying to get rid of these _maincommand, _midcommand, _subcommand suffixes.

Guess they are not needed because jsonargparse supports nested namespaces to separate the different command levels.

Also, the suffixes showed up in generated configs, making them ugly...

Update: done!

Copy link

@mauvilsa mauvilsa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tried to run the code yet. But might do that in case I see weird behaviors.

"info",
parents=[common_parser],
subparser = ArgumentParser(
parents=[mid_common_parser],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there aren't tests in jsonargparse related to parent parsers. Could be that it works just fine. But I should take note of this to have a closer look.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems to work, at least neither our automated tests nor me practically trying it noticed an issue yet.

Comment on lines +9 to +11
from jsonargparse._actions import _ActionSubCommands # noqa: F401
from jsonargparse._completions import prepare_actions_context, shtab_prepare_actions # noqa: F401
from jsonargparse._completions import bash_compgen_typehint # noqa: F401

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look at this in more detail. Eventually there shouldn't be private imports. But I need to see if there is already an alternative, or a modification in jsonargparse is required.

Previously, ArgparsePatternAction and ArgparsePatternFileAction
appended recursion roots directly to args.paths. This mixed
CLI positional paths with paths derived from patterns
(e.g., using the `R` root path command in a pattern file),
complicating downstream argument parsing and future jsonargparse
integration.

This commit introduces `args.pattern_roots` as a dedicated list
for these accumulated root paths:
- All argparse definition sites now initialize `pattern_roots=[]` alongside `paths=[]`
- ArgparsePatternAction and ArgparsePatternFileAction write directly to `args.pattern_roots`
- The build_matcher utility accepts both `include_paths` and `pattern_roots` and concatenates them internally
- `create_cmd` iterations explicitly concatenate both lists before processing

This ensures `args.paths` strictly reflects exactly what the
user provided positionally, paving the way for a clean
jsonargparse implementation without regressions in pattern behavior.
Guess it was triggered due to naming the variable "token",
maybe "sort_key" is less problematic.
other validators / specs are also there and it is easier to maintain
as Python code. the compress module is Cython code.
…approach

The old code worked around argparse's flat namespace by appending
_maincommand / _midcommand / _subcommand suffixes to every common
option's dest (e.g. log_level_subcommand), then resolving them with
CommonOptions.resolve() after parsing.  This polluted config key names
and env var names (BORG_LOG_LEVEL_SUBCOMMAND instead of BORG_LOG_LEVEL).

jsonargparse nests subcommand arguments automatically, so the workaround
is no longer needed.  Each parser level now registers common options with
their clean dest name.  flatten_namespace() is updated to a two-pass
depth-first walk so the most-specific (innermost) value wins naturally:

  borg --info create --debug  →  log_level = "debug"  (subcommand wins)
  borg --info create          →  log_level = "info"   (top-level fills gap)

For append-action options (--debug-topic) values from all levels are
merged (outer + inner) to preserve the accumulation behaviour.
Borg's ArgumentParser (in borg.helpers.argparsing) now subclasses
jsonargparse's ArgumentParser and pre-sets two defaults that every
borg parser uses:

  formatter_class = RawDescriptionHelpFormatter
  add_help        = False
@ThomasWaldmann
Copy link
Member Author

(rebased on current master, added auto env var support)

@ThomasWaldmann
Copy link
Member Author

ThomasWaldmann commented Feb 27, 2026

Hmm, I can't get "store_true" stuff working correctly:

subparser.add_argument("-s", "--stats", dest="stats", action="store_true", help="print stats")

With that and without the value being set in the default config, overriding via BORG_CREATE__STATS=true crashes the code, because it puts a str into args.stat instead of the expected bool.

If I set the value in the default config, it works, but I can not overwrite it with the env var.

A hack with ActionYesNo also didn't work, because it does not like short options like -s. omni-us/jsonargparse#355 (comment)

Another weird hack: omni-us/jsonargparse#497 - is that the intended way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

argparse++

2 participants