Python argparse choices from an infinite set
argparse, containers, iteration, math, python
Solution
It was a documentation bug. This was issue16468, fixed in August 2019 by PR 15566.
The library as written requires the `choices` argument to be not just a container but also iterable, It tries to list the available options, which isn't going to work for your case. You could try to hack it by giving it a fake `__iter__` that just returns some informational string.
Problem
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 else: 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 True >>> 104729 in primes True >>> 100 in primes False >>> 100 not in primes True ``` 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']) Namespace(prime=7) >>> parser.parse_args(['11']) Namespace(prime=11) >>> parser.parse_args(['12']) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/argparse.py", line 1688, in parse_args args, argv = self.parse_known_args(args, namespace) File "/usr/lib/python2.7/argparse.py", line 1720, in parse_known_args namespace, args = self._parse_known_args(args, namespace) File "/usr/lib/python2.7/argparse.py", line 1929, in _parse_known_args stop_index = consume_positionals(start_index) File "/usr/lib/python2.7/argparse.py", line 1885, in consume_positionals take_action(action, args) File "/usr/lib/python2.7/argparse.py", line 1778, in take_action argument_values = self._get_values(action, argument_strings) File "/usr/lib/python2.7/argparse.py", line 2219, in _get_values self._check_value(action, value) File "/usr/lib/python2.7/argparse.py", 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`?