This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author fhsxfhsx
Recipients fhsxfhsx, n8falke, paul.j3
Date 2020-01-14.08:14:24
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1578989665.47.0.272868367103.issue36078@roundup.psfhosted.org>
In-reply-to
Content
I ran into the same issue and looked into the code, and found it more complicated than I thought. The more I went on, more issues occur. I wonder if I should open a new issue, but I will first comment here. If you feel like this should be a new issue, I will open one then. And I apologize in advance for possible vaguenesses in this comment because I modified it several times as I explored the code and found more issues. (also because of my poor English):)

It seems the issue happens only on positional arguments but not optional ones. Empty optional arguments will not call `take_action` and default values are handled and converted after consuming all arguments.

It also leads to inconsistancy between positional and optional arguments behaviour. Positional arguments always go through `take_action`, but optional arguments don't if an argument doesn't appear.

This inconsistancy causes another I think is strange behaviour,

    parser = ArgumentParser()
    parser.add_argument('i', action='count')
    parser.parse_args([])

got

    Namespace(i=1)

On the other hand, in `_get_values` function, `_check_value` is called to handle `choices=`, but there is no such guard for optional arguments, which means,

    parser = ArgumentParser()
    parser.add_argument('-i', nargs='?', type=int, default='2', choices=[1])
    parser.parse_args([])

doesn't raise an error.

Besides Paul's two instructive solutions, I think it better to make both sides behave the same. However, I found things seem not that simple.

First, ZERO_OR_MORE, no default value, positional arguments have `required=True` by default, but

    parser.add_argument('foo', nargs='*')
    parser.parse_args([])

got no problems. So it at least appears not required. (The document says `required` is only for optionals, so I guess it's just a implementation level but not a user level thing)

Second, the last case above gives

    Namespace(foo=[])

which seems logically incorrect or at least controversial, because the default is not set and you give no arguments, how does this list come? The document says nothing about the case (it's true it's a very corner one) and it also differs from the optional arguments case which gives

    Namespace(foo=None)

A walk around which doesn't change it is possible and I've written a patch fixing it.
And I'm not sure what we usually do if I propose to make them give the same result, is a PEP needed or I just raise a discussion about it? The change might break current code.
History
Date User Action Args
2020-01-14 08:14:25fhsxfhsxsetrecipients: + fhsxfhsx, paul.j3, n8falke
2020-01-14 08:14:25fhsxfhsxsetmessageid: <1578989665.47.0.272868367103.issue36078@roundup.psfhosted.org>
2020-01-14 08:14:25fhsxfhsxlinkissue36078 messages
2020-01-14 08:14:24fhsxfhsxcreate