>>> sh.call("cat", input='Foobar')
('Foobar', '')
"""
- if hasattr(self, "_wait"):
- self._wait()
+ self._wait()
kwargs.setdefault("interactive", False)
kwargs.setdefault("strip", False)
kwargs.setdefault("python", None)
# SIGCHILD handler to write a single byte to the pipe to get
# us out of select() when a subprocess exits.
proc = subprocess.Popen(args, stdout=stdout, stderr=stderr, stdin=stdin)
- if hasattr(self, "_async"):
- self._async(proc, args, **kwargs)
+ if self._async(proc, args, **kwargs):
return proc
stdout, stderr = proc.communicate(kwargs["input"])
+ # can occur if we were doing interactive communication; i.e.
+ # we didn't pass in PIPE.
+ if stdout is None:
+ stdout = ""
+ if stderr is None:
+ stderr = ""
if not kwargs["interactive"]:
if kwargs["strip"]:
self._log(None, stderr)
else: eclass = CallError
raise eclass(proc.returncode, args, stdout, stderr)
if kwargs["strip"]:
- return stdout.rstrip("\n")
+ return str(stdout).rstrip("\n")
return (stdout, stderr)
def _log(self, stdout, stderr):
"""Logs the standard output and standard input from a command."""
logging.debug("STDOUT:\n" + stdout)
if stderr:
logging.debug("STDERR:\n" + stderr)
+ def _wait(self):
+ pass
+ def _async(self, *args, **kwargs):
+ return False
def callAsUser(self, *args, **kwargs):
"""
Performs a system call as a different user. This is only possible
execution. See :meth:`Shell.call` source code for details.
"""
self.running[proc.pid] = (proc, args, python, on_success, on_error)
+ return True # so that the parent function returns
def _wait(self):
"""
Blocking call that waits for an open subprocess slot. This is
return
on_success(stdout, stderr)
+# Setup a convenience global instance
+shell = Shell()
+call = shell.call
+callAsUser = shell.callAsUser
+safeCall = shell.safeCall
+eval = shell.eval
class DummyParallelShell(ParallelShell):
"""Same API as :class:`ParallelShell`, but doesn't actually