I would like to know how to get order of optional argument passed from commandline to argparse
I have image processing class which is able to apply different actions to image - like rotate, crop, resize...
And order in which these actions are applied is often essential (for example: you want to crop image before you resize it)
I have this code:
parser = argparse.ArgumentParser(description='Image processing arguments')
parser.add_argument('source_file', help='source file')
parser.add_argument('target_file', help='target file')
parser.add_argument('-resize', nargs=2, help='resize image', metavar=('WIDTH', 'HEIGHT'))
parser.add_argument('-rotate', nargs=1, help='rotate image', metavar='ANGLE')
parser.add_argument('-crop', nargs=4, help='crop image', metavar=('START_X','START_Y','WIDTH','HEIGHT'))
ar = parser.parse_args()
print ar
But - no matter in which order I pass parameters to script:
cmd.py test.jpg test2.jpg -crop 10 10 200 200 -resize 450 300
cmd.py test.jpg test2.jpg -resize 450 300 -crop 10 10 200 200
in Namespace items are always in same order (alphabetical I suppose):
Namespace(crop=['10', '10', '200', '200'], resize=['450', '300'], rotate=None, source_file='test.jpg', target_file='test
2.jpg')
Is there way to order them by position in command line string or to get their index?
Combining Positional and Optional arguments Note that the order does not matter.
Optional Arguments To add an optional argument, simply omit the required parameter in add_argument() .
The argparse module makes it easy to write user-friendly command-line interfaces. The program defines what arguments it requires, and argparse will figure out how to parse those out of sys.argv .
You could always peek at sys.argv
which is a list (and thus ordered) and simply iterate over it checking which argument comes first or use the list.index()
to see the respective positions of your keywords in the list...
sys.argv
contains a list of the words entered in the command line (the delimiter of such "word" is a space unless a string was surrounded by quotation marks). This means that if the user entered something like ./my_proggie -resize 500
then sys.argv
would contain a list like this: ['./my_proggie', '-resize', '500']
.
The Namespace is a simple object whose str()
lists its attributes according to the order of the keys in its __dict__
. Attributes are set with setattr(namespace, dest, value)
.
One solution is to define a custom Namespace class. For example:
class OrderNamespace(argparse.Namespace):
def __init__(self, **kwargs):
self.__dict__['order'] = []
super(OrderNamespace, self).__init__(**kwargs)
def __setattr__(self,attr,value):
self.__dict__['order'].append(attr)
super(OrderNamespace, self).__setattr__(attr, value)
and use
args = parser.parse_args(None, OrderNamespace())
producing for your two examples
OrderNamespace(crop=..., order=[..., 'crop', 'resize'], resize=...)
OrderNamespace(crop=..., order=[..., 'resize', 'crop'], resize=...)
The order
attribute gives the order in which the other attributes are set. The initial items are for defaults and the file positionals. Adding default=argparse.SUPPRESS
to the arguments will suppress some of these items. This custom class could be more elaborate, using for example an OrderedDictionary, only noting the order for selected arguments, or using order
to control the display of the attributes.
Another option is to use a custom Action class that creates this order
attribute, e.g.
class OrderAction(argparse._StoreAction):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
order = getattr(namespace, 'order') if hasattr(namespace, 'order') else []
order.append(self.dest)
setattr(namespace, 'order', order)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With