Determine actually given command line arguments

H

Henry Leyh

Hello,
I am writing a program that gets its parameters from a combination of
config file (using configparser) and command line arguments (using
argparse). Now I would also like the program to be able to _write_ a
configparser config file that contains only the parameters actually
given on the commandline. Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I have tried giving the arguments default values and then looking for
those having a non-default value but this is really awkward, especially
if it comes to non-string arguments. Also, parsing sys.argv looks
clumsy because you have to keep track of short and long options with and
without argument etc. i.e. all things that I got argparse for in the
first place.

Thanks && Greetings,
Henry
 
C

Colin J. Williams

Hello,
I am writing a program that gets its parameters from a combination of
config file (using configparser) and command line arguments (using
argparse). Now I would also like the program to be able to _write_ a
configparser config file that contains only the parameters actually
given on the commandline. Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I have tried giving the arguments default values and then looking for
those having a non-default value but this is really awkward, especially
if it comes to non-string arguments. Also, parsing sys.argv looks
clumsy because you have to keep track of short and long options with and
without argument etc. i.e. all things that I got argparse for in the
first place.

Thanks && Greetings,
Henry
Try sys.argv

Colin W.
 
R

Roy Smith

Henry Leyh said:
Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']
 
D

Dave Angel

Henry Leyh said:
Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']

Colin & Roy:
The OP mentioned sys.argv in his original query.
 
J

Jussi Piitulainen

Try sys.argv

You people should read what you quote, or what you don't quote when
you cut the relevant portion.

Q. ... parsing sys.argv looks clumsy because ...
A. Try sys.argv

I mean, huh?
 
H

Henry Leyh

Henry Leyh said:
Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']

Thanks, but as I wrote in my first posting I am aware of sys.argv and
was hoping to _avoid_ using it because I'd then have to kind of
re-implement a lot of the stuff already there in argparse, e.g. parsing
sys.argv for short/long options, flag/parameter options etc.

I was thinking of maybe some sort of flag that argparse sets on those
optional arguments created with add_argument() that are really given on
the command line, i.e. those that it stumbles upon them during parse_args().

Regards,
Henry
 
H

Henry Leyh

Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().


I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']

Thanks, but as I wrote in my first posting I am aware of sys.argv and was
hoping to _avoid_ using it because I'd then have to kind of re-implement a
lot of the stuff already there in argparse, e.g. parsing sys.argv for
short/long options, flag/parameter options etc.

I was thinking of maybe some sort of flag that argparse sets on those
optional arguments created with add_argument() that are really given on the
command line, i.e. those that it stumbles upon them during parse_args().

I don't know about that but I imagine that you could compare values
with their defaults to see which have been changed.

Yes, I was trying that and it sort of works with strings if I use
something sufficiently improbable like "__UNSELECTED__" as default. But
it gets difficult with boolean or even number arguments where you just
may not have valid "improbable" defaults. You could now say, so what,
it's the default anyway. But in my program I would like to distinguish
between given and not given arguments rather than between default and
non-default.

Regards,
Henry
 
S

Skip Montanaro

Yes, I was trying that and it sort of works with strings if I use something sufficiently improbable like "__UNSELECTED__" as default. But it gets difficult with boolean or even number arguments where you just may not have valid "improbable" defaults. You could now say, so what, it's the default anyway. But in my program I would like to distinguish between given and not given arguments rather than between default and non-default.

Initialize all your arg variables to None, then after command line
processing, any which remain as None weren't set on the command line.
At that point, set them to the actual defaults. I think that's a
pretty common idiom.

Note: I am an old cranky dude and still use getopt. This idiom is
pretty easy there. YMMV with argparse or optparse.

Skip
 
W

Wayne Werner

Yes, I was trying that and it sort of works with strings if I use something
sufficiently improbable like "__UNSELECTED__" as default. But it gets
difficult with boolean or even number arguments where you just may not have
valid "improbable" defaults. You could now say, so what, it's the default
anyway. But in my program I would like to distinguish between given and not
given arguments rather than between default and non-default.

Have you looked into docopt? It's pretty awesome, and might really help in
this case.

HTH,
-W
 
H

Henry Leyh

Initialize all your arg variables to None, then after command line
processing, any which remain as None weren't set on the command line.
At that point, set them to the actual defaults. I think that's a
pretty common idiom.

Note: I am an old cranky dude and still use getopt. This idiom is
pretty easy there. YMMV with argparse or optparse.

Unfortunately, argparse wants to know the type of the argument and the
boolean arguments (those with action=store_true) can't be initialized
with None.

However, maybe I could convert boolean arguments to something like

parser.add_argument('--foo', type=str, nargs='?', const='True',
default=None)

I'd then have to check for string 'True' rather than for boolean True,
though.

Regards,
Henry
 
R

Roy Smith

Henry Leyh said:
Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']

