lebrice / SimpleParsing

Simple, Elegant, Typed Argument Parsing with argparse
MIT License
410 stars 51 forks source link

Bug when parsing N lists of N elements each, without a default value passed to `add_arguments` #19

Open lebrice opened 4 years ago

lebrice commented 4 years ago

Describe the bug OK so this one is tricky and very specific, and shouldn't impact anyone really. When we're trying to parse multiple lists using the same attribute (no prefixing, aka ConflictResolution.ALWAYS_MERGE mode), When the list length and the number of instances to parse is the same, AND there is no default value passed to add_arguments, it gets parsed as multiple lists each with only one element, rather than duplicating the field's default value correctly.

For example:

from dataclasses import dataclass, field
from typing import List, Tuple

from simple_parsing import ArgumentParser, ConflictResolution

@dataclass
class CNNStack():
    name: str = "stack"
    num_layers: int = 3
    kernel_sizes: Tuple[int,int,int] = (7, 5, 5)
    num_filters: List[int] = field(default_factory=[32, 64, 64].copy)

parser = ArgumentParser(conflict_resolution=ConflictResolution.ALWAYS_MERGE)

num_stacks = 3
for i in range(num_stacks):
    parser.add_arguments(CNNStack, dest=f"stack_{i}")

# Parse with no arguments (should get all default values)
args = parser.parse_args()
stack_0 = args.stack_0
stack_1 = args.stack_1
stack_2 = args.stack_2

print(stack_0, stack_1, stack_2, sep="\n")
expected = """
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=[32, 64, 64])
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=[32, 64, 64])
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=[32, 64, 64])
"""
actual = """
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=32)
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=64)
CNNStack(name='stack', num_layers=3, kernel_sizes=(7, 5, 5), num_filters=64)
"""