By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,505 Members | 1,206 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,505 IT Pros & Developers. It's quick & easy.

Creating Python class wrapper for a command line tool

P: n/a

Hi,

I was wondering what would be the most elegant way for creating a Python class
wrapper for a command line utility, which takes three types of arguments:

1. options with values (--foo=bar)

2. boolean options (--squibble)

3. data lines (MUNGE:x:y:z:frob)

So, when you call the program from command line it looks like

command --foo=bar --hip=hurray --squibble --optimize \
MUNGE1:x1:y:z:frob1 \
MUNGE2:x2:y:z:frob2 \
MUNGE3:x3:y:z:frob3

and it produces something. The idea is to make class with methods for
setting the options and data, and then calling write() after all options
have been set.

My current model is like this:

class Wrapper:

def __init__(self, **kwargs):
"""Initialize object"""

opts = []

for key, val in kwargs.items():
if isinstance(val, str) and val.find(' ') > -1:
val = '"%s"' % val
opts.append("--%s %s" % (key.replace('_', '-'), val))

def setbool(self, opt):
pass

def data(self, data):
pass

def write(self):
pass
The init method might look a bit odd; the reason is that I thought to call
Wrapper like this:

obj = Wrapper(use_bar=foo, treshold=10, name="alley cat")

and __init__() would transform those keyword parameters to long string
of the form '--use_bar foo --threshold 10 --name "alley cat"'

However, using **kwargs I cannot use boolean values, because a key in a
dictionary must have a value. Using parameter boolean=True would transform
to --boolean 1, which is not correct. That's why I added a separate method
setbool(), but that doesn't seem nice. To wrap the command line call

command --optimize --use_bar foo --threshold 10 --name "alley cat" \
MUNGE1:x1:y:z:frob1 \
MUNGE2:x2:y:z:frob2 \
MUNGE3:x3:y:z:frob3

obj = Wrapper(use_bar=foo, treshold=10, name="alley cat")
obj.setbool('optimize')
obj.data("MUNGE1:x1:y:z:frob1")
obj.data("MUNGE2:x2:y:z:frob2")
obj.data("MUNGE3:x3:y:z:frob3")

This is acceptable, but I'm sure many of you professional Pythonistas have
a more elegant solution. What do you think?

--
# Edvard Majakari Software Engineer
# PGP PUBLIC KEY available Soli Deo Gloria!

$_ = '456476617264204d616a616b6172692c20612043687269737 469616e20'; print
join('',map{chr hex}(split/(\w{2})/)),uc substr(crypt(60281449,'es'),2,4),"\n";

Jul 18 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Edvard Majakari wrote:
Hi,

I was wondering what would be the most elegant way for creating a Python class
wrapper for a command line utility, which takes three types of arguments:

1. options with values (--foo=bar)

2. boolean options (--squibble)

3. data lines (MUNGE:x:y:z:frob)

So, when you call the program from command line it looks like

command --foo=bar --hip=hurray --squibble --optimize \
MUNGE1:x1:y:z:frob1 \
MUNGE2:x2:y:z:frob2 \
MUNGE3:x3:y:z:frob3

and it produces something. The idea is to make class with methods for
setting the options and data, and then calling write() after all options
have been set.

My current model is like this:

class Wrapper:

def __init__(self, **kwargs):
"""Initialize object"""

opts = []

for key, val in kwargs.items():
if isinstance(val, str) and val.find(' ') > -1:
val = '"%s"' % val
opts.append("--%s %s" % (key.replace('_', '-'), val))

def setbool(self, opt):
pass

def data(self, data):
pass

def write(self):
pass
The init method might look a bit odd; the reason is that I thought to call
Wrapper like this:

obj = Wrapper(use_bar=foo, treshold=10, name="alley cat")

and __init__() would transform those keyword parameters to long string
of the form '--use_bar foo --threshold 10 --name "alley cat"'

However, using **kwargs I cannot use boolean values, because a key in a
dictionary must have a value. Using parameter boolean=True would transform
to --boolean 1, which is not correct. That's why I added a separate method
setbool(), but that doesn't seem nice. To wrap the command line call

command --optimize --use_bar foo --threshold 10 --name "alley cat" \
MUNGE1:x1:y:z:frob1 \
MUNGE2:x2:y:z:frob2 \
MUNGE3:x3:y:z:frob3

obj = Wrapper(use_bar=foo, treshold=10, name="alley cat")
obj.setbool('optimize')
obj.data("MUNGE1:x1:y:z:frob1")
obj.data("MUNGE2:x2:y:z:frob2")
obj.data("MUNGE3:x3:y:z:frob3")

This is acceptable, but I'm sure many of you professional Pythonistas have
a more elegant solution. What do you think?


