homepage

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 terry.reedy
Recipients bethard, chris.jerdonek, r.david.murray, terry.reedy, wim.glenn
Date 2013年01月16日.01:10:15
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1358298616.23.0.814706081214.issue16468@psf.upfronthosting.co.za>
In-reply-to
Content
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)
History
Date User Action Args
2013年01月16日 01:10:16terry.reedysetrecipients: + terry.reedy, bethard, r.david.murray, chris.jerdonek, wim.glenn
2013年01月16日 01:10:16terry.reedysetmessageid: <1358298616.23.0.814706081214.issue16468@psf.upfronthosting.co.za>
2013年01月16日 01:10:16terry.reedylinkissue16468 messages
2013年01月16日 01:10:15terry.reedycreate

AltStyle によって変換されたページ (->オリジナル) /