From 7b5848b9c330d55884922f2324a00035cf2e35fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 5 Jan 2016 17:46:52 +0100 Subject: [PATCH] Extracted handler result normalization and added tests for it Caught some more bugs while doing that. --- src/octoprint/util/comm.py | 206 +++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 89 deletions(-) diff --git a/src/octoprint/util/comm.py b/src/octoprint/util/comm.py index ed5265d5..21920be7 100644 --- a/src/octoprint/util/comm.py +++ b/src/octoprint/util/comm.py @@ -2204,7 +2204,7 @@ class MachineCom(object): except: self._logger.exception("Error while processing hook {name} for phase {phase} and command {command}:".format(**locals())) else: - normalized = self._handle_command_handler_result(command, command_type, gcode, hook_results) + normalized = _normalize_command_handler_result(command, command_type, gcode, hook_results) # make sure we don't allow multi entry results in sending and sent phase if phase in ("sending", "sent") and len(normalized) > 1: @@ -2224,7 +2224,7 @@ class MachineCom(object): gcode_handler = "_gcode_" + gcode + "_" + phase if hasattr(self, gcode_handler): handler_results = getattr(self, gcode_handler)(command, cmd_type=command_type) - new_results += self._handle_command_handler_result(command, command_type, gcode, handler_results) + new_results += _normalize_command_handler_result(command, command_type, gcode, handler_results) else: new_results.append((command, command_type, gcode)) if not new_results: @@ -2238,98 +2238,12 @@ class MachineCom(object): new_results = [] for command, command_type, gcode in results: handler_results = getattr(self, command_phase_handler)(command, cmd_type=command_type, gcode=gcode) - new_results += self._handle_command_handler_result(command, command_type, gcode, handler_results) + new_results += _normalize_command_handler_result(command, command_type, gcode, handler_results) results = new_results # finally return whatever we resulted on return results - def _handle_command_handler_result(self, command, command_type, gcode, handler_results): - """ - Normalizes a command handler results. - - Handler results can be either ``None``, a single result entry or a list of result - entries. - - ``None`` results are ignored, the provided ``command``, ``command_type`` - and ``gcode`` are returned in that case (as single-entry list with one - 3-tuple as entry). - - Single result entries are either: - - * a single string defining a replacement ``command`` - * a 1-tuple defining a replacement ``command`` - * a 2-tuple defining a replacement ``command`` and ``command_type`` - - A ``command`` that is ``None`` will lead to the entry being ignored for - the normalized result. - - The method returns a list of normalized result entries. Normalized result - entries always are a 3-tuple consisting of ``command``, ``command_type`` - and ``gcode``, the latter two being allowed to be ``None``. The list may - be empty in which case the command is to be suppressed. - - Parameters: - command (str or None): The command for which the handler result was - generated - command_type (str or None): The command type for which the handler - result was generated - gcode (str or None): The GCODE for which the handler result was - generated - handler_results: The handler result(s) to normalized. Can be either - a single result entry or a list of result entries. - - Returns: - (list) - A list of normalized handler result entries, which are - 3-tuples consisting of ``command``, ``command_type`` and - ``gcode``, the latter two of which may be ``None``. - """ - - if handler_results is None: - # handler didn't return anything, we'll just continue - return [(command, command_type, gcode)] - - if not isinstance(handler_results, list): - handler_results = [handler_results,] - - result = [] - for handler_result in handler_results: - # we iterate over all handler result entries and process each one - # individually here - - if handler_result is None: - # entry is None, we'll ignore that entry and continue - continue - - if isinstance(handler_result, basestring): - # entry is just a string, replace command with it - command = handler_result - gcode = gcode_command_for_cmd(command) - result.append((command, command_type, gcode)) - - elif isinstance(handler_result, tuple): - # entry is a tuple, extract command and command_type - hook_result_length = len(handler_results) - if hook_result_length == 1: - # handler returned just the command - command, = handler_results - elif hook_result_length == 2: - # handler returned command and command_type - command, command_type = handler_results - else: - # handler returned a tuple of an unexpected length, ignore - # and continue - continue - - if command is None: - # command is None, ignore it and continue - continue - - gcode = gcode_command_for_cmd(command) - result.append((command, command_type, gcode)) - - return result - ##~~ actual sending via serial def _do_increment_and_send_with_checksum(self, cmd): @@ -3210,6 +3124,120 @@ def gcode_command_for_cmd(cmd): return None +def _normalize_command_handler_result(command, command_type, gcode, handler_results): + """ + Normalizes a command handler result. + + Handler results can be either ``None``, a single result entry or a list of result + entries. + + ``None`` results are ignored, the provided ``command``, ``command_type`` + and ``gcode`` are returned in that case (as single-entry list with one + 3-tuple as entry). + + Single result entries are either: + + * a single string defining a replacement ``command`` + * a 1-tuple defining a replacement ``command`` + * a 2-tuple defining a replacement ``command`` and ``command_type`` + + A ``command`` that is ``None`` will lead to the entry being ignored for + the normalized result. + + The method returns a list of normalized result entries. Normalized result + entries always are a 3-tuple consisting of ``command``, ``command_type`` + and ``gcode``, the latter two being allowed to be ``None``. The list may + be empty in which case the command is to be suppressed. + + Examples: + >>> _normalize_command_handler_result("M105", None, "M105", None) + [('M105', None, 'M105')] + >>> _normalize_command_handler_result("M105", None, "M105", "M110") + [('M110', None, 'M110')] + >>> _normalize_command_handler_result("M105", None, "M105", ["M110"]) + [('M110', None, 'M110')] + >>> _normalize_command_handler_result("M105", None, "M105", ["M110", "M117 Foobar"]) + [('M110', None, 'M110'), ('M117 Foobar', None, 'M117')] + >>> _normalize_command_handler_result("M105", None, "M105", [("M110",), "M117 Foobar"]) + [('M110', None, 'M110'), ('M117 Foobar', None, 'M117')] + >>> _normalize_command_handler_result("M105", None, "M105", [("M110", "lineno_reset"), "M117 Foobar"]) + [('M110', 'lineno_reset', 'M110'), ('M117 Foobar', None, 'M117')] + >>> _normalize_command_handler_result("M105", None, "M105", []) + [] + >>> _normalize_command_handler_result("M105", None, "M105", ["M110", None]) + [('M110', None, 'M110')] + >>> _normalize_command_handler_result("M105", None, "M105", [("M110",), (None, "ignored")]) + [('M110', None, 'M110')] + >>> _normalize_command_handler_result("M105", None, "M105", [("M110",), ("M117 Foobar", "display_message"), ("tuple", "of unexpected", "length"), ("M110", "lineno_reset")]) + [('M110', None, 'M110'), ('M117 Foobar', 'display_message', 'M117'), ('M110', 'lineno_reset', 'M110')] + + Arguments: + command (str or None): The command for which the handler result was + generated + command_type (str or None): The command type for which the handler + result was generated + gcode (str or None): The GCODE for which the handler result was + generated + handler_results: The handler result(s) to normalized. Can be either + a single result entry or a list of result entries. + + Returns: + (list) - A list of normalized handler result entries, which are + 3-tuples consisting of ``command``, ``command_type`` and + ``gcode``, the latter two of which may be ``None``. + """ + + original = (command, command_type, gcode) + + if handler_results is None: + # handler didn't return anything, we'll just continue + return [original] + + if not isinstance(handler_results, list): + handler_results = [handler_results,] + + result = [] + for handler_result in handler_results: + # we iterate over all handler result entries and process each one + # individually here + + if handler_result is None: + # entry is None, we'll ignore that entry and continue + continue + + if isinstance(handler_result, basestring): + # entry is just a string, replace command with it + command = handler_result + gcode = gcode_command_for_cmd(command) + result.append((command, command_type, gcode)) + + elif isinstance(handler_result, tuple): + # entry is a tuple, extract command and command_type + hook_result_length = len(handler_result) + if hook_result_length == 1: + # handler returned just the command + command, = handler_result + elif hook_result_length == 2: + # handler returned command and command_type + command, command_type = handler_result + else: + # handler returned a tuple of an unexpected length, ignore + # and continue + continue + + if command is None: + # command is None, ignore it and continue + continue + + gcode = gcode_command_for_cmd(command) + result.append((command, command_type, gcode)) + + # reset to original + command, command_type, gcode = original + + return result + + # --- Test code for speed testing the comm layer via command line follows