-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
Improve error messages for argparse choices using enum #86667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Summary The argparse module mentions that it will happily accept an enum for the choices argument option [1]. There are currently 2 issues with this:
Example of 1 For example using the GameMove example in the argparse documentation: class GameMove(Enum):
ROCK = 'rock'
PAPER = 'paper'
SCISSORS = 'scissors'
parser = argparse.ArgumentParser(prog='game.py')
parser.add_argument('move', type=GameMove, choices=GameMove)
parser.print_help() Gives the usage:
As you can see, the string representations of the valid enum members is used instead of the values. Example of 2 Below is an example of the error message shown for invalid enum values, with metavar specified: parser = argparse.ArgumentParser(prog='game.py')
parser.add_argument('move', metavar='your-move', type=GameMove, choices=GameMove)
parser.parse_args(['asdf']) Gives the following output:
This is in contrast with using standard iterable-based choices: parser = argparse.ArgumentParser(prog='game.py')
parser.add_argument('move', metavar='your-move', choices=[x.value for x in GameMove])
parser.parse_args(['asdf']) Gives the following output:
Analysis of 2 The reason for this behaviour is because argparse attempts to convert to the correct type before checking the choices membership and an invalid enum value results in the first error message. It would be helpful (& consistent) if the choices are also displayed along with the invalid value message. Possible Solution I believe that both issues could be solved by using the enum member values in the choices and then checking for choice membership _before_ the value is converted to an enum (ie for enums only). |
I'm inclined to state in the docs that choices is designed to work with collections of strings and that there is no special support for enums. Paul, what do you think? |
https://bugs.python.org/issue25061 also had some discussion over error message display for enums |
Oh apologies, I had "open" selected when I searched for prior issues. Upon reading that issue I agree with Mr Hettinger's points about enum values not being a concern of the parser. The solution for my needs was simple enough: I made my own action which simply set choices based on member values (I'm using user-friendly strings) and converted to the correct type upon being called [1]. Instead of removing any mention of enums from the docs - would a small example showing how to deal with them be worthwhile? [1] class EnumAction(argparse.Action):
def __init__(self, option_strings, dest, **kwargs):
kwargs["choices"] = [member.value for member in enum_class]
super().__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, values, option_string):
if isinstance(values, str):
converted_values = enum_class(values)
else:
converted_values = [enum_class(value) for value in values]
setattr(namespace, self.dest, converted_values)
return EnumAction |
choices is fine for a few strings, but quickly becomes awkward with other types and large numbers. The testing isn't an issue, since it just does a simple Custom type or action is the best alternative. I'm in favor omitting the enums mention in the docs, since it seems to be more confusing than helpful. |
How does PR 23563 look to you all? |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: