classification
Title: argparse: Problem with defaults for variable nargs when using choices
Type: behavior Stage: needs patch
Components: Library (Lib) Versions: Python 3.2, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: bethard Nosy List: bethard, eric.araujo, eric.smith, regis, thesociable
Priority: normal Keywords:

Created on 2010-08-17 09:19 by thesociable, last changed 2012-01-23 22:23 by thesociable.

Messages (4)
msg114108 - (view) Author: Martin Pengelly-Phillips (thesociable) Date: 2010-08-17 09:19
Variable argument count plays badly with choices.

Example:
========
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('choices', nargs='*', default='a', choices=['a',
'b', 'c'])
>>> args = parser.parse_args()
>>> print type(args.choices)
<type 'str'>
>>> args = parser.parse_args(['a'])
>>> print type(args.choices)
<type 'list'>


If the user specifies the value on the command line then a list is used, but if the value comes from the default a string is used.
Unfortunately, changing default to a list value gives an error:
error: argument choices: invalid choice: ['a'] (choose from 'a', 'b',
'c')

Additionally, this means it is also not possible to use default=['a', 'c']. 

The current workaround is to create a custom type:

def my_type(string):
    if string not in ['a', 'b', 'c']:
        raise TypeError
    return string
msg151780 - (view) Author: Michał M. (regis) Date: 2012-01-22 17:55
Maybe it will sound strange, but what is this task REALLY about? I mean - I can see two problems here, but no clear information about which problem is a real problem and - if it is - what is the expected behavior.

Problems I can see are:
1) Type of returned value changes depending on the value source (list for user provided or list for default)
2) It's impossible to set list as 'default'

I understand that this task concentrates on 1st one, however changing behavior described in 2nd would - in my oppinion - fix 1st one too - am I right? User would "define" the returned type by defining the 'default' as a list or string. 

But - if we assume that we only discuss 1st problem here - what is the expected behavior? Provided workaround is suggesting that we expect string, but - basing on current nargs behavior and "intuition" - I'd rather expect to get a list, when I define nargs with "*" or "+". This sounds "natural" for me.

Could someone explain me the problem and the expected behavior in a clear way?

Sorry if I'm not clear, but it's my first post here and maybe I've missed something in the description or I assume something that is not true (especially that the task is quite old... ;) ).
msg151807 - (view) Author: Michał M. (regis) Date: 2012-01-23 10:50
Of course I've made a mistake:

"list for user provided or list for default"

should be:

"list for user provided or STRING for default"
msg151857 - (view) Author: Martin Pengelly-Phillips (thesociable) Date: 2012-01-23 22:23
The real issue is that the choices flag does not work with a default flag and * nargs.

The following works as expected:
>>> parser.add_argument('chosen', nargs='*', default=['a'])
>>> print(parser.parse_args())
Namespace(chosen=['a'])
>>> print(parser.parse_args(['a', 'b']))
Namespace(chosen=['a', 'b'])

Introducing a choices constraint breaks down when using the defaults:
>>> parser.add_argument('chosen', nargs='*', default=['a'], choices=['a', 'b'])
>>> print(parser.parse_args(['a']))
Namespace(chosen=['a'])
>>> print(parser.parse_args())
error: argument chosen: invalid choice: ['a'] (choose from 'a', 'b')

I would expect instead to have Namespace.chosen populated with the default list as before, but the choices constraint check does not validate correctly.

I think that changing the choices constraint logic to iterate over the default values if nargs results in a list would be a possible solution.
History
Date User Action Args
2012-01-23 22:23:14thesociablesetmessages: + msg151857
title: argparse: Problem with defaults for variable nargs -> argparse: Problem with defaults for variable nargs when using choices
2012-01-23 10:50:51regissetmessages: + msg151807
2012-01-22 17:55:46regissetnosy: + regis
messages: + msg151780
2010-11-02 22:01:00eric.araujosetnosy: + eric.araujo
2010-08-21 22:39:06georg.brandlsetassignee: bethard
2010-08-17 19:08:29eric.smithsetnosy: + eric.smith
2010-08-17 13:22:56bethardsetnosy: + bethard
stage: needs patch

versions: + Python 2.7, Python 3.2, - Python 2.6
2010-08-17 09:19:03thesociablecreate