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
This commit is contained in:
Gina Häußge 2017-09-28 10:24:47 +02:00
parent 79f7a5a1e7
commit c84e199e87
5 changed files with 84 additions and 85 deletions

View file

@ -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()

View file

@ -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)

View file

@ -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))

View file

@ -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:]:

View file

@ -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")