Use UTF-8 for _all_ output from sarge

Lines taking from the asynchronous processing of stdout/stderr where
left as str, leading to encoding problems when utf8 characters showed
up in the stream and were being interpreted as ascii encoding.
(cherry picked from commit 9373be3)
This commit is contained in:
Gina Häußge 2015-07-02 08:36:03 +02:00
parent 7b3e0563cc
commit d7a86a4d28
5 changed files with 54 additions and 35 deletions

View file

@ -218,7 +218,7 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
if not on_progress_kwargs:
on_progress_kwargs = dict()
self._cura_logger.info("### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
self._cura_logger.info(u"### Slicing %s to %s using profile stored at %s" % (model_path, machinecode_path, profile_path))
engine_settings = self._convert_to_engine(profile_path, printer_profile, posX, posY)
@ -227,16 +227,15 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
return False, "Path to CuraEngine is not configured "
working_dir, _ = os.path.split(executable)
args = ['"%s"' % executable, '-v', '-p']
args = [executable, '-v', '-p']
for k, v in engine_settings.items():
args += ["-s", '"%s=%s"' % (k, str(v))]
args += ['-o', '"%s"' % machinecode_path, '"%s"' % model_path]
args += ["-s", "%s=%s" % (k, str(v))]
args += ["-o", machinecode_path, model_path]
self._logger.info(u"Running %r in %s" % (" ".join(args), working_dir))
import sarge
command = " ".join(args)
self._logger.info("Running %r in %s" % (command, working_dir))
p = sarge.run(command, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture())
p = sarge.run(args, cwd=working_dir, async=True, stdout=sarge.Capture(), stderr=sarge.Capture())
p.wait_events()
self._slicing_commands[machinecode_path] = p.commands[0]
@ -254,6 +253,7 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
p.commands[0].poll()
continue
line = octoprint.util.to_unicode(line, errors="replace")
self._cura_logger.debug(line.strip())
if on_progress is not None:
@ -282,14 +282,14 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
#
# with <step_factor> being 0 for "inset", 1 for "skin" and 2 for "export".
if line.startswith("Layer count:") and layer_count is None:
if line.startswith(u"Layer count:") and layer_count is None:
try:
layer_count = float(line[len("Layer count:"):].strip())
layer_count = float(line[len(u"Layer count:"):].strip())
except:
pass
elif line.startswith("Progress:"):
split_line = line[len("Progress:"):].strip().split(":")
elif line.startswith(u"Progress:"):
split_line = line[len(u"Progress:"):].strip().split(":")
if len(split_line) == 3:
step, current_layer, _ = split_line
try:
@ -302,21 +302,21 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
on_progress_kwargs["_progress"] = (step_factor[step] * layer_count + current_layer) / (layer_count * 3)
on_progress(*on_progress_args, **on_progress_kwargs)
elif line.startswith("Print time:"):
elif line.startswith(u"Print time:"):
try:
print_time = int(line[len("Print time:"):].strip())
print_time = int(line[len(u"Print time:"):].strip())
if analysis is None:
analysis = dict()
analysis["estimatedPrintTime"] = print_time
except:
pass
elif line.startswith("Filament:") or line.startswith("Filament2:"):
if line.startswith("Filament:"):
filament_str = line[len("Filament:"):].strip()
elif line.startswith(u"Filament:") or line.startswith(u"Filament2:"):
if line.startswith(u"Filament:"):
filament_str = line[len(u"Filament:"):].strip()
tool_key = "tool0"
else:
filament_str = line[len("Filament2:"):].strip()
filament_str = line[len(u"Filament2:"):].strip()
tool_key = "tool1"
try:
@ -339,20 +339,20 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
with self._job_mutex:
if machinecode_path in self._cancelled_jobs:
self._cura_logger.info("### Cancelled")
self._cura_logger.info(u"### Cancelled")
raise octoprint.slicing.SlicingCancelled()
self._cura_logger.info("### Finished, returncode %d" % p.returncode)
self._cura_logger.info(u"### Finished, returncode %d" % p.returncode)
if p.returncode == 0:
return True, dict(analysis=analysis)
else:
self._logger.warn("Could not slice via Cura, got return code %r" % p.returncode)
self._logger.warn(u"Could not slice via Cura, got return code %r" % p.returncode)
return False, "Got returncode %r" % p.returncode
except octoprint.slicing.SlicingCancelled as e:
raise e
except:
self._logger.exception("Could not slice via Cura, got an unknown error")
self._logger.exception(u"Could not slice via Cura, got an unknown error")
return False, "Unknown error, please consult the log file"
finally:
@ -371,7 +371,7 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin,
command = self._slicing_commands[machinecode_path]
if command is not None:
command.terminate()
self._logger.info("Cancelled slicing of %s" % machinecode_path)
self._logger.info(u"Cancelled slicing of %s" % machinecode_path)
def _load_profile(self, path):
import yaml

View file

@ -418,13 +418,13 @@ class PluginManagerPlugin(octoprint.plugin.SimpleApiPlugin,
return self._pip_caller.execute(*args)
def _log_call(self, *lines):
self._log(lines, prefix=" ", stream="call")
self._log(lines, prefix=u" ", stream="call")
def _log_stdout(self, *lines):
self._log(lines, prefix=">", stream="stdout")
self._log(lines, prefix=u">", stream="stdout")
def _log_stderr(self, *lines):
self._log(lines, prefix="!", stream="stderr")
self._log(lines, prefix=u"!", stream="stderr")
def _log(self, lines, prefix=None, stream=None, strip=True):
if strip:

View file

@ -46,12 +46,12 @@ def perform_update(target, check, target_version):
install_arg = check["pip"].format(target_version=target_version)
logger.debug("Target: %s, executing pip install %s" % (target, install_arg))
logger.debug(u"Target: %s, executing pip install %s" % (target, install_arg))
pip_args = ["install", check["pip"].format(target_version=target_version, target=target_version)]
pip_caller.execute(*pip_args)
logger.debug("Target: %s, executing pip install %s --ignore-reinstalled --force-reinstall --no-deps" % (target, install_arg))
logger.debug(u"Target: %s, executing pip install %s --ignore-reinstalled --force-reinstall --no-deps" % (target, install_arg))
pip_args += ["--ignore-installed", "--force-reinstall", "--no-deps"]
pip_caller.execute(*pip_args)
@ -59,13 +59,13 @@ def perform_update(target, check, target_version):
return "ok"
def _log_call(*lines):
_log(lines, prefix=" ")
_log(lines, prefix=u" ")
def _log_stdout(*lines):
_log(lines, prefix=">")
_log(lines, prefix=u">")
def _log_stderr(*lines):
_log(lines, prefix="!")
_log(lines, prefix=u"!")
def _log(lines, prefix=None):
lines = map(lambda x: x.strip(), lines)

View file

@ -352,9 +352,7 @@ def silent_remove(file):
def sanitize_ascii(line):
if not isinstance(line, basestring):
raise ValueError("Expected either str or unicode but got {} instead".format(line.__class__.__name__ if line is not None else None))
if isinstance(line, str):
line = unicode(line, 'ascii', 'replace')
return line.encode('ascii', 'replace').rstrip()
return to_unicode(line, encoding="ascii", errors="replace").rstrip()
def filter_non_ascii(line):
@ -369,12 +367,28 @@ def filter_non_ascii(line):
"""
try:
unicode(line, 'ascii').encode('ascii')
to_str(to_unicode(line, encoding="ascii"), encoding="ascii")
return False
except ValueError:
return True
def to_str(s_or_u, encoding="utf-8", errors="strict"):
"""Make sure ``s_or_u`` is a str."""
if isinstance(s_or_u, unicode):
return s_or_u.encode(encoding, errors=errors)
else:
return s_or_u
def to_unicode(s_or_u, encoding="utf-8", errors="strict"):
"""Make sure ``s_or_u`` is a unicode string."""
if isinstance(s_or_u, str):
return s_or_u.decode(encoding, errors=errors)
else:
return s_or_u
def dict_merge(a, b):
"""
Recursively deep-merges two dictionaries.

View file

@ -11,6 +11,9 @@ import sys
import logging
from octoprint.util import to_unicode
class UnknownPip(Exception):
pass
@ -77,11 +80,13 @@ class PipCaller(object):
while p.returncode is None:
line = p.stderr.readline(timeout=0.5)
if line:
line = to_unicode(line, errors="replace")
self._log_stderr(line)
all_stderr.append(line)
line = p.stdout.readline(timeout=0.5)
if line:
line = to_unicode(line, errors="replace")
self._log_stdout(line)
all_stdout.append(line)