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.

Activity

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

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