2

I am working on a custom Nagios script in which I would like to implement parsing of command line arguments in the same way that is used on existing Nagios Plugin check_disk.

In that plugin you have an option parameter -C to Clear current config and start over with new parameters.

Extracted from check_disk help:

check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar
           ----(3)-----    ---------(1)----------    --------(2)--------

Checks warning/critical thresholds:

  1. for volume /foo use 1000M and 500M as thresholds
  2. for volume /bar use 5% and 3%
  3. All remaining volumes use 100M and 50M

I have tried with argparse and some parameter as action='append' but repeated arguments are stored in a list and missing ones are not includes as a "None" entry.

I have also tried with parse_known_args hoping to stop parsing on first unknown argument, but I get a namespace with all known arguments and a list of unknown arguments.

I guess that my only option is using regular expressions before parsing the command line arguments.

import re
import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument('-w', help='warning')
parser.add_argument('-c', help='critical')
parser.add_argument('-p', help='path')

separator=r'-S'
groups = re.split(separator, '|'.join(sys.argv[1:])))

args = []
for idx, group_args in enumerate(groups):
   args.append('')
   args[idx]=parser.parse_args(group_args.split('|'))

I do not know if argparse can handle this kind of scenario without need to split using regular expressions.

Or if this is the best approach I can find.

This is not related with Using the same option multiple times in Python's argparse because it is not the same case, I have different optional argument not just one option with multiple values.

In example above (3) have not got option -p, (1) and (2) have it. That is one of the difference and one of the problems. If all options were mandatory, it was easy.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
outon
  • 116
  • 1
  • 9
  • What you want does not fit the `argparse` parsing approach well, if at all. It handles flagged options in the order that the user provided, and independently (except as handled by `append`). You might approximate what you want with `nargs` (e.g. 3 or +). – hpaulj Jun 23 '20 at 00:03
  • Keep in mind when designing a fancy API that you have to explain it to your user. `argparse` is simple enough that the `usage` can be auto-generated (and even that code is brittle). – hpaulj Jun 23 '20 at 00:04
  • 1
    Unfortunately,`argparse` will not directly do what you want, so your idea of pre-parsing the input arguments into groups is probably the only option. I also don't know of any other argument parsing tools that would handle this use case (and I *think* I've reviewed them all). – FMc Jun 23 '20 at 00:20
  • @FMc could you post your comment as an answer? – outon Jun 24 '20 at 07:09

1 Answers1

0

To handle this:

check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar

I can imagine starting with a namespace

args = argparse.Namespace(w:[None], c:[None], p:[None])
args = parser.parse_args(args=args)

and define a couple of custom Action classes.

For `-C` use a class that appends a `None` to each of those 3 attributes
    namespace['w'].append(None), etc

For each of `w`, `c` and `p`, an Action class, that replaces the last `None`
    with the users value.  

In other words, use the C argument to 'reset' by advancing the lists, and then use the others to to adjust the default default values.

Alternatively start with a Namespace(C=[[None, None, None]]), and add append a list with each 'C'. Then 'w' would set the namespace['C'][-1][0] etc. (Or use a list of dicts).

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Can you clarify your answer with some working code. I just tried your first two lines and got an error. I have a working code but using regular expression and pre-processing the arguments. I like your approach but I would like to know if your idea can be written down or it is just an idea. – outon Jun 23 '20 at 07:53