- If you have Python 2.3 you may not have subprocess
- This class is much simpler than subprocess: it does just one thing.
- You may want to pipe two commands in a fancier way
In my strive to be compatible with standard MacOS system (that uses 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
If you need to do different things, redefine (get|set)_(out|input|err).
No comments:
Post a Comment