Exemple #1
0
 def delete_clicked():
     element = self._get_selected_element()
     if element is None:
         config.get_main_window().statusBar().showMessage(
             "Nothing to delete", config.STATUS_MSG_TIMEOUT)
     else:
         self._pipeline_model.delete(element)
Exemple #2
0
    def add_element(self, new_elem: SpikeElement) -> None:
        # Inserts new element into  pipeline in proper order

        new_elem_cls_count = self._elem_cls_count(new_elem.__class__)
        new_elem_is_singleton = self._element_policy.\
            is_cls_singleton(new_elem.__class__)
        if new_elem_is_singleton and new_elem_cls_count:
            config.get_main_window().statusBar().showMessage(
                'Only one element of this type allowed in pipeline',
                config.STATUS_MSG_TIMEOUT)
            return

        target_positions = self._element_policy.cls_order_dict
        new_elem_target_pos = target_positions[new_elem.__class__]
        new_elem_insert_pos = 0
        for pipe_elem in self._element_list:
            pipe_elem_target_pos = target_positions[pipe_elem.__class__]
            if new_elem_target_pos >= pipe_elem_target_pos:
                new_elem_insert_pos += 1
            else:
                break

        self.beginInsertRows(QtCore.QModelIndex(), new_elem_insert_pos,
                             new_elem_insert_pos)
        self._element_list.insert(new_elem_insert_pos, new_elem)
        self.endInsertRows()
Exemple #3
0
    def move_down(self, elem: SpikeElement) -> None:
        rank = self._element_policy.cls_order_dict
        row = self._element_list.index(elem)

        if row < len(self._element_list) - 1 and \
                rank[type(elem)] == rank[type(self._element_list[row + 1])]:
            self.beginMoveRows(QtCore.QModelIndex(), row + 1, row + 1,
                               QtCore.QModelIndex(), row)  # noqa: E128
            self._swap(self._element_list, row, row + 1)
            self.endMoveRows()
        else:
            config.get_main_window().statusBar().showMessage(
                "Cannot move element any lower", config.STATUS_MSG_TIMEOUT)
Exemple #4
0
def _perform_save_action() -> None:
    """Saves current pipeline of elements to a user specified JSON file

    Launches a file dialog box that allows the user to specifiy a JSON file,
    attempts to encode the element pipeline, and if successful writes out the
    decoded element pipelin in JSON format to file.

    config.cvt_elem_to_dict() does most of the hard work, by extracting class
    and parameter data from the element that allows the element to be JSON
    encoded and reinstantiated later when the filed is read back in by
    _perform_load_action().

    """
    global _pipeline_model

    # TODO: _element_list is supposed to be private - use data() instead?
    element_list = _pipeline_model._element_list

    if element_list:
        options = QtWidgets.QFileDialog.Options()
        options |= QtWidgets.QFileDialog.DontUseNativeDialog
        file_name, _filter = QtWidgets.QFileDialog.getSaveFileName(
            config.get_main_window(), caption='Save File',
            filter='JSON (*.json)', options=options)

        if file_name:
            if not file_name.lower().endswith('.json'):
                file_name = file_name + '.json'
            elem_dict_list = [config.cvt_elem_to_dict(element)
                              for element in element_list]

            with open(file_name, 'w') as json_file:
                json.dump(elem_dict_list, json_file)
Exemple #5
0
def test_get_main_window():
    """Tests function that finds reference to app's main window."""
    app = QtWidgets.QApplication(sys.argv)  # noqa: F841
    win = SpikelyMainWindow()
    found_win = config.get_main_window()

    assert win is found_win
Exemple #6
0
    def convert_value(self, type_str, value_str):
        success, cvt_value = True, None
        try:
            if value_str == 'None':
                cvt_value = None

            elif type_str in ['str', 'file', 'folder', 'file_or_folder']:
                cvt_value = value_str

            elif type_str == 'int':
                if value_str == 'inf':
                    cvt_value = float(value_str)
                else:
                    cvt_value = int(value_str)

            elif type_str == 'float':
                cvt_value = float(value_str)

            elif type_str == 'int_list':
                cvt_value = self._str_list_to_int_list(value_str)

            elif type_str == "int_or_int_list":
                try:
                    cvt_value = int(value_str)
                except ValueError:
                    cvt_value = self._str_list_to_int_list(value_str)

            elif type_str == 'int_list_list':
                # Strip outer sq brackets: '[[1,2],[3,4]]' -> '[1,2],[3,4]'
                value_str = re.sub(r'^\[|\]$', '', value_str)
                # Disambiguate list separator: '[1,2],[3,4]' -> [1,2]:[3,4]'
                value_str = re.sub(r'\] *, *\[', ':', value_str)
                # Split into int_list strings and convert into int_lists
                cvt_value = list(map(
                    self._str_list_to_int_list, value_str.split(':')))

            elif type_str == 'bool':
                if value_str.lower() in ['true', 'yes']:
                    cvt_value = True
                elif value_str.lower() in ['false', 'no']:
                    cvt_value = False
                else:
                    raise TypeError(f'{value_str} is not a valid bool type')

            elif type_str == 'dtype':
                # Conversion test will trigger exception if not well-formed
                np.dtype(value_str)
                # Save dtype as string for consumption by SpikeInterface
                cvt_value = value_str

            else:
                raise TypeError(f'{type_str} is not a Spikely supported type')

        except (TypeError, ValueError) as err:
            QtWidgets.QMessageBox.warning(
                config.get_main_window(), 'Type Conversion Error', repr(err))
            success = False

        return success, cvt_value