Thanks, but as I wrote in my first posting I am aware of sys.argv and
was hoping to _avoid_ using it because I'd then have to kind of
re-implement a lot of the stuff already there in argparse, e.g. parsing
sys.argv for short/long options, flag/parameter options etc.

Sorry, I missed that.

I'm not clear on exactly what you're trying to do. You say:
Now I would also like the program to be able to _write_ a
configparser config file that contains only the parameters actually
given on the commandline.

I'm guessing what you're trying to do is parse the command line first,
then anything that was set there can get overridden by a value in the
config file? That seems backwards. Usually, the order is:

1) built-in default
2) config file (possibly a system config file, then a per-user one)
3) environment variable
4) command-line argument

It sounds like you're doing it in the reverse order -- allowing the
config file to override the command line.
 
H

Henry Leyh

Is there a simple way to determine which
command line arguments were actually given on the commandline, i.e. does
argparse.ArgumentParser() know which of its namespace members were
actually hit during parse_args().

I think what you're looking for is sys.argv:

$ cat argv.py
import sys
print sys.argv

$ python argv.py foo bar
['argv.py', 'foo', 'bar']

Thanks, but as I wrote in my first posting I am aware of sys.argv and
was hoping to _avoid_ using it because I'd then have to kind of
re-implement a lot of the stuff already there in argparse, e.g. parsing
sys.argv for short/long options, flag/parameter options etc.

Sorry, I missed that.

I'm not clear on exactly what you're trying to do. You say:
Now I would also like the program to be able to _write_ a
configparser config file that contains only the parameters actually
given on the commandline.

I'm guessing what you're trying to do is parse the command line first,
then anything that was set there can get overridden by a value in the
config file? That seems backwards. Usually, the order is:

1) built-in default
2) config file (possibly a system config file, then a per-user one)
3) environment variable
4) command-line argument

It sounds like you're doing it in the reverse order -- allowing the
config file to override the command line.

No. The program reads a general config file in $HOME, something like
~/.programrc; then parses the command like for '-c FILE' and, if FILE is
present reads it; then parses the command line remains for more
arguments which overwrite everything previously set. (For the record,
this split parsing is done with two argparse parsers. The first parses
for '-c FILE' with parse_known_args(). If there is a FILE, its contents
is used as defaults for a second parser (using set_options()) which then
parses the remains that were returned by the first parser's
parse_known_args().)

But now I would also like to be able to _write_ such a config file FILE
that can be read in a later run. And FILE should contain only those
arguments that were given on the command line.

Say, I tell argparse to look for arguments -s|--sopt STRING, -i|--iopt
INT, -b|--bopt [BOOL], -C CONFFILE. Then 'prog -s bla -i 42 -C cfile'
should produce a confparser compatible cfile which contains

[my_options]
sopt = blah
iopt = 42

and not 'bopt = False' (if False was the program's default for bopt).

Regards,
Henry
 
J

Jussi Piitulainen

Henry said:
But now I would also like to be able to _write_ such a config file
FILE that can be read in a later run. And FILE should contain only
those arguments that were given on the command line.

Say, I tell argparse to look for arguments -s|--sopt STRING,
-i|--iopt INT, -b|--bopt [BOOL], -C CONFFILE. Then 'prog -s bla -i
42 -C cfile' should produce a confparser compatible cfile which
contains

[my_options]
sopt = blah
iopt = 42

and not 'bopt = False' (if False was the program's default for
bopt).

Could you instead write those options that differ from the defaults?
You could parse an actual command line and an empty command line, and
work out the difference.

So 'prog -i 3' would not cause 'iopt = 3' to be written if 3 is the
default for iopt, but would that be a problem?
 
H

Henry Leyh

Henry said:
But now I would also like to be able to _write_ such a config file
FILE that can be read in a later run. And FILE should contain only
those arguments that were given on the command line.

Say, I tell argparse to look for arguments -s|--sopt STRING,
-i|--iopt INT, -b|--bopt [BOOL], -C CONFFILE. Then 'prog -s bla -i
42 -C cfile' should produce a confparser compatible cfile which
contains

[my_options]
sopt = blah
iopt = 42

and not 'bopt = False' (if False was the program's default for
bopt).

Could you instead write those options that differ from the defaults?
You could parse an actual command line and an empty command line, and
work out the difference.

So 'prog -i 3' would not cause 'iopt = 3' to be written if 3 is the
default for iopt, but would that be a problem?

That's what the program does at the moment. However, I'm not quite
happy with it. Generally, the user doesn't know what's the default and
it would be confusing if 'prog -i 3' doesn't make 'iopt = 3' turn up in
the file at the end. There may also be the case when the user (for
whatever reason) _wants_ the default in the file.

I think I will try the opposite instead: the program writes the whole
set of options to the file. This would produce a complete and
consistent configuration which automatically reflects the hierarchy in
which the options were set. And the user can sort it out by hand if he
wants.

Regards,
Henry
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top