option argument length

  • Thread starter Ritesh Raj Sarraf
  • Start date
R

Ritesh Raj Sarraf

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I'm using optparse module to parse all options and arguments.

My program uses mostly "option arguments" hence my len(args) value is always
zero. I need to check if the user has passed the correct number of "option
arguments". Something like:

(options,args) = parser.parse_args()

len(options) != 1 or len(options) > 2:
print "Incorrect number of arguments passed."

How do I accomplish it ?

Regards,

rrs
- --
Ritesh Raj Sarraf
RESEARCHUT -- http://www.researchut.com
"Stealing logics from one person is plagiarism, stealing from many is
research."
"Necessity is the mother of invention."

Note: Please CC me. I'm not subscribed to the list
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDk1Nh4Rhi6gTxMLwRApx0AJ9XHlWFU1J0NdN02gtvimogUSgDkACgmkOO
2pX8ocoC7pot1a8R4u2BWrY=
=piNo
-----END PGP SIGNATURE-----
 
M

Marc 'BlackJack' Rintsch

Ritesh Raj said:
My program uses mostly "option arguments" hence my len(args) value is always
zero. I need to check if the user has passed the correct number of "option
arguments". Something like:

(options,args) = parser.parse_args()

len(options) != 1 or len(options) > 2:
print "Incorrect number of arguments passed."

How do I accomplish it ?

Just insert an ``if`` in front of the condition and end the program with
``sys.exit()`` after the message.

Ciao,
Marc 'BlackJack' Rintsch
 
P

Peter Otten

Ritesh said:
My program uses mostly "option arguments" hence my len(args) value is
always zero. I need to check if the user has passed the correct number of
"option arguments". Something like:

(options,args) = parser.parse_args()

len(options) != 1 or len(options) > 2:
print "Incorrect number of arguments passed."

How do I accomplish it ?

Judging from your code sample invention is the mother of that necessity.
You can pass a custom Values object with a __len__() method

class MyValues:
def __len__(self):
return len(self.__dict__)

# ...

options, args = parser.parse_args(values=MyValues())

but you should do your users a favour and give them meaningful error
messages. I can't conceive how you could achieve this by checking the
number of options. Explicit constraint checks like

options, args = parser.parse_args()
if options.eat_your_cake and options.have_it:
parser.error("Sorry, you cannot eat your cake and have it")

will increase your script's usability and make it easier to maintain for
only a tiny amount of work.

Peter
 
R

Ritesh Raj Sarraf

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Just insert an ``if`` in front of the condition and end the program with
``sys.exit()`` after the message.

Ciao,
Marc 'BlackJack' Rintsch

This won't help because "options" is an instance.

Regards,

rrs
- --
Ritesh Raj Sarraf
RESEARCHUT -- http://www.researchut.com
"Stealing logics from one person is plagiarism, stealing from many is
research."
"Necessity is the mother of invention."

Note: Please CC me. I'm not subscribed to the list
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDlIbH4Rhi6gTxMLwRAlgSAJ0Y3TT9eCBgrck5N2Y9YjOTZMxUgwCcDeO5
qqgzY6rz2E4YKvurnlHL0nQ=
=hlZO
-----END PGP SIGNATURE-----
 
R

Ritesh Raj Sarraf

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
options, args = parser.parse_args(values=MyValues())

but you should do your users a favour and give them meaningful error
messages. I can't conceive how you could achieve this by checking the
number of options. Explicit constraint checks like

options, args = parser.parse_args()
if options.eat_your_cake and options.have_it:
parser.error("Sorry, you cannot eat your cake and have it")

will increase your script's usability and make it easier to maintain for
only a tiny amount of work.

I'm using this for "option arguments" which are mutually inclusive.
But I want the user to pass atleast one "option argument" for the program to
function properly.

For example, I have an option "--fetch-update" which requires a file "foo"
to check what it has to fetch. If the file is provided as an argument, it
uses it, else I add a parser.set_defaults("foo") which makes the program to
look for it in the current working directory.

