Python argparse choices from an infinite set



I have the following code to create a container which pretends to behave like the set of all prime numbers (actually hides a memoised brute-force prime test)

import math

def is_prime(n):
if n == 2 or n == 3:
return True
if n == 1 or n % 2 == 0:
return False
return all(n % i for i in xrange(3, int(1 + math.sqrt(n)), 2))

class Primes(object):

def __init__(self):
self.memo = {}

def __contains__(self, n):
if n not in self.memo:
self.memo[n] = is_prime(n)
return self.memo[n]

That seems to be working so far:

>>> primes = Primes()
>>> 7 in primes
>>> 104729 in primes
>>> 100 in primes
>>> 100 not in primes

But it's not playing nicely with argparse:

>>> import argparse as ap
>>> parser = ap.ArgumentParser()
>>> parser.add_argument('prime', type=int, choices=primes, metavar='p')
_StoreAction(option_strings=[], dest='prime', nargs=None, const=None, default=None, type=<type 'int'>, choices=<__main__.Primes object at 0x7f4e21783f10>, help=None, metavar='p')
>>> parser.parse_args(['7'])
>>> parser.parse_args(['11'])
>>> parser.parse_args(['12'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/", line 1688, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/usr/lib/python2.7/", line 1720, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/lib/python2.7/", line 1929, in _parse_known_args
stop_index = consume_positionals(start_index)
File "/usr/lib/python2.7/", line 1885, in consume_positionals
take_action(action, args)
File "/usr/lib/python2.7/", line 1778, in take_action
argument_values = self._get_values(action, argument_strings)
File "/usr/lib/python2.7/", line 2219, in _get_values
self._check_value(action, value)
File "/usr/lib/python2.7/", line 2267, in _check_value
tup = value, ', '.join(map(repr, action.choices))
TypeError: argument 2 to map() must support iteration

The docs just say that

Any object that supports the in operator can be passed as the choices value, so dict objects, set objects, custom containers, etc. are all supported.
Obviously I don't want to iterate the infinite "set" of primes. So why the heck is argparse trying to map my primes? Doesn't it just need in and not in?

Continue reading...