I am by no means a professional Pythonist... but it doesn't seem too bad
to me to check for each kwarg whether it's type is boolean and if so,
just add it to the command line as a flag instead of as a value
parameter. And data arguments can be passed in the *args tuple.

I'm thinking along the lines of:

def __init__(self, *args, **kwargs):
self.opts = []

for key, val in kwargs:
cmdkey = key.replace('_', '-')

if isinstance(val, bool):
self.opts.append("--%s" % cmdkey)
else:
if isinstance(val, str) and val.find(' ') > -1:
val = '"%s"' % val
self.opts.append("--%s %s" % (cmdkey, val))
Which would be called like:

obj = Wrapper("MUNGE1:x1:y:z:frob1", "MUNGE2:x2:y:z:frob2",
"MUNGE3:x3:y:z:frob3", optimize=True, use_bar=foo, threshold=10,
name="Alley cat")

This just wraps everything in the constructor. Alternatively, you could
go for setting each command-line parameter via a method flag.

obj = Wrapper()
obj.boolParam('optimize')
obj.valueParam('use_bar', 'foo')
obj.valueParam('threshold', 10)
obj.valueParam('name', 'alley cat')
obj.dataParam("MUNGE1:x1:y:z:frob1")
obj.dataParam("MUNGE2:x2:y:z:frob2")
obj.dataParam("MUNGE3:x3:y:z:frob3")

Combining the two methods seems ugly to me, though.

- Rico
Jul 18 '05 #2

P: n/a
Rico Huijbers <E.************@REMOVEstudent.tue.nl> writes:
I am by no means a professional Pythonist... but it doesn't seem too bad
to me to check for each kwarg whether it's type is boolean and if so, just
add it to the command line as a flag instead of as a value parameter. And
data arguments can be passed in the *args tuple.
Wow - I had to test it and didn't work. Then I remembered it would
probably work with Python2.3, and it did. But the thingamajick must work
with Python2.2.
obj = Wrapper("MUNGE1:x1:y:z:frob1", "MUNGE2:x2:y:z:frob2",
"MUNGE3:x3:y:z:frob3", optimize=True, use_bar=foo, threshold=10,
name="Alley cat")

This just wraps everything in the constructor. Alternatively, you could go
for setting each command-line parameter via a method flag.
Yes - well, command line options are not necessary a must, so I thought to
separate those from data (which *is* compulsory for the thing to work).
Combining the two methods seems ugly to me, though.


I admit, it is not as pretty. But the command I'm using takes lots and
lots of parameters, flags etc. and one reason in having a Python interface
is to avoid very long parameter lists (if constructor is not given any
keyword arguments, some sane defaults are assumed for them).

But thanks for the follow-up!

--
#!/usr/bin/perl -w
$h={23,69,28,'6e',2,64,3,76,7,20,13,61,8,'4d',24,7 3,10,'6a',12,'6b',21,68,14,
72,16,'2c',17,20,9,61,11,61,25,74,4,61,1,45,29,20, 5,72,18,61,15,69,20,43,26,
69,19,20,6,64,27,61,22,72};$_=join'',map{chr hex $h->{$_}}sort{$a<=>$b}
keys%$h;m/(\w).*\s(\w+)/x;$_.=uc substr(crypt(join('',60,28,14,49),join'',
map{lc}($1,substr $2,4,1)),2,4)."\n"; print;
Jul 18 '05 #3

P: n/a
Edvard Majakari wrote:
Rico Huijbers <E.************@REMOVEstudent.tue.nl> writes:
I am by no means a professional Pythonist... but it doesn't seem too bad
to me to check for each kwarg whether it's type is boolean and if so,
just add it to the command line as a flag instead of as a value
parameter. And data arguments can be passed in the *args tuple.


Wow - I had to test it and didn't work. Then I remembered it would
probably work with Python2.3, and it did. But the thingamajick must work
with Python2.2.


You could test object identity instead.
def isbool(b): .... return b is True or b is False
.... isbool(1), isbool(True) (0, 1) isbool(0), isbool(False)

(0, 1)

Peter

Jul 18 '05 #4

P: n/a
Peter Otten <__*******@web.de> writes:
You could test object identity instead.
def isbool(b):

... return b is True or b is False


Ah. Should have tried (I almost thought of that myself, but then I
remembered 1 == True and thought it wouldn't work. But I forgot there's
magic in Python ;)

This works great with Python2.2. Thanks!

--
# Edvard Majakari Software Engineer
# PGP PUBLIC KEY available Soli Deo Gloria!

$_ = '456476617264204d616a616b6172692c20612043687269737 469616e20'; print
join('',map{chr hex}(split/(\w{2})/)),uc substr(crypt(60281449,'es'),2,4),"\n";
Jul 18 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.