lebrice / SimpleParsing

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

Lists of enums are parsed by value on the command line #62

Closed stevebyan closed 2 years ago

stevebyan commented 3 years ago

Describe the bug While enums seem to be parsed by member name, a list of them seems to be parsed by member value, but only if the value is a string, not an integer

To Reproduce

import enum
from typing import *
from dataclasses import dataclass

from simple_parsing import ArgumentParser
from simple_parsing.helpers import list_field

parser = ArgumentParser()

class Color(enum.Enum):
    RED = "RED"
    ORANGE = "ORANGE"
    BLUE = "BLUE"

class Temperature(enum.Enum):
    HOT = 1
    WARM = 0
    COLD = -1
    MONTREAL = -35

@dataclass
class MyPreferences:
    """You can use Enums"""
    color: Color = Color.BLUE # my favorite colour
    # a list of colors
    color_list: List[Color] = list_field(Color.ORANGE)
    # pick a temperature
    temp: Temperature = Temperature.WARM
    # a list of temperatures
    temp_list: List[Temperature] = list_field(Temperature.COLD, Temperature.WARM)

parser.add_arguments(MyPreferences, "my_preferences")
args = parser.parse_args()
prefs: MyPreferences = args.my_preferences
print(prefs)

Expected behavior A clear and concise description of what you expected to happen.

$ python issue.py --color ORANGE --color_list RED BLUE --temp MONTREAL
MyPreferences(color=<Color.ORANGE: 'ORANGE'>, color_list=[<Color.RED: 'RED'>, <Color.BLUE: 'BLUE'>], temp=<Temperature.MONTREAL: -35>, temp_list=[<Temperature.COLD: -1>, <Temperature.WARM: 0>])
$ python issue.py --color ORANGE --color_list RED BLUE --temp MONTREAL --temp_list MONTREAL
MyPreferences(color=<Color.ORANGE: 'ORANGE'>, color_list=[<Color.RED: 'RED'>, <Color.BLUE: 'BLUE'>], temp=<Temperature.MONTREAL: -35>, temp_list=[<Temperature.MONTREAL: -35>])

Actual behavior A clear and concise description of what is happening.

$ python issue.py --color ORANGE --color_list RED BLUE --temp MONTREAL --temp_list MONTREAL
usage: enums.py [-h] [--color Color] [--color_list Color] [--temp Temperature]
                [--temp_list Temperature]
enums.py: error: argument --temp_list: invalid Temperature value: 'MONTREAL'

Desktop (please complete the following information):

Additional context If I add the proper encoders and decoders, I can load and save both kinds of enum lists from .json files just fine:

@encode.register
def encode_Color(obj: Color) -> str:
    return obj.name

register_decoding_fn(Color, Color)

@encode.register
def encode_Temperature(obj: Temperature) -> str:
    return obj.name

register_decoding_fn(Temperature, lambda temp: Temperature[temp])
stevebyan commented 3 years ago

Does get_parsing_fn() in simple_parsing/wrappers/field_parsing.py need a special case for enums?

lebrice commented 2 years ago

Hey there @stevebyan , I'm really sorry for not getting back to you earlier.

This is a really nice bug. This wasn't being picked up by the tests, strangely enough. Added a test for it, was able to reproduce the issue, then added a fix. Now works correctly.

Thanks again!