From 7e2dba496e44a9e2aee0085aa043e83ea199662a Mon Sep 17 00:00:00 2001 From: chriskiehl Date: Thu, 7 Jan 2016 21:14:22 -0500 Subject: [PATCH] Moved client execution/processing code into own module; minor cleanup --- gooey/gui/processor.py | 80 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 gooey/gui/processor.py diff --git a/gooey/gui/processor.py b/gooey/gui/processor.py new file mode 100644 index 0000000..0f05536 --- /dev/null +++ b/gooey/gui/processor.py @@ -0,0 +1,80 @@ +import os +import re +import subprocess + +from functools import partial +from multiprocessing.dummy import Pool + +from gooey.gui.pubsub import pub +from gooey.gui.util.casting import safe_float +from gooey.gui.util.functional import unit, bind + + +class ProcessController(object): + def __init__(self, progress_regex, progress_expr): + self._process = None + self.progress_regex = progress_regex + self.progress_expr = progress_expr + + def was_success(self): + self._process.communicate() + return self._process.returncode == 0 + + def poll(self): + if not self._process: + raise Exception('Not started!') + self._process.poll() + + def run(self, command): + env = os.environ.copy() + env["GOOEY"] = "1" + self._process = subprocess.Popen(command, bufsize=1, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, shell=True, env=env) + Pool(1).apply_async(self._forward_stdout, (self._process,)) + + def _forward_stdout(self, process): + ''' + Reads the stdout of `process` and forwards lines and progress + to any interested subscribers + ''' + while True: + line = process.stdout.readline() + if not line: + break + pub.send_message('console_update', msg=line) + pub.send_message('progress_update', progress=self._extract_progress(line)) + pub.send_message('execution_complete') + + def _extract_progress(self, text): + ''' + Finds progress information in the text using the + user-supplied regex and calculation instructions + ''' + # monad-ish dispatch to avoid the if/else soup + find = partial(re.search, string=text.strip()) + regex = unit(self.progress_regex) + match = bind(regex, find) + result = bind(match, self._calculate_progress) + return result + + def _calculate_progress(self, match): + ''' + Calculates the final progress value found by the regex + ''' + if not self.progress_expr: + return safe_float(match.group(1)) + else: + return self._eval_progress(match) + + def _eval_progress(self, match): + ''' + Runs the user-supplied progress calculation rule + ''' + _locals = {k: safe_float(v) for k, v in match.groupdict().items()} + if "x" not in _locals: + _locals["x"] = [safe_float(x) for x in match.groups()] + try: + return int(eval(self.progress_expr, {}, _locals)) + except: + return None +