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')]"
        )
예제 #3
0
    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
예제 #4
0
    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
예제 #5
0
    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