Execute class: $(command) in python

February 23rd, 2006

Although you can easily do with module subprocess what I do with the following class:

I wrote this because I needed to use Python to do some system automation and I needed something that acted like Perl and bash (in bash 2 you are supposed to do $(command) instead of `command` but it’s syntactical sugar).

In my strive to be compatible with standard MacOS system (which du use 2.3 by default) I forgot it existed module subprocess. So I wrote this simple class.

Even if in production you may prefer to use subprocess you can consider this an example of streams in Python. This is a very simple example. If you want to really pipe two processes, use module subprocess. If you want to make streams in a C++ fashion you can take inspiration by this code, but you may want to do it line based (but this ain’t no problem, in fact we are using properties, so you can do whatever you want with them — an example later).

Stream acts like a Mixin (thanks Dialtone!). It defines __rshift__ and __lshift__ (that become >> and


class Stream(object):
    def __rshift__(self, rho):
        if isinstance(rho, Stream):
            rho.input = self.out
            return rho
        else:
            raise TypeError()

    def __lshift__(self, rho):
        if isinstance(rho, Stream):
            self.input = rho.out
            return self
        else: raise TypeError()
    

Remember: classes that subclass Stream must have an attribute named out and one named input. If you need something more complex, use properties to implicitly call functions every-time you access out or in. For example since I use lazy evaluation I do:


    input = property(fset=set_input, fget=get_input)
    out = property(fget=get_out)
    err = property(fget=get_err)

Now have a look at the whole code:


import os

class Stream(object):
    def __rshift__(self, rho):
        if isinstance(rho, Stream):
            rho.input = self.out
            return rho
        else:
            raise TypeError()

    def __lshift__(self, rho):
        if isinstance(rho, Stream):
            self.input = rho.out
            return self
        else: raise TypeError()

class Execute(Stream):
    def __init__(self, command, *kargs, **prefs):
        self._commandString = ' '.join((command,) + kargs)
        self.has_run = False

    def _lazy_run(self):
        if self.has_run: return
        self.has_run = True
        (self.sin, self.sout, self.serr) = os.popen3(self._commandString)
        self.sin.write(self.input)
        self.sin.close()
        self.out_list = list([line.strip() for line in self.sout])
        self.err_list = list([line.strip() for line in self.serr])

    def run(self):
        self._lazy_run()
        return self

    def _make_string(self, which):
        self._lazy_run()
        if hasattr(self, "%s_string" % which):
            return
        setattr(self, "%s_string" % which,
                    '\n'.join(getattr(self, "%s_list"% which)))

    def set_input(self, s):
        if hasattr(self, "input"):
            self.input_ = "%s%s" % (self.input, str(s))
        else:
            self.input_ = str(s)

    def get_input(self):
        try:
            return self.input_
        except AttributeError:
            return ""

    def get_out(self):
        self._make_string("out")
        return self.out_string

    def get_err(self):
        self._make_string("err")
        return self.err_string

    input = property(fset=set_input, fget=get_input)
    out = property(fget=get_out)
    err = property(fget=get_err)

    def __str__(self):
        return self.out

print Execute("cat Execute.py") >> Execute("wc -l")
print Execute("wc -l") << Execute("cat Execute.py") 

If you need to do different things, redefine (get|set)_(out|input|err).

Programming, Python | Comments | Trackback

Leave a Reply

  1.  
  2.  
  3.  
  4. XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
You can keep track of new comments to this post with the comments feed.

Recent Posts

Blogroll

Siti amici

Misc

Recent Comments

Categories

Enrico Franchi graduated in Maths and Computer Science and is now studying for a Computet Science MSc (though because of italian bureaucracy that very course is to be cancelled).

RiK0's Tech Temple is using WP-Gravatar