Exemple #7
0
    def closeEvent(self, event):
        """Overrides QMainWindow method for confirmation before exiting"""
        if self.process.state() == QtCore.QProcess.Running:
            reply = QtWidgets.QMessageBox.question(
                config.get_main_window(), 'Exiting', 'Exiting will terminate'
                ' pipeline execution.  Are you sure you want to exit?',
                QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)

            if reply == QtWidgets.QMessageBox.No:
                event.ignore()
Exemple #8
0
def _action(name, tip, slot, shortcut=None, checkable=False, checked=None):
    action = QtWidgets.QAction(name, config.get_main_window(),
                               checkable=checkable)
    action.setStatusTip(tip)
    action.triggered.connect(slot)
    if shortcut is not None:
        action.setShortcut(shortcut)
    if checkable and checked is not None:
        action.setChecked(checked)

    return action
Exemple #9
0
def _perform_file_action() -> None:

    options = QtWidgets.QFileDialog.Options()
    options |= QtWidgets.QFileDialog.DontUseNativeDialog
    file_name, _filter = QtWidgets.QFileDialog.getOpenFileName(
        config.get_main_window(),
        caption='Copy File Name to Clipboard',
        options=options)

    if file_name:
        QtWidgets.QApplication.clipboard().setText(file_name)
Exemple #10
0
def _perform_load_action() -> None:
    """Loads current pipeline with elements from a previously saved JSON file

    Launches a file dialog box that allows the user to select a previously
    saved JSON file, attempts to decode it, and if successful adds the elements
    to the current pipeline replacing any elements extant in the pipeline.

    config.cvt_dict_to_elem() does most of the hard work, and throws exceptions
    if the element is no longer installed, or is no longer compatible with the
    version saved previously.

    """
    global _pipeline_model

    options = QtWidgets.QFileDialog.Options()
    options |= QtWidgets.QFileDialog.DontUseNativeDialog
    file_name, _filter = QtWidgets.QFileDialog.getOpenFileName(
            config.get_main_window(), caption='Open File',
            filter='JSON (*.json)', options=options)

    if file_name:
        _pipeline_model.clear()
        try:
            with open(file_name, 'r') as json_file:
                elem_dict_list = json.load(json_file)

            for elem_dict in elem_dict_list:
                elem = config.cvt_dict_to_elem(elem_dict)
                _pipeline_model.add_element(elem)

        except (json.decoder.JSONDecodeError, ValueError) as e:
            QtWidgets.QMessageBox.warning(
                config.get_main_window(), 'JSON File Load Failure',
                f'Failed to load {file_name}: {str(e)}')
            _pipeline_model.clear()

        except Exception as e:
            QtWidgets.QMessageBox.warning(
                config.get_main_window(), 'JSON File Load Failure',
                f'Unspecified exception: {str(e)}')
            _pipeline_model.clear()
Exemple #11
0
    def run(self):
        # Called in response to user pressing Run button in UI
        missing_param_count = self._missing_param_count()
        if missing_param_count:
            QtWidgets.QMessageBox.warning(
                config.get_main_window(), 'Run Failure',
                f'Missing mandatory element parameters.  Missing parameter '
                f'count: {missing_param_count}')
            return

        for cls in self._element_policy.required_cls_list:
            if not self._elem_cls_count(cls):
                QtWidgets.QMessageBox.warning(
                    config.get_main_window(), 'Run Failure',
                    f'Missing required element: {cls.__name__}')
                return

        config.get_main_window().statusBar().showMessage(
            'Running pipeline', config.STATUS_MSG_TIMEOUT)

        elem_jdict_list = [
            config.cvt_elem_to_dict(element) for element in self._element_list
        ]

        elem_list_str = json.dumps(elem_jdict_list)

        # TODO: Add plumbing for shared output support
        if self.share_output:
            run_path = pkg_resources.resource_filename('spikely.pipeman',
                                                       'piperun.py')
        else:
            run_path = pkg_resources.resource_filename('spikely.pipeman',
                                                       'pipeman.py')

        run_process = QtCore.QProcess(self)
        success = run_process.startDetached('python',
                                            [f'{run_path}', elem_list_str])
        if not success:
            QtWidgets.QMessageBox.warning(
                config.get_main_window(), 'Failed to Start Python Process',
                f'Command line: python {run_path}, elem_list_str')
Exemple #12
0
def _perform_folder_action() -> None:

    options = QtWidgets.QFileDialog.Options()
    options |= QtWidgets.QFileDialog.DontUseNativeDialog
    options |= QtWidgets.QFileDialog.ShowDirsOnly
    options |= QtWidgets.QFileDialog.DontResolveSymlinks
    folder_name = QtWidgets.QFileDialog.getExistingDirectory(
        config.get_main_window(),
        caption='Copy Folder Name to Clipboard',
        options=options)

    if folder_name:
        QtWidgets.QApplication.clipboard().setText(folder_name)