WHen the program see the "--fetch-update" option, it should execute the
required code. Now how do I check if at least one option has been passed at
the command-line ?
I have multiple options but I have parser.set_defaults() for each of them.

Regards,

rrs
- --
Ritesh Raj Sarraf
RESEARCHUT -- http://www.researchut.com
"Stealing logics from one person is plagiarism, stealing from many is
research."
"Necessity is the mother of invention."

Note: Please CC me. I'm not subscribed to the list
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDlIhF4Rhi6gTxMLwRAsLTAJ9ydjppGrFVbH2kL00vL00HgtrxqQCghZBq
pC0/1HftWE+9Eipx6vF+3Bo=
=Ay8m
-----END PGP SIGNATURE-----
 
P

Peter Otten

Ritesh said:
I'm using this for "option arguments" which are mutually inclusive.
But I want the user to pass atleast one "option argument" for the program
to function properly.

For example, I have an option "--fetch-update" which requires a file "foo"
to check what it has to fetch. If the file is provided as an argument, it
uses it, else I add a parser.set_defaults("foo") which makes the program
to look for it in the current working directory.

WHen the program see the "--fetch-update" option, it should execute the
required code. Now how do I check if at least one option has been passed
at the command-line ?
I have multiple options but I have parser.set_defaults() for each of them.

I'm sorry I don't understand your example. Wouldn't you need at least two
options to demonstrate "mutually inclusive" options? The set_default()
method seems to accept only keyword arguments -- but even it were used
correctly I'm still unclear why you would need it at all.

Perhaps you can post a few sample invocations (both correct and illegal) of
your script together with a description (in English, not code) of how the
script should react?

Peter, puzzled
 
R

Ritesh Raj Sarraf

I'm sorry I don't understand your example. Wouldn't you need at least two
options to demonstrate "mutually inclusive" options? The set_default()
method seems to accept only keyword arguments -- but even it were used
correctly I'm still unclear why you would need it at all.

Perhaps you can post a few sample invocations (both correct and illegal) of
your script together with a description (in English, not code) of how the
script should react?

Peter, puzzled


try:
version = "0.6b"
reldate = "03/10/2005"
copyright = "(C) 2005 Ritesh Raj Sarraf - RESEARCHUT (http://www.researchut.com/)"

#FIXME: Option Parsing
# There's a flaw with either optparse or I'm not well understood with it
# Presently you need to provide all the arguments to it to work.
# No less, no more. This needs to be converted to getopt sometime.

#parser = OptionParser()
#parser = optparse.OptionParser()
parser = optparse.OptionParser(usage="%prog [OPTION1, OPTION2, ...]", version="%prog " + version)
parser.add_option("-d","--download-dir", dest="download_dir", help="Root directory path to save the downloaded files", action="store", type="string")
parser.set_defaults(download_dir="foo")
parser.add_option("-s","--cache-dir", dest="cache_dir", help="Root directory path where the pre-downloaded files will be searched. If not, give a period '.'",action="store", type="string", metavar=".")
parser.set_defaults(cache_dir=".")
#parser.set_defaults(cache_dir=".")
#parser.add_option("-u","--uris", dest="uris_file", help="Full path of the uris file which contains the main database of files to be downloaded",action="store", type="string")

