mirror of
https://github.com/kennethreitz-archive/procs.git
synced 2026-06-05 23:30:18 +00:00
Merge pull request #10 from hjwp/master
A first cut of working processes and working | based chains
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
*.pyc
|
||||
__pycache__
|
||||
+9
-9
@@ -13,7 +13,6 @@ Ideas
|
||||
- Process monitoring
|
||||
- programatically compose a chain of streams.
|
||||
- process call timeouts
|
||||
- >>> uptime.stdout >> cowsay.stdin
|
||||
|
||||
Usage
|
||||
-----
|
||||
@@ -23,7 +22,7 @@ Simple Usage::
|
||||
>>> import procs
|
||||
|
||||
>>> c = procs.run('uptime')
|
||||
>>> c.exit_code
|
||||
>>> c.returncode
|
||||
0
|
||||
>>> c.ok
|
||||
True
|
||||
@@ -33,13 +32,14 @@ Simple Usage::
|
||||
|
||||
Advanced Usage::
|
||||
|
||||
>>> chain = procs.chain()
|
||||
>>> uptime = chain.process('uptime')
|
||||
>>> cowsay = chain.process('cowsay')
|
||||
>>> chain.link(uptime.stdout, cowsay.stdin)
|
||||
>>> chain.start(wait=True)
|
||||
>>> chain.wait()
|
||||
|
||||
>>> ls = procs.Process('ls /usr/bin')
|
||||
>>> grep = procs.Process('grep python')
|
||||
>>> chain = ls | grep
|
||||
>>> chain.run()
|
||||
>>> print(chain.stdout)
|
||||
python
|
||||
python3
|
||||
python3.4
|
||||
|
||||
>>> from procs import ProcessHandler
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
class Process(object):
|
||||
def __init__(self, command):
|
||||
self.command = command
|
||||
self.environ = {}
|
||||
self.cwd = None
|
||||
|
||||
|
||||
def set_command(self, command):
|
||||
# process popen chain, etc
|
||||
self.command = command
|
||||
|
||||
def set_environ(self, environ, clean=False):
|
||||
self.environ = dict() if clean else dict(os.environ)
|
||||
self.environ.update(environ)
|
||||
|
||||
def set_cwd(self, cwd):
|
||||
# expand, discover, etc.
|
||||
self.cwd = cwd
|
||||
|
||||
def start(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def stdin(self):
|
||||
return 'stdin'
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
return 'stdout'
|
||||
|
||||
@property
|
||||
def stderr(self):
|
||||
return 'stderr'
|
||||
|
||||
|
||||
class Chain(object):
|
||||
|
||||
def __init__(self):
|
||||
self.processes = []
|
||||
|
||||
def process(self, command):
|
||||
p = Process(command)
|
||||
self.processes.append(p)
|
||||
|
||||
return p
|
||||
|
||||
def link(self, x, y):
|
||||
print 'Linking {} to {}'.format(x, y)
|
||||
|
||||
def start(self, wait=False):
|
||||
for process in self.processes:
|
||||
process.start()
|
||||
|
||||
self.wait()
|
||||
|
||||
def wait(self):
|
||||
# wait, somehow
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
def chain():
|
||||
return Chain()
|
||||
|
||||
|
||||
def process(command, env=None, clean_env=False, cwd=None, wait=False):
|
||||
p = Process(command)
|
||||
|
||||
if wait:
|
||||
p.start()
|
||||
p.wait()
|
||||
|
||||
|
||||
def run(command, env=None, cwd=None, clean_environ=False):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from .process import Process
|
||||
|
||||
def run(command):
|
||||
process = Process(command)
|
||||
process.run()
|
||||
return process
|
||||
@@ -0,0 +1,32 @@
|
||||
from __future__ import print_function
|
||||
import os
|
||||
|
||||
|
||||
class Chain(object):
|
||||
|
||||
def __init__(self, processes):
|
||||
self.processes = processes
|
||||
|
||||
|
||||
def run(self):
|
||||
for proc, next_proc in zip(self.processes, self.processes[1:]):
|
||||
read, write = os.pipe()
|
||||
proc.set_stdout(write)
|
||||
next_proc.set_stdin(read)
|
||||
for proc in self.processes:
|
||||
proc.start()
|
||||
for proc in self.processes:
|
||||
proc.wait()
|
||||
if proc._stdout is not None:
|
||||
os.close(proc._stdout)
|
||||
|
||||
|
||||
@property
|
||||
def returncode(self):
|
||||
return self.processes[-1].returncode
|
||||
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
return self.processes[-1].stdout
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
from __future__ import print_function
|
||||
import subprocess
|
||||
from .chain import Chain
|
||||
|
||||
|
||||
class Process(object):
|
||||
|
||||
def __init__(self, command):
|
||||
self.command = command
|
||||
self._stdin = None
|
||||
self._stdout = None
|
||||
self._stdout_text = None
|
||||
self._returncode = None
|
||||
|
||||
def set_stdin(self, stdin):
|
||||
self._stdin = stdin
|
||||
|
||||
def set_stdout(self, stdout):
|
||||
self._stdout = stdout
|
||||
|
||||
@property
|
||||
def stdin(self):
|
||||
return 'stdin'
|
||||
|
||||
@property
|
||||
def stdout(self):
|
||||
if self._stdout_text is not None:
|
||||
return self._stdout_text
|
||||
|
||||
@property
|
||||
def returncode(self):
|
||||
if self._returncode is not None:
|
||||
return self._returncode
|
||||
|
||||
@property
|
||||
def ok(self):
|
||||
if self._returncode is not None:
|
||||
return self.returncode is 0
|
||||
|
||||
@property
|
||||
def subprocess(self):
|
||||
if self._subprocess is not None:
|
||||
return self._subprocess
|
||||
|
||||
def start(self):
|
||||
self._subprocess = subprocess.Popen(
|
||||
args=self.command,
|
||||
shell=True,
|
||||
stdin=self._stdin if self._stdin else subprocess.PIPE,
|
||||
stdout=self._stdout if self._stdout else subprocess.PIPE,
|
||||
)
|
||||
|
||||
def wait(self):
|
||||
self._returncode = self._subprocess.wait()
|
||||
if self._subprocess.stdout is not None:
|
||||
self._stdout_text = self._subprocess.stdout.read().decode()
|
||||
|
||||
|
||||
def run(self):
|
||||
self.start()
|
||||
self.wait()
|
||||
|
||||
|
||||
def __or__(self, other):
|
||||
return Chain([self, other])
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '<Process: {command}>'.format(command=self.command)
|
||||
|
||||
Executable
+2986
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
|
||||
from procs import Process
|
||||
|
||||
|
||||
TEST_DIR = os.path.abspath(os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), 'test_data'
|
||||
))
|
||||
|
||||
|
||||
def test_chained_procs():
|
||||
ls = Process('ls {test_dir}'.format(test_dir=TEST_DIR))
|
||||
grep = Process('grep 2')
|
||||
chain = ls | grep
|
||||
chain.run()
|
||||
assert chain.returncode == 0
|
||||
assert chain.stdout.strip() == 'file2'
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import os
|
||||
|
||||
from procs import Process
|
||||
|
||||
|
||||
TEST_DIR = os.path.abspath(os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), 'test_data'
|
||||
))
|
||||
|
||||
def tests_repr():
|
||||
p = Process('foo')
|
||||
assert repr(p) == '<Process: foo>'
|
||||
|
||||
|
||||
def test_single_proc():
|
||||
ls = Process('ls {test_dir}'.format(test_dir=TEST_DIR))
|
||||
ls.run()
|
||||
assert ls.returncode == 0
|
||||
assert ls.stdout == u'file1\nfile2\nfile3\n'
|
||||
|
||||
|
||||
def test_empty_output():
|
||||
cat = Process('cat /dev/null')
|
||||
cat.run()
|
||||
assert cat.stdout == u''
|
||||
|
||||
|
||||
def test_returncode():
|
||||
assert not os.path.exists('/bin/nosuchcommand')
|
||||
|
||||
p = Process('/bin/nosuchcommand')
|
||||
p.run()
|
||||
assert p.returncode == 127
|
||||
|
||||
|
||||
def test_ok_if_returncode_0():
|
||||
p = Process('ls')
|
||||
p.run()
|
||||
assert p.ok is True
|
||||
|
||||
|
||||
def test_not_ok_if_returncode_not_0():
|
||||
assert not os.path.exists('/bin/nosuchcommand')
|
||||
p = Process('/bin/nosuchcommand')
|
||||
p.run()
|
||||
assert p.ok is False
|
||||
@@ -0,0 +1,10 @@
|
||||
import procs
|
||||
|
||||
|
||||
def test_run_is_same_as_Process_run():
|
||||
process = procs.Process('ls')
|
||||
process.run()
|
||||
p = procs.run('ls')
|
||||
assert p.returncode == process.returncode
|
||||
assert p.stdout == process.stdout
|
||||
|
||||
Reference in New Issue
Block a user