From 8e500b78aade9a615bdc673e508fc05368533804 Mon Sep 17 00:00:00 2001 From: Ross Hendrickson Date: Sat, 17 Aug 2013 00:26:47 -0500 Subject: [PATCH] Add logic to parser to handle multi line path. Create tests for new functionality --- octoprint/cura/__init__.py | 10 ++- octoprint/cura/parser.py | 98 +++++++++++++++++++++++------ octoprint/cura/tests/test_cura.py | 5 +- octoprint/cura/tests/test_parser.py | 56 +++++++++++++++++ 4 files changed, 145 insertions(+), 24 deletions(-) diff --git a/octoprint/cura/__init__.py b/octoprint/cura/__init__.py index 256ffa50..6e9f34c0 100644 --- a/octoprint/cura/__init__.py +++ b/octoprint/cura/__init__.py @@ -36,6 +36,8 @@ class CuraEngine(object): def process_file( self, config, gcode, file_path, call_back=None, call_back_args=None): + + from octoprint.cura import parser """Wraps around the main.cpp processFile method. :param config: :class: `string` :path to a cura config file: @@ -54,7 +56,13 @@ class CuraEngine(object): call_back(*call_back_args) logging.info("Slicing call back complete:%s" % str(call_back)) - args = [self.cura_path, '-s', config, '-o', gcode, file_path] + + args = [self.cura_path, '-o', gcode, file_path] + + settings = parser.process_profile_ini(config) + + args.extend(settings) + logging.info('CuraEngine args:%s' % str(args)) thread = threading.Thread(target=start_thread, args=(call_back, diff --git a/octoprint/cura/parser.py b/octoprint/cura/parser.py index 42d557a5..f8d7ea5b 100644 --- a/octoprint/cura/parser.py +++ b/octoprint/cura/parser.py @@ -9,40 +9,64 @@ def process_profile_ini(filename): :note: The filename should be the full path to the profile.ini """ + if not filename: + raise ValueError("No file name to process") - profile = open(filename, 'r') + # This made it easier to mock and test + profile = read_filename(filename) data = {} + logging.info("Processing %s" % filename) for line in profile: if _is_multi_start(line): + read_multi_line(line, profile, data) - multi_line = line - - while(not _is_multi_end(line)): - line = profile.readline() - multi_line += next_line - - data = process_multi_setting_line(data, multi_line) - if _is_single(line): - data = process_setting_line(data, setting_line) - - profile.close() + data = process_setting_line(data, line) return format_data_for_command(data) +def read_multi_line(line, profile, data): -def _is_multi_start(line): - pass + multi_line = line + + line = profile.readline() + + if _is_multi_continue(line): + multi_line += line + + if _is_single(line): + data = process_setting_line(data, multi_line) + data = process_setting_line(data, line) + return + + while(_is_multi_continue(line)): + + line = profile.readline() + + if not line: + break + + if _is_single(line): + data = process_setting_line(data, line) + break + + if _is_multi_start(line): + read_multi_line(line, profile, data) + break + + multi_line += line + + data = process_multi_setting_line(data, multi_line) -def _is_multi_end(line): - pass -def _is_single(line): - pass +def process_multi_setting_line(data, multi_line): + + data = process_setting_line(data, multi_line) + return data def process_setting_line(data, setting_line): @@ -61,13 +85,21 @@ def process_setting_line(data, setting_line): # TODO: Make this more fault tolerant + # Changes var_with_underscore to varWithUnderscore split = setting_line.split("=") variable_parts = split[0].split("_") end_variable_parts = ''.join(word.title() for word in variable_parts[1:]) - new_name = str(variable_parts[0]) + end_variable_parts + new_name = (str(variable_parts[0]) + end_variable_parts).strip() + new_value = split[1].strip() - data[new_name] = split[1].strip() + if '.gcode' in new_name: + new_name = new_name.replace('.gcode', 'Code') + + # might need to surround the value in quotes? + #new_value = "'" + new_value + "'" + + data[new_name] = new_value return data @@ -89,3 +121,29 @@ def format_data_for_command(data): result.extend(['-s', '%s=%s' % (key, str(value))]) return result + + +def read_filename(filename): + + lines = open(filename, 'r').read() + return lines + +def _is_multi_start(line): + + if '.gcode' in line or "=" in line and "(lp" in line: + return True + +def _is_multi_continue(line): + + if '=' not in line: + return True + + if '.gcode' not in line and '=' not in line: + return True + +def _is_single(line): + + if '=' in line and '.gcode' not in line: + return True + + diff --git a/octoprint/cura/tests/test_cura.py b/octoprint/cura/tests/test_cura.py index 791d4e7d..69f72135 100644 --- a/octoprint/cura/tests/test_cura.py +++ b/octoprint/cura/tests/test_cura.py @@ -17,8 +17,9 @@ class CuraFactoryTestCase(unittest.TestCase): self.assertEqual(fake_path, result.cura_path) + @patch('octoprint.cura.parser.process_profile_ini') @patch('threading.Thread') - def test_cura_engine_process_file(self, thread): + def test_cura_engine_process_file(self, thread, process): path = 'rosshendrickson/workspaces/opensource/CuraEngine/' cura_engine = CuraFactory.create_slicer(path) @@ -26,8 +27,6 @@ class CuraFactoryTestCase(unittest.TestCase): config_path = './cura/tests/config' gcode_filename= './cura/tests/output.gcode' - args = [path, '-s', config_path, '-o', file_path] - cura_engine.process_file(config_path, gcode_filename, file_path) self.assertTrue(thread.called) diff --git a/octoprint/cura/tests/test_parser.py b/octoprint/cura/tests/test_parser.py index 659de572..4eb29702 100644 --- a/octoprint/cura/tests/test_parser.py +++ b/octoprint/cura/tests/test_parser.py @@ -1,7 +1,13 @@ import logging import unittest +from StringIO import StringIO +import io +from mock import patch +from mock import MagicMock +from mock import Mock + class ParserTestCase(unittest.TestCase): def setUp(self): @@ -11,8 +17,11 @@ class ParserTestCase(unittest.TestCase): layer_height = 0.1 retraction_enable = False solid_layer_thickness = 0.6 +end4.gcode = ;end gcode nozzle_size = 0.5 print_speed = 50 +end.gcode = ;End gcode + M102 T0 ; whatever print_temperature = 220 print_temperature2 = 0 start2.gcode = ;Sliced at: {day} {date} {time} @@ -35,8 +44,55 @@ end2.gcode = ;End GCode G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way M84 ;steppers off G90 ;absolute positioning +print_temperature3 = 0 """ + @patch('octoprint.cura.parser.read_filename') + def test_process_profile_ini(self, open_f): + + from octoprint.cura.parser import process_profile_ini + + open_f.return_value = StringIO(self.setting_string) + + result = process_profile_ini('fake_filename') + + logging.info(str(result)) + + expected = len([line for line in self.setting_string if '=' in line])*2 + self.assertEqual(len(result), expected) + + def test_is_mult_line(self): + + from octoprint.cura.parser import _is_multi_start + test = "cool_end_start = 1.0" + + self.assertFalse(_is_multi_start(test)) + + test = "G92 E0" + + self.assertFalse(_is_multi_start(test)) + + test = "start2.gcode = ;Sliced at:" + + self.assertTrue(_is_multi_start(test)) + + test = "plugin_config = (lp1" + + self.assertTrue(_is_multi_start(test)) + + + def test_is_single_line(self): + + from octoprint.cura.parser import _is_single + test = "cool_end_start = 1.0" + + self.assertTrue(_is_single(test)) + + test = "G92 E0" + + self.assertFalse(_is_single(test)) + + def test_process_setting_line(self): from octoprint.cura.parser import process_setting_line