# We'll have additional options
# --set-update - This will extract the list of uris which need to be fetched
# --fetch-update - This will fetch the list of uris which need for update.
# --install-update - This will install the fetched database files
# The same will happen for upgradation.
# --set-upgrade - This will extract the list of uris which need to be fetched
# --fetch-upgrade - This will fetch the list of uris which need for upgrade
# --install-upgrade - This will install the fetched database files
parser.add_option("","--set-update", dest="set_update", help="Extract the list of uris which need to be fetched for _updation_", action="store", type="string", metavar="foo")
parser.set_defaults(set_update="foo")
parser.add_option("","--fetch-update", dest="fetch_update", help="Fetch the list of uris which are needed for _updation_.", action="store", type="string", metavar="foo")
parser.set_defaults(fetch_update="foo")
parser.add_option("","--install-update", dest="install_update", help="Install the fetched database files ", action="store", type="string", metavar="foo.zip")
parser.set_defaults(install_update="foo.zip")
parser.add_option("","--set-upgrade", dest="set_upgrade", help="Extract the list of uris which need to be fetched ", action="store", type="string", metavar="foo.dat")
parser.set_defaults(set_upgrade="foo.dat")
parser.add_option("","--fetch-upgrade", dest="fetch_upgrade", help="Fetch the list of uris which are needed ", action="store", type="string", metavar="foo.dat")
parser.set_defaults(fetch_upgrade="foo.dat")
parser.add_option("","--install-upgrade", dest="install_upgrade", help="Install the fetched packages ", action="store", type="string", metavar="foo-fetched.zip")
parser.set_defaults(install_ugprade="foofetched.zip")
(options, args) = parser.parse_args()
#parser.check_required("-d", "-s", "-u")
#if len(arguments) != 2:
# parser.error("Err! Incorrect number of arguments. Exiting")
if len(options) != 1 or len(options) > 2:
print len(args)
parser.error("No arguments were passed\n")
sys.exit(1)
elif not options.set_upgrade and options.upgrade_type:
parser.error("Only options --set-upgrade and --upgrade-type are mutually inclusive\n")
sys.exit(1)


Thanks,

rrs
 
P

Peter Otten

Ritesh said:
parser.add_option("-d","--download-dir", dest="download_dir",
help="Root directory path to save the downloaded files",
action="store", type="string")
parser.set_defaults(download_dir="foo")

This can be simplified to

parser.add_option("-d", "--download-dir", default="foo",
help="Root directory path to save the downloaded files")

which seems to be the reason why I've never seen the set_defaults() call
before.
if len(options) != 1 or len(options) > 2:

It doesn't matter much as it won't work anyway, but

len(options) > 2 implies len(options) != 1, so

if len(options) != 1:
#...

would suffice here.

Now to the actual problem: I think you didn't understand my previous
question. I cannot infer from your non-working code what it actually should
do. I asked for examples of how your script would be used. E. g,
assuming the code above is in a file called sarraf.py, what should the
following invocations

../sarraf.py --fetch-update bar
../sarraf.py --fetch-update bar --the-mutually-inclusive-option baz

do? Would the first terminate with an error message that another option must
also be given? Would it use the default? Would the second be accepted? Try
to describe it as simple and clear as possible. Imagine you were talking to
someone who has never written a line of code.

Peter
 
R

Ritesh Raj Sarraf

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Peter,

This can be simplified to

parser.add_option("-d", "--download-dir", default="foo",
help="Root directory path to save the downloaded files")

which seems to be the reason why I've never seen the set_defaults() call
before.

As per python docs, it's mentioned that "default=" has been deprecated.
That's why I changed to parser.set_defaults()
It doesn't matter much as it won't work anyway, but

len(options) > 2 implies len(options) != 1, so

if len(options) != 1:
#...

Yes, you're right. Sorry.
would suffice here.

But will len(options) give a meaningful output. "options" is an instance.
It gives a Value Error.
Now to the actual problem: I think you didn't understand my previous
question. I cannot infer from your non-working code what it actually
should do. I asked for examples of how your script would be used. E. g,
assuming the code above is in a file called sarraf.py, what should the
following invocations

./sarraf.py --fetch-update bar
./sarraf.py --fetch-update bar --the-mutually-inclusive-option baz

do? Would the first terminate with an error message that another option
must also be given? Would it use the default? Would the second be
accepted? Try to describe it as simple and clear as possible. Imagine you
were talking to someone who has never written a line of code.

../sarraf.py --fetch-update /bar

If the user gives the /bar argument, the program should save the downloaded
files to /bar. But I'm assuming that the user could be dumb or too lazy, in
which case --fetch-udpate should use the parser.set_defaults value
i.e. /foo

