def testParallel(self): print("\n=== Parallel without Wait ===") table_scan = TableScan(("+p A", "+p B", "C", "+p D", "+p E", "F"), [ ["1", "2", "3", "4", "5", "6"], ]) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Parallel(Set('A', 1.0), Set('B', 2.0)), Set('C', 3.0), Parallel(Set('D', 4.0), Set('E', 5.0)), Set('F', 6.0)]" ) print("\n=== Parallel with Wait For ===") table_scan = TableScan( ("+p A", "+p B", "C", "+p D", "+p E", "Wait For", "Value"), [ ["1", "2", "3", "4", "5", "completion", "10"], ["6", "7", "8", "9", "10", "Seconds", "10"], ], start=Comment('Start Run'), stop=Comment('Stop Run')) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Parallel(Set('A', 1.0), Set('B', 2.0)), Set('C', 3.0), Comment('Start Run'), Parallel(Set('D', 4.0), Set('E', 5.0)), Log('A', 'B', 'C', 'D', 'E'), Comment('Stop Run'), Parallel(Set('A', 6.0), Set('B', 7.0)), Set('C', 8.0), Parallel(Set('D', 9.0), Set('E', 10.0)), Comment('Start Run'), Delay(10), Log('A', 'B', 'C', 'D', 'E'), Comment('Stop Run')]" ) print("\n=== Parallel with Delay and Wait For ===") table_scan = TableScan( ("+p A", "+p B", "Delay", "Wait For", "Value"), [ ["1", "2", "00:05:00", "counts", "10"], ], start=Comment('Start Run'), stop=Comment('Stop Run'), special={'Delay': lambda cell: Delay(parseSeconds(cell))}) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Parallel(Set('A', 1.0), Set('B', 2.0)), Delay(300), Comment('Start Run'), Wait('counts', 10.0, comparison='>=', tolerance=0.1), Log('A', 'B', 'counts'), Comment('Stop Run')]" ) print("\n=== Parallel with range and Delay ===") table_scan = TableScan( ("+p A", "+p B", "Delay"), [ ["1", "[2, 4, 6]", "00:05:00"], ], special={'Delay': lambda cell: Delay(parseSeconds(cell))}) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Parallel(Set('A', 1.0), Set('B', 2.0)), Delay(300), Parallel(Set('A', 1.0), Set('B', 4.0)), Delay(300), Parallel(Set('A', 1.0), Set('B', 6.0)), Delay(300)]" ) print("\n=== Parallel with Timeout ===") table_scan = TableScan(("+p A", "Wait For", "Value", "Or Time"), [ ["1", "Completion", "", "00:05:00"], ]) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Parallel(Set('A', 1.0), timeout=300, errhandler='OnErrorContinue'), Log('A')]" )
def testSpecialColumns(self): print("\n=== Special columns ===") # Commands Start/Next/End turn into Include("lf_start.scn"), Include("lf_next.scn") resp. Include("lf_end.scn") special = { 'Run Control': lambda cell: Include(cell + ".scn"), 'Delay': lambda cell: Delay(parseSeconds(cell)), } table_scan = TableScan(( "Run Control", "X", "Delay", "Wait For", "Value", ), [ ["Start", "10", "", "Neutrons", "10"], ["", "20", "00:01:00", "Neutrons", "10"], ["Stop", "", "", "", ""], ], special=special) cmds = handle(table_scan) self.assertEqual( str(cmds), "[Include('Start.scn'), Set('X', 10.0), Wait('Neutrons', 10.0, comparison='>=', tolerance=0.1), Log('X', 'Neutrons'), Set('X', 20.0), Delay(60), Wait('Neutrons', 10.0, comparison='>=', tolerance=0.1), Log('X', 'Neutrons'), Include('Stop.scn')]" )
def createScan(self, lineinfo=True): """Create scan. :param lineinfo: By default Comment commands are added for line info. If scan settings include a "table_scan_row", that PV will also be set. :return: List of commands. """ # Parse column headers. settings = getScanSettings() col_device = [None for i in range(self.cols)] i = 0 while i < self.cols: if self.headers[i] == TableScan.WAITFOR: # Column TableScan.WAITFOR must be followed by TableScan.VALUE if i >= self.cols - 1 or self.headers[i + 1] != TableScan.VALUE: raise ValueError(TableScan.WAITFOR + " column must be followed by " + TableScan.VALUE) # .. and may then be followed by TableScan.OR_TIME if i < self.cols - 2 and self.headers[i + 2] == TableScan.OR_TIME: i += 2 else: i += 1 elif self.headers[i] == TableScan.COMMENT: # Comment is no device name pass else: # Parse device info col_device[i] = settings.parseDeviceSettings(self.headers[i]) i += 1 # Add first column of line numbers numbered = [] for row in self.rows: numbered_row = list(row) numbered_row.insert(0, len(numbered) + 1) numbered.append(numbered_row) # Expand any range(start, end, step) cells # (which will duplicate the line numbers) expanded_rows = expandRanges(numbered) # Assemble commands for each row in the table current_line = 0 commands = list() log_devices = list() if self.log_always is not None: log_devices = list(self.log_always) if self.pre: commands += self.pre for numbered_row in expanded_rows: line = numbered_row[0] row = numbered_row[1:] row_commands = commands if line != current_line: if lineinfo: row_commands.append(Comment("# Line %d" % line)) if settings.table_scan_row: row_commands.append( SettingsBasedSet(settings.table_scan_row, line)) current_line = line # Parallel commands to execute in this row self.parallel_commands = list() # Handle all columns c = 0 while c < self.cols: what = self.headers[c] if len(row[c]) <= 0: pass # Empty column, nothing to do elif what in self.special: self.__flushParallel(row_commands) special_handler = self.special[what] value = self.__getValue(row[c]) command = special_handler(value) row_commands.append(command) elif what == TableScan.COMMENT: self.__flushParallel(row_commands) text = row[c] row_commands.append(Comment(text)) # TODO if self.settings.comment: # row_commands.append(SetCommand(self.settings.comment, text)) elif what == TableScan.WAITFOR: waitfor = row[c] value = self.__getValue(row[c + 1]) if waitfor.lower() != TableScan.COMPLETION: # Complete accumulated parallel_commands before starting the run self.__flushParallel(row_commands) # Optional commands to mark start of a "Wait For" if self.start: row_commands += self.start if waitfor.lower() == TableScan.COMPLETION: # Assert that there are any parallel commands, # because otherwise the 'WaitFor - Completion' was likely an error if not self.__flushParallel(row_commands): raise Exception( "Line %d has no parallel commands to complete" % line) elif waitfor.lower() in (TableScan.SECONDS, TableScan.TIME): if value: row_commands.append(Delay(parseSeconds(value))) else: timeout = None errhandler = None if c + 2 < self.cols and self.headers[ c + 2] == TableScan.OR_TIME: or_time = row[c + 2].strip() if len(or_time) > 0: timeout = parseSeconds(or_time) errhandler = "OnErrorContinue" cmd = SettingsBasedWait(waitfor, value, timeout=timeout, errhandler=errhandler) row_commands.append(cmd) if not waitfor in log_devices: log_devices.append(waitfor) if len(log_devices) > 0: row_commands.append(Log(log_devices)) # Optional commands to mark end of a "Wait For" if self.stop: row_commands += self.stop # Skip TableScan.VALUE in addition to current column, # so next two Exceptions should not happen unless there's an empty "WAIT_FOR" if c + 2 < self.cols and self.headers[ c + 2] == TableScan.OR_TIME: c = c + 2 else: c = c + 1 elif what == TableScan.VALUE: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[c], TableScan.VALUE, TableScan.WAITFOR, str(row))) elif what == TableScan.OR_TIME: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[c], TableScan.OR_TIME, TableScan.WAITFOR, str(row))) else: # 'Normal' column that sets a device directly or in loop device = col_device[c] value = self.__getValue(row[c]) if type(value) is float: loop = None else: loop = getRangeOrLoop(str(value), loop_matcher) if loop is None: command = SettingsBasedSet(what, value) if device.getParallel(): # Add one more parallel command self.parallel_commands.append(command) else: # Normal command, flush accumulated parallel commands self.__flushParallel(row_commands) row_commands.append(command) else: # Create loop self.__flushParallel(row_commands) if device.getParallel(): raise Exception( "Line %d: Cannot use loop(..) with parallel access in column '%s'" % (line, what)) body = list() command = SettingsBasedLoop(what, loop[0], loop[1], loop[2], body) row_commands.append(command) # Place remaining commands in row into body of this loop row_commands = command.getBody() if not device.getName() in log_devices: log_devices.append(device.getName()) c = c + 1 # End of columns in row # Complete accumulated parallel commands self.__flushParallel(row_commands) # End of row if self.post: # End one long run at end of table commands += self.post if lineinfo: commands.append(Comment("# End")) return commands
def createScan(self): """Create scan. :return: List of commands. """ # Parse column headers. settings = getScanSettings() col_device = [None for i in range(self.cols)] i = 0 while i < self.cols: if self.headers[i] == TableScan.WAITFOR: # Column TableScan.WAITFOR must be followed by TableScan.VALUE if i >= self.cols - 1 or self.headers[i + 1] != TableScan.VALUE: raise ValueError(TableScan.WAITFOR + " column must be followed by " + TableScan.VALUE) # .. and may then be followed by TableScan.OR_TIME if i < self.cols - 2 and self.headers[i + 2] == TableScan.OR_TIME: i += 2 else: i += 1 elif self.headers[i] in (TableScan.COMMENT): # Ignore other special columns pass else: # Parse device info col_device[i] = settings.parseDeviceSettings(self.headers[i]) i += 1 # Expand any range(start, end, step) cells expanded_rows = expandRanges(self.rows) # Assemble commands for each row in the table commands = list() log_devices = list() if self.log_always is not None: log_devices = list(self.log_always) if self.pre: commands += self.pre line = 0 for row in expanded_rows: line += 1 # Parallel commands to execute in this row parallel_commands = list() # Handle all columns i = 0 while i < self.cols: what = self.headers[i] if len(row[i]) <= 0: pass # Empty column, nothing to do elif what in self.special: special_handler = self.special[what] value = self.__getValue(row[i]) command = special_handler(value) commands.append(command) elif what == TableScan.COMMENT: text = row[i] commands.append(Comment(text)) # TODO if self.settings.comment: # commands.append(SetCommand(self.settings.comment, text)) elif what == TableScan.WAITFOR: waitfor = row[i] value = self.__getValue(row[i + 1]) if waitfor.lower( ) != TableScan.COMPLETION and parallel_commands: # Complete accumulated parallel_commands before starting the run commands.append(Parallel(parallel_commands)) parallel_commands = list() # Optional commands to mark start of a "Wait For" if self.start: commands += self.start if waitfor.lower() == TableScan.COMPLETION: # Assert that there are any parallel commands, # because otherwise the 'WaitFor - Completion' was likely an error if not parallel_commands: raise Exception( "Line %d has no parallel commands to complete" % line) commands.append(Parallel(parallel_commands)) parallel_commands = list() elif waitfor.lower() == TableScan.SECONDS: if value: commands.append(Delay(parseSeconds(value))) else: timeout = None errhandler = None if i + 2 < self.cols and self.headers[ i + 2] == TableScan.OR_TIME: or_time = row[i + 2].strip() if len(or_time) > 0: timeout = parseSeconds(or_time) errhandler = "OnErrorContinue" cmd = SettingsBasedWait(waitfor, value, timeout=timeout, errhandler=errhandler) commands.append(cmd) if not waitfor in log_devices: log_devices.append(waitfor) if len(log_devices) > 0: commands.append(Log(log_devices)) # Optional commands to mark end of a "Wait For" if self.stop: commands += self.stop # Skip TableScan.VALUE in addition to current column, # so next two Exceptions should not happen unless there's an empty "WAIT_FOR" if i + 2 < self.cols and self.headers[ i + 2] == TableScan.OR_TIME: i = i + 2 else: i = i + 1 elif what == TableScan.VALUE: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[i], TableScan.VALUE, TableScan.WAITFOR, str(row))) elif what == TableScan.OR_TIME: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[i], TableScan.OR_TIME, TableScan.WAITFOR, str(row))) else: # 'Normal' column that sets a device device = col_device[i] value = self.__getValue(row[i]) command = SettingsBasedSet(what, value) if device.getParallel(): parallel_commands.append(command) else: commands.append(command) if not device.getName() in log_devices: log_devices.append(device.getName()) i = i + 1 # End of columns in row # Complete accumulated parallel commands if parallel_commands: commands.append(Parallel(parallel_commands)) parallel_commands = list() if self.post: # End one long run at end of table commands += self.post return commands
def createScan(self): """Create scan. :return: List of commands. """ # Parse column headers. settings = getScanSettings() col_device = [None for i in range(self.cols)] i = 0 while i < self.cols: if self.headers[i] == TableScan.WAITFOR: # Column TableScan.WAITFOR must be followed by TableScan.VALUE if i >= self.cols - 1 or self.headers[i + 1] != TableScan.VALUE: raise ValueError(TableScan.WAITFOR + " column must be followed by " + TableScan.VALUE) # .. and may then be followed by TableScan.OR_TIME if i < self.cols - 2 and self.headers[i + 2] == TableScan.OR_TIME: i += 2 else: i += 1 elif self.headers[i] in (TableScan.COMMENT): # Ignore other special columns pass else: # Parse device info col_device[i] = settings.parseDeviceSettings(self.headers[i]) i += 1 # Expand any range(start, end, step) cells expanded_rows = expandRanges(self.rows) # Assemble commands for each row in the table commands = list() log_devices = list() if self.log_always is not None: log_devices = list(self.log_always) if self.pre: commands += self.pre line = 0 for row in expanded_rows: line += 1 # Parallel commands to execute in this row parallel_commands = list() # Handle all columns i = 0 while i < self.cols: what = self.headers[i] if len(row[i]) <= 0: pass # Empty column, nothing to do elif what in self.special: special_handler = self.special[what] value = self.__getValue(row[i]) command = special_handler(value) commands.append(command) elif what == TableScan.COMMENT: text = row[i] commands.append(Comment(text)) # TODO if self.settings.comment: # commands.append(SetCommand(self.settings.comment, text)) elif what == TableScan.WAITFOR: waitfor = row[i] value = self.__getValue(row[i + 1]) if waitfor.lower() != TableScan.COMPLETION and parallel_commands: # Complete accumulated parallel_commands before starting the run commands.append(Parallel(parallel_commands)) parallel_commands = list() # Optional commands to mark start of a "Wait For" if self.start: commands += self.start if waitfor.lower() == TableScan.COMPLETION: # Assert that there are any parallel commands, # because otherwise the 'WaitFor - Completion' was likely an error if not parallel_commands: raise Exception("Line %d has no parallel commands to complete" % line) commands.append(Parallel(parallel_commands)) parallel_commands = list() elif waitfor.lower() == TableScan.SECONDS: if value: commands.append(Delay(parseSeconds(value))) else: timeout = None errhandler = None if i + 2 < self.cols and self.headers[i + 2] == TableScan.OR_TIME: or_time = row[i + 2].strip() if len(or_time) > 0: timeout = parseSeconds(or_time) errhandler = "OnErrorContinue" cmd = SettingsBasedWait(waitfor, value, timeout=timeout, errhandler=errhandler) commands.append(cmd) if not waitfor in log_devices: log_devices.append(waitfor) if len(log_devices) > 0: commands.append(Log(log_devices)) # Optional commands to mark end of a "Wait For" if self.stop: commands += self.stop # Skip TableScan.VALUE in addition to current column, # so next two Exceptions should not happen unless there's an empty "WAIT_FOR" if i + 2 < self.cols and self.headers[i + 2] == TableScan.OR_TIME: i = i + 2 else: i = i + 1 elif what == TableScan.VALUE: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[i], TableScan.VALUE, TableScan.WAITFOR, str(row)) ) elif what == TableScan.OR_TIME: raise Exception( "Line %d: Found value '%s' in '%s' column after empty '%s' column.\nRow: %s" % (line, row[i], TableScan.OR_TIME, TableScan.WAITFOR, str(row)) ) else: # 'Normal' column that sets a device device = col_device[i] value = self.__getValue(row[i]) command = SettingsBasedSet(what, value) if device.getParallel(): parallel_commands.append(command) else: commands.append(command) if not device.getName() in log_devices: log_devices.append(device.getName()) i = i + 1 # End of columns in row # Complete accumulated parallel commands if parallel_commands: commands.append(Parallel(parallel_commands)) parallel_commands = list() if self.post: # End one long run at end of table commands += self.post return commands