Creating Python class wrapper for a command line tool

Discussion in 'Python' started by Edvard Majakari, May 26, 2004.

  1. 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!

    $_ = '456476617264204d616a616b6172692c20612043687269737469616e20'; print
    join('',map{chr hex}(split/(\w{2})/)),uc substr(crypt(60281449,'es'),2,4),"\n";
     
    Edvard Majakari, May 26, 2004
    #1
    1. Advertising

  2. 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
     
    Rico Huijbers, May 26, 2004
    #2
    1. Advertising

  3. Rico Huijbers <> 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,73,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;
     
    Edvard Majakari, May 26, 2004
    #3
  4. Edvard Majakari

    Peter Otten Guest

    Edvard Majakari wrote:

    > Rico Huijbers <> 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
     
    Peter Otten, May 26, 2004
    #4
  5. Peter Otten <> 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!

    $_ = '456476617264204d616a616b6172692c20612043687269737469616e20'; print
    join('',map{chr hex}(split/(\w{2})/)),uc substr(crypt(60281449,'es'),2,4),"\n";
     
    Edvard Majakari, May 27, 2004
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?TWFuZHk=?=

    Running command line tool from web application

    =?Utf-8?B?TWFuZHk=?=, Jan 14, 2005, in forum: ASP .Net
    Replies:
    10
    Views:
    3,672
    =?Utf-8?B?TWFuZHk=?=
    Jan 17, 2005
  2. Replies:
    4
    Views:
    1,729
    Terry Hancock
    Apr 23, 2005
  3. Tim
    Replies:
    4
    Views:
    799
    wb_peter
    Sep 27, 2006
  4. planetthoughtful

    Creating interactive command-line Python app?

    planetthoughtful, Dec 21, 2005, in forum: Python
    Replies:
    6
    Views:
    462
    Tim Chase
    Jan 3, 2013
  5. Anish Chapagain

    Creating wrapper for python..

    Anish Chapagain, Aug 4, 2008, in forum: C Programming
    Replies:
    3
    Views:
    332
    Antoninus Twink
    Aug 4, 2008
Loading...

Share This Page