|
3 | 3 | This module provides a compatibility layer between Borg's argparse patterns |
4 | 4 | and jsonargparse's API. Key adaptations: |
5 | 5 |
|
6 | | -1. Namespace flattening: jsonargparse creates nested namespaces for subcommands |
| 6 | +1. type+action combination: jsonargparse forbids combining type= and action= |
| 7 | + in add_argument(). Our override keeps type= at call sites for readability |
| 8 | + and wraps both into a composite action class that jsonargparse accepts. |
| 9 | +
|
| 10 | +2. Namespace flattening: jsonargparse creates nested namespaces for subcommands |
7 | 11 | (args.create.name instead of args.name). flatten_namespace() merges these |
8 | 12 | into a flat namespace compatible with Borg's command handlers. |
9 | 13 | """ |
|
14 | 18 | from jsonargparse._core import ArgumentGroup as _JAPArgumentGroup |
15 | 19 |
|
16 | 20 |
|
17 | | -class ArgumentGroup(_JAPArgumentGroup): |
18 | | - """ArgumentGroup for Borg.""" |
| 21 | +def _make_type_converting_action(base_action_name, type_fn): |
| 22 | + """Create a custom action class that wraps a standard action and applies type conversion. |
| 23 | +
|
| 24 | + jsonargparse forbids type+action, so we strip both from kwargs and replace |
| 25 | + them with a single composite action class that does type conversion + action. |
| 26 | + """ |
| 27 | + _action_map = {"append": argparse._AppendAction, "store": argparse._StoreAction} |
| 28 | + base_cls = _action_map.get(base_action_name) |
| 29 | + if base_cls is None: |
| 30 | + return None |
| 31 | + |
| 32 | + class TypeConvertingAction(base_cls): |
| 33 | + def __call__(self, parser, namespace, values, option_string=None): |
| 34 | + if type_fn is not None and isinstance(values, str): |
| 35 | + try: |
| 36 | + values = type_fn(values) |
| 37 | + except argparse.ArgumentTypeError as e: |
| 38 | + raise argparse.ArgumentError(self, str(e)) |
| 39 | + super().__call__(parser, namespace, values, option_string) |
| 40 | + |
| 41 | + TypeConvertingAction.__name__ = f"TypeConverting{base_action_name.title()}Action" |
| 42 | + return TypeConvertingAction |
| 43 | + |
| 44 | + |
| 45 | +class BorgAddArgumentMixin: |
| 46 | + """Mixin that handles the type+action combination jsonargparse forbids. |
| 47 | +
|
| 48 | + Call sites can use both type= and action= naturally (e.g. type=parse_exclude_pattern, |
| 49 | + action="append"). This mixin intercepts the call, strips both, and creates a |
| 50 | + composite action class that jsonargparse accepts. |
| 51 | + """ |
| 52 | + |
| 53 | + def add_argument(self, *args, **kwargs): |
| 54 | + action = kwargs.get("action") |
| 55 | + if action is not None and "type" in kwargs and isinstance(action, str): |
| 56 | + type_fn = kwargs.pop("type") |
| 57 | + wrapper = _make_type_converting_action(action, type_fn) |
| 58 | + if wrapper is not None: |
| 59 | + kwargs["action"] = wrapper |
| 60 | + else: |
| 61 | + # Unknown action string, put type back and hope for the best. |
| 62 | + kwargs["type"] = type_fn |
| 63 | + return super().add_argument(*args, **kwargs) |
| 64 | + |
| 65 | + |
| 66 | +class ArgumentGroup(BorgAddArgumentMixin, _JAPArgumentGroup): |
| 67 | + """ArgumentGroup that supports Borg's add_argument patterns.""" |
19 | 68 |
|
20 | 69 | pass |
21 | 70 |
|
22 | 71 |
|
23 | | -class ArgumentParser(_JAPArgumentParser): |
| 72 | +class ArgumentParser(BorgAddArgumentMixin, _JAPArgumentParser): |
24 | 73 | """ArgumentParser bridging Borg's argparse patterns with jsonargparse.""" |
25 | 74 |
|
26 | 75 | def __init__(self, *args, **kwargs): |
|
0 commit comments