Terry J. Reedy added the comment:

I took a good look at the 3.3 code. With respect to the main purpose of choices 
-- checking user input -- argparse does not require that choices be iterable, 
as it *does* use 'in', as it should. Line 2274:

        if action.choices is not None and value not in action.choices:

So unless the usage message is generated even when not needed (I did not delve 
that far), non-iterables should work now as long as the user does not request 
the usage message or make an input mistake.

If that is so, then this issue is strictly about the string representation of 
non-iterable choices. A mis-behaving tail is not a reason to kill the dog ;-). 
The easy answer, and the only sensible one I see, is to use either str() or 
repr(). But how to do that? I think this and #16418 have to be fixed together.

The current format-by-iteration method, used for both usage and exceptions, 
works well for small iterable collections. But it is obnoxious for non-small 
collections. As I mentioned before, it will just hang for infinite iterables, 
which is even worse. So the method needs to be changed anyway. And to do that, 
it should be factored out of the three places where it is currently done 
in-line.

At 557:
        elif action.choices is not None:
            choice_strs = [str(choice) for choice in action.choices]
            result = '{%s}' % ','.join(choice_strs)

To match the code below, so it can be factored out into a function,
change the last two lines to

            choices_str = ','.join(str(c) for c in action.choices)
            result = '{%s}' % choices_str

At 597: (note that 'params' is adjusted action.__dict__)
        if params.get('choices') is not None:
            choices_str = ', '.join([str(c) for c in params['choices']])
            params['choices'] = choices_str

The intermediate list in the 2nd line is not needed
            choices_str = ', '.join(str(c) for c in params['choices'])

I am aware of but do not understand ',' versus ', ' as joiner. I also do not 
understand why both versions of choices_str are needed. Are there two different 
usage messages? 

At 2276:
                    'choices': ', '.join(map(repr, action.choices))}

or, replacing map with comprehension
                    choices_str = ', '.join(repr(c) for c in action.choices)
                    'choices': choices_str}

Now define choices_str(src, joiner, rep), delete 559 and 598, and modify

559: ... result = '{%s}' % choices_str(action.choices, ',', str)

599: ... params['choices'] = choices_str(param['choices'], ', ', str)

2276: ... 'choices': choices_str(action.choices, ', ', repr}

(I am assuming that the two joiners are really needed. If not, delete.)

Now we should be able to write choices_str to solve all 3 problems in the two 
issues. My coded suggestion:

from itertools import islice
N = 21  # maximum number (+1) of choices for the current nice string.
# This is just an illustrative value, experiment might show better #.

def choices_str(src, joiner, rep):
  prefix = list(islice(src, N))
  if len(prefix) < N:  # short iterables
    return joiner.join(rep(c) for c in prefix)  # current string
  else:
    try:  # non-short sliceable finite sequences
      head = joiner.join(rep(c) for c in src[:N//2])
      tail = joiner.join(rep(c) for c in src[N//4:])
      return head + ' ..., ' + tail
    except AttributeError:  # no __getindex__(slice), everything else
      return repr(src)

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue16468>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to