I need to write a django management command (not related to django) for starting workers. I take the inspiration from docker-compose up
and would like the following behavior:
>>> services = ['a', 'b', 'c']
>>> import argparse
>>> ap = argparse.ArgumentParser()
>>> ap.add_argument('services', ???)
>>> ap.parse_args(''.split())
Namespace(services=[])
>>> ap.parse_args('a b'.split())
Namespace(services=['a', 'b'])
>>> ap.parse_args('a b d'.split())
: error: argument services: invalid choice: 'd' (choose from 'a', 'b', 'c')
>>> ap.parse_args('a b b'.split())
: error: argument services: duplicated choice: 'b'
Currently, I have tested several approaches, but the main roadblock is that if choices=services
is supplied, nargs='*'
doesn't allow 0 arguments anymore.
>>> ap.add_argument('services', choices=services, nargs='*')
>>> ap.parse_args(''.split())
usage: [-h] [{a,b,c} [{a,b,c} ...]]
: error: argument services: invalid choice: [] (choose from 'a', 'b', 'c')
While there is one working solution (having a custom type) and one workaround (just validate later) they don't feel right. (One other solution is posted as answer, but I'd love to see better solutions if it exists at all.)
(It looks like the "no duplicate" feature isn't native in Python and would need overriding argparse.Action
, probably starting here.)
Edit: I have given up on insisting that it must work like the spec above. The workaround is much nicer. I simply do ap.add_argument('--a', dest='services', action='append_const', const=AaaService)
, and my namespace has a services
attr that contains all the service classes I want to run.