From c84e199e87a6bbdeb7e7331126b4ac0bce0861ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 28 Sep 2017 10:24:47 +0200 Subject: [PATCH] Add & use "octoprint analysis gcode" subcommand That should solve any weird import issues we have when running gcodeInterpreter.py directly (and hence putting octoprint.util as first entry into the python path, causing potential issues with imported modules such as yaml to catch the octoprint.util.platform module instead of the actual python platform module). See reported problem with that by @CapnBry in #2095 --- src/octoprint/__main__.py | 7 +++ src/octoprint/cli/__init__.py | 3 +- src/octoprint/cli/analysis.py | 73 +++++++++++++++++++++++ src/octoprint/filemanager/analysis.py | 4 +- src/octoprint/util/gcodeInterpreter.py | 82 -------------------------- 5 files changed, 84 insertions(+), 85 deletions(-) create mode 100644 src/octoprint/__main__.py create mode 100644 src/octoprint/cli/analysis.py diff --git a/src/octoprint/__main__.py b/src/octoprint/__main__.py new file mode 100644 index 00000000..3dd81998 --- /dev/null +++ b/src/octoprint/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python2 +# coding=utf-8 +from __future__ import absolute_import, division, print_function + +if __name__ == "__main__": + import octoprint + octoprint.main() diff --git a/src/octoprint/cli/__init__.py b/src/octoprint/cli/__init__.py index 7a4133ce..1cc3d82e 100644 --- a/src/octoprint/cli/__init__.py +++ b/src/octoprint/cli/__init__.py @@ -135,9 +135,10 @@ from .plugins import plugin_commands from .dev import dev_commands from .client import client_commands from .config import config_commands +from .analysis import analysis_commands @click.group(name="octoprint", invoke_without_command=True, cls=click.CommandCollection, - sources=[server_commands, plugin_commands, dev_commands, client_commands, config_commands]) + sources=[server_commands, plugin_commands, dev_commands, client_commands, config_commands, analysis_commands]) @standard_options() @legacy_options @click.version_option(version=octoprint.__version__, allow_from_autoenv=False) diff --git a/src/octoprint/cli/analysis.py b/src/octoprint/cli/analysis.py new file mode 100644 index 00000000..34c90d78 --- /dev/null +++ b/src/octoprint/cli/analysis.py @@ -0,0 +1,73 @@ +# coding=utf-8 +from __future__ import absolute_import, division, print_function + +__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html' +__copyright__ = "Copyright (C) 2017 The OctoPrint Project - Released under terms of the AGPLv3 License" + +import click + +#~~ "octoprint util" commands + +@click.group() +def analysis_commands(): + pass + +@analysis_commands.group(name="analysis") +def util(): + """Analysis tools.""" + pass + + +@util.command(name="gcode") +@click.option("--throttle", "throttle", type=float, default=None) +@click.option("--throttle-lines", "throttle_lines", type=int, default=None) +@click.option("--speed-x", "speedx", type=float, default=6000) +@click.option("--speed-y", "speedy", type=float, default=6000) +@click.option("--speed-z", "speedz", type=float, default=300) +@click.option("--offset", "offset", type=(float, float), multiple=True) +@click.option("--max-t", "maxt", type=int, default=10) +@click.option("--g90-extruder", "g90_extruder", is_flag=True) +@click.option("--progress", "progress", is_flag=True) +@click.argument("path", type=click.Path()) +def gcode_command(path, speedx, speedy, speedz, offset, maxt, throttle, throttle_lines, g90_extruder, progress): + """Runs a GCODE file analysis.""" + + import time + import yaml + from octoprint.util.gcodeInterpreter import gcode + + throttle_callback = None + if throttle: + def throttle_callback(filePos, readBytes): + if filePos % throttle_lines == 0: + # only apply throttle every $throttle_lines lines + time.sleep(throttle) + + offsets = offset + if offsets is None: + offsets = [] + elif isinstance(offset, tuple): + offsets = list(offsets) + offsets = [(0, 0)] + offsets + if len(offsets) < maxt: + offsets += [(0, 0)] * (maxt - len(offsets)) + + start_time = time.time() + + progress_callback = None + if progress: + def progress_callback(percentage): + click.echo("PROGRESS:{}".format(percentage)) + interpreter = gcode(progress_callback=progress_callback) + + interpreter.load(path, + speedx=speedx, + speedy=speedy, + offsets=offsets, + throttle=throttle_callback, + max_extruders=maxt, + g90_extruder=g90_extruder) + + click.echo("DONE:{}s".format(time.time() - start_time)) + click.echo("RESULTS:") + click.echo(yaml.safe_dump(interpreter.get_result(), default_flow_style=False, indent=" ", allow_unicode=True)) diff --git a/src/octoprint/filemanager/analysis.py b/src/octoprint/filemanager/analysis.py index 33a7a2e8..9c913d81 100644 --- a/src/octoprint/filemanager/analysis.py +++ b/src/octoprint/filemanager/analysis.py @@ -324,8 +324,8 @@ class GcodeAnalysisQueue(AbstractAnalysisQueue): speedy = self._current.printer_profile["axes"]["y"]["speed"] offsets = self._current.printer_profile["extruder"]["offsets"] - interpreter = os.path.realpath(os.path.join(os.path.dirname(__file__), "..", "util", "gcodeInterpreter.py")) - command = [sys.executable, interpreter, "--speed-x={}".format(speedx), "--speed-y={}".format(speedy), + command = [sys.executable, "-m", "octoprint", "analysis", "gcode", + "--speed-x={}".format(speedx), "--speed-y={}".format(speedy), "--max-t={}".format(max_extruders), "--throttle={}".format(throttle), "--throttle-lines={}".format(throttle_lines)] for offset in offsets[1:]: diff --git a/src/octoprint/util/gcodeInterpreter.py b/src/octoprint/util/gcodeInterpreter.py index 2e8f62df..061564ce 100644 --- a/src/octoprint/util/gcodeInterpreter.py +++ b/src/octoprint/util/gcodeInterpreter.py @@ -512,85 +512,3 @@ def getCodeFloat(line, code): except: return None -if __name__ == "__main__": - import click - import time - import yaml - import sys - - @click.command() - @click.option("--throttle", "throttle", type=float, default=None) - @click.option("--throttle-lines", "throttle_lines", type=int, default=None) - @click.option("--speed-x", "speedx", type=float, default=6000) - @click.option("--speed-y", "speedy", type=float, default=6000) - @click.option("--speed-z", "speedz", type=float, default=300) - @click.option("--offset", "offset", type=(float, float), multiple=True) - @click.option("--max-t", "maxt", type=int, default=10) - @click.option("--g90-extruder", "g90_extruder", is_flag=True) - @click.option("--progress", "progress", is_flag=True) - @click.argument("path", type=click.Path()) - def main(path, speedx, speedy, speedz, offset, maxt, throttle, throttle_lines, g90_extruder, progress): - throttle_callback = None - if throttle: - def throttle_callback(filePos, readBytes): - if filePos % throttle_lines == 0: - # only apply throttle every $throttle_lines lines - time.sleep(throttle) - - offsets = offset - if offsets is None: - offsets = [] - elif isinstance(offset, tuple): - offsets = list(offsets) - offsets = [(0, 0)] + offsets - if len(offsets) < maxt: - offsets += [(0, 0)] * (maxt - len(offsets)) - - start_time = time.time() - - progress_callback = None - if progress: - def progress_callback(percentage): - print("PROGRESS:{}".format(percentage)) - interpreter = gcode(progress_callback=progress_callback) - - interpreter.load(path, - speedx=speedx, - speedy=speedy, - offsets=offsets, - throttle=throttle_callback, - max_extruders=maxt, - g90_extruder=g90_extruder) - - print("DONE:{}s".format(time.time() - start_time)) - print("RESULTS:") - print(yaml.safe_dump(interpreter.get_result(), default_flow_style=False, indent=" ", allow_unicode=True)) - - # os args are gained differently on win32 - try: - from click.utils import get_os_args - args = get_os_args() - except ImportError: - # for whatever reason we are running an older Click version? - args = sys.argv[1:] - - if len(args) >= len(sys.argv): - # Now some ugly preprocessing of our arguments starts. We have a somewhat difficult situation on our hands - # here if we are running under Windows and want to be able to handle utf-8 command line parameters (think - # plugin parameters such as names or something, e.g. for the "dev plugin:new" command) while at the same - # time also supporting sys.argv rewriting for debuggers etc (e.g. PyCharm). - # - # So what we try to do here is solve this... Generally speaking, sys.argv and whatever Windows returns - # for its CommandLineToArgvW win32 function should have the same length. If it doesn't however and - # sys.argv is shorter than the win32 specific command line arguments, obviously stuff was cut off from - # sys.argv which also needs to be cut off of the win32 command line arguments. - # - # So this is what we do here. - - # -1 because first entry is the script that was called - sys_args_length = len(sys.argv) - 1 - - # cut off stuff from the beginning - args = args[-1 * sys_args_length:] if sys_args_length else [] - - main(args=args, prog_name="octoprint-gcode-analysis")