../sarraf.py --set-upgrade foo.dat --upgrade-type minimal

set-upgrade will again write data to foo.dat. If the user doesn't pass it as
an arguemnt it should take the defaults (again whatever is there in
parser.set_defaults). This will be inclusive with the --upgrade-type option
because the user will have a choice of selecting what kind of upgrade he'd
like to do, minimal or full or blah.

For this I think this should be enough:

if not options.set_upgrade and options.upgrade_type:
parser.error("They are mutually inclusive options")


But my main concern is what if the user doesn't pass any arguemtns. Every
option I have has a default value. So I want to check what the user has
passed.
But unfortunately the args variable has "0" as its value always.

Is my way (up till now) of using optparse logically incorrect or improper ?


Regards,

rrs
- --
Ritesh Raj Sarraf
RESEARCHUT -- http://www.researchut.com
"Stealing logics from one person is plagiarism, stealing from many is
research."
"Necessity is the mother of invention."

Note: Please CC me. I'm not subscribed to the list
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFDlzC84Rhi6gTxMLwRAtCBAJ9z5zDQ8oyx8Jy/rLe9JrwLII3xtACfTaEV
VhMmj8OD+/p+yN/8wF6xe+8=
=atC6
-----END PGP SIGNATURE-----
 
P

Peter Otten

Ritesh said:
./sarraf.py --fetch-update /bar

If the user gives the /bar argument, the program should save the
downloaded files to /bar. But I'm assuming that the user could be dumb or
too lazy, in which case --fetch-udpate should use the parser.set_defaults
value i.e. /foo

./sarraf.py --set-upgrade foo.dat --upgrade-type minimal

set-upgrade will again write data to foo.dat. If the user doesn't pass it
as an arguemnt it should take the defaults (again whatever is there in
parser.set_defaults). This will be inclusive with the --upgrade-type
option because the user will have a choice of selecting what kind of
upgrade he'd like to do, minimal or full or blah.

For this I think this should be enough:

if not options.set_upgrade and options.upgrade_type:
parser.error("They are mutually inclusive options")


But my main concern is what if the user doesn't pass any arguemtns. Every
option I have has a default value. So I want to check what the user has
passed.
But unfortunately the args variable has "0" as its value always.

args are just the leftover arguments. For

../sarraf.py alpha --set-upgrade foo.dat beta

it would be ["alpha", "beta"].

---

I think your description is starting to make sense to me. Your user can
either update or upgrade but you cannot just check the value of e. g.
set_upgrade because you want to treat the default value and that same value
given on the command line differently.

If this is a correct assessment I don't think what you want is covered by
optparse. However, I hacked something together:

import optparse

parser = optparse.OptionParser()

parser.add_option("--alpha")
parser.add_option("--beta")

class Values(object):
def __init__(self):
self.__defaults = {}
def set_defaults(self, **kw):
self.__defaults.update(kw)
def __len__(self):
"""Number of options set by the user."""
return len(self.__dict__) -1
def __getattr__(self, name):
try:
return self.__defaults[name]
except KeyError:
raise AttributeError
def is_default(self, name):
"""Return True when the default fro option 'name'
wasn't overriden by the user"""
return name not in self.__dict__

values = Values()
values.set_defaults(alpha="xxx", beta="yyy")

options, args = parser.parse_args(values=values)

print "len(options) =", len(options)
print "alpha =", options.alpha,
print "(using default)" * options.is_default("alpha")
print "beta =", options.beta,
print "(using default)" * options.is_default("beta")

Not particularly elegant but I'm not able to come up with something better
for the moment. Maybe you should just provide fewer defaults to the parser.
Or you could look into option callbacks for an alternate approach.
Is my way (up till now) of using optparse logically incorrect or improper
?

Well, as the optparse author points out, "required options" are a
self-contradictory term -- don't use them if you can avoid it. Would your
problem go away if you used two different scripts, one for updating and the
other for upgrading?

Peter
 

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,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top