From 71d73c65625882d15b5aba01f80937b61e5c84f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Tue, 21 Oct 2014 14:14:00 +0200 Subject: [PATCH] Do not try to slice on local slicers when printing Since slicing takes a lot of resources, that might lead to quality loss for the print job. --- src/octoprint/plugin/types.py | 11 ++++---- src/octoprint/plugins/cura/__init__.py | 14 +++++----- src/octoprint/server/api/files.py | 26 ++++++++++++++----- src/octoprint/server/api/slicing.py | 2 +- src/octoprint/slicing/__init__.py | 4 +-- .../static/js/app/viewmodels/files.js | 4 +++ src/octoprint/templates/index.jinja2 | 2 +- tests/filemanager/test_filemanager.py | 12 +++++++-- tests/slicing/test_slicingmanager.py | 6 ++--- 9 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/octoprint/plugin/types.py b/src/octoprint/plugin/types.py index 72954377..12e41dab 100644 --- a/src/octoprint/plugin/types.py +++ b/src/octoprint/plugin/types.py @@ -194,11 +194,12 @@ class SlicerPlugin(Plugin): def is_slicer_configured(self): return False - def get_slicer_type(self): - return None - - def get_slicer_name(self): - return None + def get_slicer_properties(self): + return dict( + type=None, + name=None, + same_device=True, + ) def get_slicer_profile_options(self): return None diff --git a/src/octoprint/plugins/cura/__init__.py b/src/octoprint/plugins/cura/__init__.py index 037a9bc3..9e963919 100644 --- a/src/octoprint/plugins/cura/__init__.py +++ b/src/octoprint/plugins/cura/__init__.py @@ -190,11 +190,12 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin, cura_engine = s.get(["cura_engine"]) return cura_engine is not None and os.path.exists(cura_engine) - def get_slicer_type(self): - return "cura" - - def get_slicer_name(self): - return "CuraEngine" + def get_slicer_properties(self): + return dict( + type="cura", + name="CuraEngine", + same_device=True + ) def get_slicer_default_profile(self): path = s.get(["default_profile"]) @@ -214,7 +215,8 @@ class CuraPlugin(octoprint.plugin.SlicerPlugin, description = profile_dict["_description"] del profile_dict["_description"] - return octoprint.slicing.SlicingProfile(self.get_slicer_type(), "unknown", profile_dict, display_name=display_name, description=description) + properties = self.get_slicer_properties() + return octoprint.slicing.SlicingProfile(properties["type"], "unknown", profile_dict, display_name=display_name, description=description) def save_slicer_profile(self, path, profile, allow_overwrite=True, overrides=None): new_profile = Profile.merge_profile(profile.data, overrides=overrides) diff --git a/src/octoprint/server/api/files.py b/src/octoprint/server/api/files.py index 33b04398..6f8b78ec 100644 --- a/src/octoprint/server/api/files.py +++ b/src/octoprint/server/api/files.py @@ -301,14 +301,20 @@ def gcodeFileCommand(filename, target): del data["slicer"] if not slicer in slicingManager.registered_slicers: return make_response("Slicer {slicer} is not available".format(**locals()), 400) + slicer_instance = slicingManager.get_slicer(slicer) elif "cura" in slicingManager.registered_slicers: slicer = "cura" + slicer_instance = slicingManager.get_slicer("cura") else: return make_response("Cannot slice {filename}, no slicer available".format(**locals()), 415) if not octoprint.filemanager.valid_file_type(filename, type="stl"): return make_response("Cannot slice {filename}, not an STL file".format(**locals()), 415) + if slicer_instance.get_slicer_properties()["same_device"] and (printer.isPrinting or printer.isPaused()): + # slicer runs on same device as OctoPrint, slicing while printing is hence disabled + return make_response("Cannot slice on {slicer} while printing due to performance reasons".format(**locals()), 409) + if "gcode" in data.keys() and data["gcode"]: gcode_name = data["gcode"] del data["gcode"] @@ -317,6 +323,11 @@ def gcodeFileCommand(filename, target): name, _ = os.path.splitext(filename) gcode_name = name + ".gco" + # prohibit overwriting the file that is currently being printed + currentOrigin, currentFilename = _getCurrentFile() + if currentFilename == gcode_name and currentOrigin == target and (printer.isPrinting() or printer.isPaused()): + make_response("Trying to slice into file that is currently being printed: %s" % gcode_name, 409) + if "profile" in data.keys() and data["profile"]: profile = data["profile"] del data["profile"] @@ -359,14 +370,8 @@ def deleteGcodeFile(filename, target): if not _verifyFileExists(target, filename): return make_response("File not found on '%s': %s" % (target, filename), 404) - currentJob = printer.getCurrentJob() - currentFilename = None - currentOrigin = None - if currentJob is not None and "file" in currentJob.keys() and "name" in currentJob["file"] and "origin" in currentJob["file"]: - currentFilename = currentJob["file"]["name"] - currentOrigin = currentJob["file"]["origin"] - # prohibit deleting the file that is currently being printed + currentOrigin, currentFilename = _getCurrentFile() if currentFilename == filename and currentOrigin == target and (printer.isPrinting() or printer.isPaused()): make_response("Trying to delete file that is currently being printed: %s" % filename, 409) @@ -382,3 +387,10 @@ def deleteGcodeFile(filename, target): return NO_CONTENT +def _getCurrentFile(): + currentJob = printer.getCurrentJob() + if currentJob is not None and "file" in currentJob.keys() and "name" in currentJob["file"] and "origin" in currentJob["file"]: + return currentJob["file"]["origin"], currentJob["file"]["name"] + else: + return None, None + diff --git a/src/octoprint/server/api/slicing.py b/src/octoprint/server/api/slicing.py index 90dc9fd7..6d03ced3 100644 --- a/src/octoprint/server/api/slicing.py +++ b/src/octoprint/server/api/slicing.py @@ -22,7 +22,7 @@ def slicingListAll(): for slicer in slicingManager.registered_slicers: result[slicer] = dict( key=slicer, - displayName=slicingManager.get_slicer(slicer).get_slicer_name(), + displayName=slicingManager.get_slicer(slicer).get_slicer_properties()["name"], default=default_slicer == slicer, profiles=_getSlicingProfilesData(slicer) ) diff --git a/src/octoprint/slicing/__init__.py b/src/octoprint/slicing/__init__.py index 3421e4e6..66e56021 100644 --- a/src/octoprint/slicing/__init__.py +++ b/src/octoprint/slicing/__init__.py @@ -69,7 +69,7 @@ class SlicingManager(object): plugins = octoprint.plugin.plugin_manager().get_implementations(octoprint.plugin.SlicerPlugin) for name, plugin in plugins.items(): if plugin.is_slicer_configured(): - self._slicers[plugin.get_slicer_type()] = plugin + self._slicers[plugin.get_slicer_properties()["type"]] = plugin @property def slicing_enabled(self): @@ -106,7 +106,7 @@ class SlicingManager(object): def slicer_worker(slicer, model_path, machinecode_path, profile_name, overrides, callback, callback_args, callback_kwargs): try: - slicer_name = slicer.get_slicer_type() + slicer_name = slicer.get_slicer_properties()["type"] with self.temporary_profile(slicer_name, name=profile_name, overrides=overrides) as profile_path: ok, result = slicer.do_slice( model_path, diff --git a/src/octoprint/static/js/app/viewmodels/files.js b/src/octoprint/static/js/app/viewmodels/files.js index 9b8de430..130f5260 100644 --- a/src/octoprint/static/js/app/viewmodels/files.js +++ b/src/octoprint/static/js/app/viewmodels/files.js @@ -261,6 +261,10 @@ function GcodeFilesViewModel(printerStateViewModel, loginStateViewModel, slicing return isLoadActionPossible && !self.listHelper.isSelected(data); }; + self.enableSlicing = function(data) { + return self.loginState.isUser() && !(self.isPrinting() || self.isPaused()); + }; + self.enableAdditionalData = function(data) { return data["gcodeAnalysis"] || data["prints"] && data["prints"]["last"]; }; diff --git a/src/octoprint/templates/index.jinja2 b/src/octoprint/templates/index.jinja2 index 53e2c090..cdf9e7cc 100644 --- a/src/octoprint/templates/index.jinja2 +++ b/src/octoprint/templates/index.jinja2 @@ -237,7 +237,7 @@
{{ _('Size') }}:
-
+
diff --git a/tests/filemanager/test_filemanager.py b/tests/filemanager/test_filemanager.py index f7d3d097..a7f1ddca 100644 --- a/tests/filemanager/test_filemanager.py +++ b/tests/filemanager/test_filemanager.py @@ -137,12 +137,16 @@ class FileManagerTest(unittest.TestCase): self.local_storage.add_file.side_effect = add_file # mock slice method on slicing manager - def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None): + def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): self.assertEquals("some_slicer", slicer_name) self.assertEquals("prefix/source.file", source_path) self.assertEquals("tmp.file", dest_path) self.assertIsNone(profile) self.assertIsNone(overrides) + self.assertIsNotNone(on_progress) + self.assertIsNotNone(on_progress_args) + self.assertTupleEqual(("some_slicer", octoprint.filemanager.FileDestinations.LOCAL, "source.file", octoprint.filemanager.FileDestinations.LOCAL, "dest.file"), on_progress_args) + self.assertIsNone(on_progress_kwargs) if not callback_args: callback_args = () @@ -199,12 +203,16 @@ class FileManagerTest(unittest.TestCase): self.local_storage.get_absolute_path.side_effect = get_absolute_path # mock slice method on slicing manager - def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None): + def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): self.assertEquals("some_slicer", slicer_name) self.assertEquals("prefix/source.file", source_path) self.assertEquals("tmp.file", dest_path) self.assertIsNone(profile) self.assertIsNone(overrides) + self.assertIsNotNone(on_progress) + self.assertIsNotNone(on_progress_args) + self.assertTupleEqual(("some_slicer", octoprint.filemanager.FileDestinations.LOCAL, "source.file", octoprint.filemanager.FileDestinations.LOCAL, "dest.file"), on_progress_args) + self.assertIsNone(on_progress_kwargs) if not callback_args: callback_args = () diff --git a/tests/slicing/test_slicingmanager.py b/tests/slicing/test_slicingmanager.py index 30e3dc45..9a209f3e 100644 --- a/tests/slicing/test_slicingmanager.py +++ b/tests/slicing/test_slicingmanager.py @@ -19,7 +19,7 @@ class TestSlicingManager(unittest.TestCase): self.profile_path = tempfile.mkdtemp() self.slicer_plugin = mock.MagicMock() - self.slicer_plugin.get_slicer_type.return_value = "mock" + self.slicer_plugin.get_slicer_properties.return_value = dict(type="mock", name="Mock", same_device=True) # mock plugin manager self.plugin_manager_patcher = mock.patch("octoprint.plugin.plugin_manager") @@ -45,7 +45,7 @@ class TestSlicingManager(unittest.TestCase): def get_implementations(*types): import octoprint.plugin if octoprint.plugin.SlicerPlugin in types: - return dict(("slicer_" + plugin.get_slicer_type(), plugin) for plugin in plugins) + return dict(("slicer_" + plugin.get_slicer_properties()["type"], plugin) for plugin in plugins) return dict() self.plugin_manager.return_value.get_implementations.side_effect = get_implementations @@ -135,7 +135,7 @@ class TestSlicingManager(unittest.TestCase): mock_thread.mock.start.assert_called_once() # assert that slicer was called correctly - self.slicer_plugin.do_slice.assert_called_once_with("prefix/source.file", machinecode_path="prefix/dest.file", profile_path="tmp.file") + self.slicer_plugin.do_slice.assert_called_once_with("prefix/source.file", machinecode_path="prefix/dest.file", profile_path="tmp.file", on_progress=None, on_progress_args=None, on_progress_kwargs=None) # assert that temporary profile was deleted again mocked_os_remove.assert_called_once_with("tmp.file")