Skip to content

negative_option with argument_generation_mode=ArgumentGenerationMode.NESTED cannot resolve conflicts #364

Description

@wogns3623

Describe the bug
flag with explict negative_option cannot resolve conflict when argument_generation_mode=ArgumentGenerationMode.NESTED mode.

To Reproduce

from dataclasses import dataclass
from simple_parsing import ArgumentParser, ArgumentGenerationMode, flag

@dataclass
class BaseConfig:
    foo: int = 1

@dataclass
class QuantizerConfig:
    asym: bool = flag(default=False, negative_option="sym")

if __name__ == "__main__":
    parser1 = ArgumentParser()
    parser1.add_arguments(BaseConfig, "base")
    parser1.add_arguments(QuantizerConfig, "w")
    parser1.add_arguments(QuantizerConfig, "a")
    print("parser1:")
    parser1.print_help()

    parser2 = ArgumentParser(argument_generation_mode=ArgumentGenerationMode.NESTED)
    parser2.add_arguments(BaseConfig, "base")
    parser2.add_arguments(QuantizerConfig, "w")
    parser2.add_arguments(QuantizerConfig, "a")
    print("parser2:")
    parser2.print_help()

Expected behavior
Like parser1, parser2 should resolve conflicts in QuantizerConfig .syminto w.sym and a.sym.

$ python issue.py
parser1:
usage: issue.py [-h] [--foo int] [--w.asym bool] [--a.asym bool]

options:
  -h, --help            show this help message and exit

BaseConfig ['base']:
  BaseConfig(foo: int = 1)

  --foo int             (default: 1)

QuantizerConfig ['w']:
  QuantizerConfig(asym: bool = False)

  --w.asym bool, --w.sym bool
                        (default: False)

QuantizerConfig ['a']:
  QuantizerConfig(asym: bool = False)

  --a.asym bool, --a.sym bool
                        (default: False)
parser2:
usage: issue.py [-h] [--foo int] [--w.asym bool] [--a.asym bool]

options:
  -h, --help            show this help message and exit

BaseConfig ['base']:
  BaseConfig(foo: int = 1)

  --base.foo int             (default: 1)

QuantizerConfig ['w']:
  QuantizerConfig(asym: bool = False)

  --w.asym bool, --w.sym bool
                        (default: False)

QuantizerConfig ['a']:
  QuantizerConfig(asym: bool = False)

  --a.asym bool, --a.sym bool
                        (default: False)

Actual behavior
parser2 cannot resolve conflict on QuantizerConfig.sym into w.sym and a.sym.

$ python issue.py 
parser1:
usage: issue.py [-h] [--foo int] [--w.asym bool] [--a.asym bool]

options:
  -h, --help            show this help message and exit

BaseConfig ['base']:
  BaseConfig(foo: int = 1)

  --foo int             (default: 1)

QuantizerConfig ['w']:
  QuantizerConfig(asym: bool = False)

  --w.asym bool, --w.sym bool
                        (default: False)

QuantizerConfig ['a']:
  QuantizerConfig(asym: bool = False)

  --a.asym bool, --a.sym bool
                        (default: False)
parser2:
Traceback (most recent call last):
  File "/home/user/reproduce/issue.py", line 28, in <module>
    parser2.print_help()
  File "/home/user/reproduce/.venv/lib/python3.12/site-packages/simple_parsing/parsing.py", line 382, in print_help
    self._preprocessing(args=list(args) if args else [])
  File "/home/user/reproduce/.venv/lib/python3.12/site-packages/simple_parsing/parsing.py", line 550, in _preprocessing
    wrapped_dataclass.add_arguments(parser=self)
  File "/home/user/reproduce/.venv/lib/python3.12/site-packages/simple_parsing/wrappers/dataclass_wrapper.py", line 214, in add_arguments
    _ = group.add_argument(*wrapped_field.option_strings, **arg_options)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/argparse.py", line 1500, in add_argument
    return self._add_action(action)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/argparse.py", line 1705, in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/argparse.py", line 1514, in _add_action
    self._check_conflict(action)
  File "/home/user/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/argparse.py", line 1654, in _check_conflict
    conflict_handler(action, confl_optionals)
  File "/home/user/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/lib/python3.12/argparse.py", line 1663, in _handle_conflict_error
    raise ArgumentError(action, message % conflict_string)
argparse.ArgumentError: argument --a.asym/--sym: conflicting option string: --sym

Desktop (please complete the following information):

  • Version 0.1.8
  • Python version: 3.12.13

Additional context
Through simple debugging, I confirmed that in argument_generation_mode=ArgumentGenerationMode.FLAT mode, the initial conflict occurring at https://github.com/lebrice/SimpleParsing/blob/3b5bc2377817ee8ee4e5f12709b2db173320b3c1/simple_parsing/parsing. py#L534 sets field_wrapper.prefix as the root path, and that the conflict with negative_option is resolved via arg_options["_conflict_prefix"].
However, in argument_generation_mode=ArgumentGenerationMode.NESTED mode, this process is omitted because there is no conflict between field_wrapper.option_strings from the outset, and it appears that no prefix is added to negative_option.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions