예제 #1
0
파일: demo.py 프로젝트: Meteorix/pyqtconfig
class MainWindow(QMainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PyQtConfig Demo')
        self.config = ConfigManager()

        CHOICE_A = 1
        CHOICE_B = 2
        CHOICE_C = 3
        CHOICE_D = 4

        map_dict = {
            'Choice A': CHOICE_A,
            'Choice B': CHOICE_B,
            'Choice C': CHOICE_C,
            'Choice D': CHOICE_D,
        }

        self.config.set_defaults({
            'number': 13,
            'text': 'hello',
            'active': True,
            'combo': CHOICE_C,
        })

        gd = QGridLayout()

        sb = QSpinBox()
        gd.addWidget(sb, 0, 1)
        self.config.add_handler('number', sb)

        te = QLineEdit()
        gd.addWidget(te, 1, 1)
        self.config.add_handler('text', te)

        cb = QCheckBox()
        gd.addWidget(cb, 2, 1)
        self.config.add_handler('active', cb)

        cmb = QComboBox()
        cmb.addItems(map_dict.keys())
        gd.addWidget(cmb, 3, 1)
        self.config.add_handler('combo', cmb, mapper=map_dict)

        self.current_config_output = QTextEdit()
        gd.addWidget(self.current_config_output, 0, 3, 3, 1)

        self.config.updated.connect(self.show_config)

        self.show_config()

        self.window = QWidget()
        self.window.setLayout(gd)
        self.setCentralWidget(self.window)

    def show_config(self):
        self.current_config_output.setText(str(self.config.as_dict()))
예제 #2
0
파일: demo.py 프로젝트: BYT3M3/pyqtconfig
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PyQtConfig Demo')
        self.config = ConfigManager()

        CHOICE_A = 1
        CHOICE_B = 2
        CHOICE_C = 3
        CHOICE_D = 4

        map_dict = {
            'Choice A': CHOICE_A,
            'Choice B': CHOICE_B,
            'Choice C': CHOICE_C,
            'Choice D': CHOICE_D,
        }

        self.config.set_defaults({
            'number': 13,
            'text': 'hello',
            'active': True,
            'combo': CHOICE_C,
        })

        gd = QGridLayout()

        sb = QSpinBox()
        gd.addWidget(sb, 0, 1)
        self.config.add_handler('number', sb)

        te = QLineEdit()
        gd.addWidget(te, 1, 1)
        self.config.add_handler('text', te)

        cb = QCheckBox()
        gd.addWidget(cb, 2, 1)
        self.config.add_handler('active', cb)

        cmb = QComboBox()
        cmb.addItems(map_dict.keys())
        gd.addWidget(cmb, 3, 1)
        self.config.add_handler('combo', cmb, mapper=map_dict)

        self.current_config_output = QTextEdit()
        gd.addWidget(self.current_config_output, 0, 3, 3, 1)

        self.config.updated.connect(self.show_config)

        self.show_config()

        self.window = QWidget()
        self.window.setLayout(gd)
        self.setCentralWidget(self.window)

    def show_config(self):
        self.current_config_output.setText(str(self.config.as_dict()))
예제 #3
0
파일: dictGUI.py 프로젝트: jedocs/lisa
class DictGui(QDialog):
    # class LisaConfigWindow(QMainWindow):

    def __init__(self, config_in, ncols=2):
        super(DictGui, self).__init__()

        self.setWindowTitle('Lisa Config')
        self.config = ConfigManager()
        self.ncols = ncols
        # used with other module. If it is set, lisa config is deleted
        self.reset_config = False

        CHOICE_A = "{pairwise_alpha_per_mm2: 45, return_only_object_with_seeds: true}"
        # CHOICE_A = 23

        CHOICE_B = 2
        CHOICE_C = 3
        CHOICE_D = 4

        map_dict = {
            'Graph-Cut': CHOICE_A,
            'Choice B': CHOICE_B,
            'Choice C': CHOICE_C,
            'Choice D': CHOICE_D,
        }
        config_def = {
            'working_voxelsize_mm': 2.0,
            'save_filetype': 'pklz',
            # 'manualroi': True,
            'segparams': CHOICE_A,
        }

        config_def.update(config_in)

        self.config.set_defaults(config_def)

        gd = QGridLayout()
        gd_max_i = 0
        for key, value in config_in.items():
            if type(value) is int:
                sb = QSpinBox()
                sb.setRange(-100000, 100000)
            elif type(value) is float:
                sb = QDoubleSpinBox()
            elif type(value) is str:
                sb = QLineEdit()
            elif type(value) is bool:
                sb = QCheckBox()
            else:
                logger.error("Unexpected type in config dictionary")

            row = gd_max_i / self.ncols
            col = (gd_max_i % self.ncols) * 2

            gd.addWidget(QLabel(key), row, col + 1)
            gd.addWidget(sb, row, col + 2)
            self.config.add_handler(key, sb)
            gd_max_i += 1

        # gd.addWidget(QLabel("save filetype"), 1, 1)
        # te = QLineEdit()
        # gd.addWidget(te, 1, 2)
        # self.config.add_handler('save_filetype', te)
        #
        # gd.addWidget(QLabel("segmentation parameters"), 2, 1)
        # te = QLineEdit()
        # gd.addWidget(te, 2, 2)
        # self.config.add_handler('segparams', te)

        # cb = QCheckBox()
        # gd.addWidget(cb, 2, 2)
        # self.config.add_handler('active', cb)

        # gd.addWidget(QLabel("segmentation parameters"), 3, 1)
        # cmb = QComboBox()
        # cmb.addItems(map_dict.keys())
        # gd.addWidget(cmb, 3, 2)
        # self.config.add_handler('segparams', cmb, mapper=map_dict)

        self.current_config_output = QTextEdit()
        # rid.setColumnMinimumWidth(3, logo.width()/2)
        text_col = (self.ncols * 2) + 3
        gd.setColumnMinimumWidth(text_col, 500)
        gd.addWidget(self.current_config_output, 1, text_col,
                     (gd_max_i / 2) - 1, 1)

        btn_reset_config = QPushButton("Default", self)
        btn_reset_config.clicked.connect(self.btnResetConfig)
        gd.addWidget(btn_reset_config, 0, text_col)

        btn_save_config = QPushButton("Ok", self)
        btn_save_config.clicked.connect(self.btnSaveConfig)
        gd.addWidget(btn_save_config, (gd_max_i / 2), text_col)

        self.config.updated.connect(self.show_config)

        self.show_config()

        # my line
        self.setLayout(gd)

        # self.window = QWidget()
        # self.window.setLayout(gd)
        # self.setCentralWidget(self.window)
    def add_grid_line(self, key, value):
        pass

    def get_config_as_dict(self):
        dictionary = self.config.as_dict()
        for key, value in dictionary.items():
            from PyQt4.QtCore import pyqtRemoveInputHook
            pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace() #  noqa BREAKPOINT
            if type(value) == QString:
                value = str(value)
            dictionary[key] = value

        return dictionary

    def btnResetConfig(self, event=None):
        self.reset_config = True
        self.close()

    def btnSaveConfig(self, event=None):
        self.reset_config = False
        self.close()

    def show_config(self):
        text = str(self.get_config_as_dict())
        self.current_config_output.setText(text)
예제 #4
0
class LisaConfigWindow(QDialog):
# class LisaConfigWindow(QMainWindow):

    def __init__(self, config_in, ncols=2):
        super(LisaConfigWindow, self).__init__()

        self.setWindowTitle('Lisa Config')
        self.config = ConfigManager()
        self.ncols = ncols
# used with other module. If it is set, lisa config is deleted
        self.reset_config = False

        CHOICE_A = "{pairwise_alpha_per_mm2: 45, return_only_object_with_seeds: true}"
        # CHOICE_A = 23

        CHOICE_B = 2
        CHOICE_C = 3
        CHOICE_D = 4

        map_dict = {
            'Graph-Cut': CHOICE_A,
            'Choice B': CHOICE_B,
            'Choice C': CHOICE_C,
            'Choice D': CHOICE_D,
        }
        config_def = {
            'working_voxelsize_mm': 2.0,
            'save_filetype': 'pklz',
            # 'manualroi': True,
            'segparams': CHOICE_A,
        }
        
        config_def.update(config_in)
        
        self.config.set_defaults(config_def)

        gd = QGridLayout()
        gd_max_i = 0
        for key, value in config_in.iteritems():
            if type(value) is int:
                sb = QSpinBox()
                sb.setRange(-100000, 100000)
            elif type(value) is float:
                sb = QDoubleSpinBox()
            elif type(value) is str:
                sb = QLineEdit()
            elif type(value) is bool:
                sb = QCheckBox()
            else:
                logger.error("Unexpected type in config dictionary")

            row = gd_max_i / self.ncols
            col = (gd_max_i % self.ncols) * 2

            gd.addWidget(QLabel(key),row, col +1) 
            gd.addWidget(sb, row, col + 2)
            self.config.add_handler(key, sb)
            gd_max_i += 1




        # gd.addWidget(QLabel("save filetype"), 1, 1)
        # te = QLineEdit()
        # gd.addWidget(te, 1, 2)
        # self.config.add_handler('save_filetype', te)
        #
        # gd.addWidget(QLabel("segmentation parameters"), 2, 1)
        # te = QLineEdit()
        # gd.addWidget(te, 2, 2)
        # self.config.add_handler('segparams', te)

        # cb = QCheckBox()
        # gd.addWidget(cb, 2, 2)
        # self.config.add_handler('active', cb)

        # gd.addWidget(QLabel("segmentation parameters"), 3, 1)
        # cmb = QComboBox()
        # cmb.addItems(map_dict.keys())
        # gd.addWidget(cmb, 3, 2)
        # self.config.add_handler('segparams', cmb, mapper=map_dict)

        self.current_config_output = QTextEdit()
        # rid.setColumnMinimumWidth(3, logo.width()/2)
        text_col = (self.ncols * 2) + 3
        gd.setColumnMinimumWidth(text_col, 500)
        gd.addWidget(self.current_config_output, 1, text_col, (gd_max_i/2)-1, 1)

        btn_reset_config = QPushButton("Reset and quit", self)
        btn_reset_config.clicked.connect(self.btnResetConfig)
        gd.addWidget(btn_reset_config, 0, text_col)

        btn_save_config = QPushButton("Save and quit", self)
        btn_save_config.clicked.connect(self.btnSaveConfig)
        gd.addWidget(btn_save_config, (gd_max_i / 2), text_col)

        self.config.updated.connect(self.show_config)

        self.show_config()

        # my line
        self.setLayout(gd)

        # self.window = QWidget()
        # self.window.setLayout(gd)
        # self.setCentralWidget(self.window)
    def add_grid_line(self, key, value):
        pass

    def get_config_as_dict(self):
        dictionary = self.config.as_dict()
        for key, value in dictionary.iteritems():
            from PyQt4.QtCore import pyqtRemoveInputHook
            pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace() #  noqa BREAKPOINT
            if type(value) == PyQt4.QtCore.QString:
                value = str(value)
            dictionary[key] = value

        return dictionary

    def btnResetConfig(self, event=None):
        self.reset_config = True
        self.close()

    def btnSaveConfig(self, event=None):
        self.reset_config = False
        self.close()


    def show_config(self):
        text = str(self.get_config_as_dict())
        self.current_config_output.setText(text)
예제 #5
0
class DictWidget(QtGui.QWidget):
    def __init__(self, config_in, ncols=2, captions=None, hide_keys=None,
                 horizontal=False, show_captions=True, accept_button=False,
                 config_manager=None, radiobuttons=None, dropdownboxes=None):
        """

        :param config_in:  dictionary
        :param ncols:
        :param captions:
        :param radiobuttons: {"name_of_radiobutton": [
                                 ["orig_caption_1", orig_caption_2],
                                 default_value]
                                 ]
                            }
        """
        super(DictWidget, self).__init__()
        if captions is None:
            captions = {}
        if hide_keys is None:
            hide_keys = []
        self.config_in = config_in
        self.ncols = ncols
        self.captions = captions
        self.accept_button = accept_button
        self.hide_keys = copy.copy(hide_keys)
        self.horizontal = horizontal
        self.show_captions = show_captions
        if radiobuttons is None:
            radiobuttons = {}
        self.radiobuttons = radiobuttons
        if dropdownboxes is None:
            dropdownboxes = {}
        self.dropdownboxes = dropdownboxes

        # hide also temp keys for lists and ndarrays
        # due to load default params
        self._get_tmp_composed_keys(config_in)
        self.hide_keys.extend(self._tmp_composed_keys_list)

        if config_manager is None:
            self.config = ConfigManager()
            self.config.set_defaults(config_in)
        else:
            self.config = config_manager
        self.mainLayout = QGridLayout(self)
        self.setLayout(self.mainLayout)
        self.widgets = {}
        self.grid_i = 0
        self.init_ui()

    def _get_tmp_composed_keys(self, cfg):
        """
        Get list of temporary keys for lists and ndarrays. This keys are used for reconstruction.

        vytvoří to seznam pomocných klíčů pro seznamy a ndarray
        :param cfg:
        :return:
        """
        self._tmp_composed_keys_dict = {}
        self._tmp_composed_keys_list = []
        toappend = {}
        for key, value in cfg.iteritems():
            if key in self.dropdownboxes.keys():
                continue
            if key in self.radiobuttons.keys():
                continue
            if type(value) in (list, np.ndarray):
                self._tmp_composed_keys_dict[key] = []
                array = np.asarray(value)
                key_array_i = 0
                for val in array.tolist():
                    # key_i = (key, key_array_i)
                    key_i = ComposedDictMetadata((key, key_array_i))
                    self._tmp_composed_keys_dict[key].append(key_i)
                    self._tmp_composed_keys_list.append(key_i)
                    key_array_i += 1
                    toappend[key_i] = val
        cfg.update(toappend)

    def _create_dropdownbox(self, key, value):
        # atomic_widget = QWidget()
        row, col = self.__calculate_new_grid_position()
        # layout = QBoxLayout(self.horizontal)
        atomic_widget = QComboBox()
        # atomic_widget.addItem("C")
        # atomic_widget.addItem("C++")
        values = self.dropdownboxes[key]
        # values = self.dropdownboxes[key][0]
        if value is not None and value in values:
            # vali = atomic_widget.findText(value)
            atomic_widget.findText(value)
        atomic_widget.addItems(values)
        # this does not work. I used findText()
        # atomic_widget.setCurrentIndex(vali)
        # layout.addWidget(cb)

        # atomic_widget.setLayout(layout)
        return atomic_widget

    def _create_radiobutton(self, key, value):
        atomic_widget = QWidget()
        layout = QBoxLayout(self.horizontal)
        for i, rbkey in enumerate(self.radiobuttons[key][0]):
            b1 = QRadioButton("Button1")
            if i == self.radiobuttons[key][1]:
                b1.setChecked(True)
            # b1.toggled.connect(lambda:self.btnstate(self.b1))
            layout.addWidget(b1)
        atomic_widget.setLayout(layout)
        return atomic_widget

    def init_ui(self):
        # self.widgets = {}
        # self.grid_i = 0
        grid = self.mainLayout

        for key, value in self.config_in.iteritems():

            if key in self.hide_keys:
                continue
            if key in self.captions.keys():
                caption = self.captions[key]
            else:
                caption = key

            atomic_widget = self.__get_widget_for_primitive_types(key, value)
            if atomic_widget is None:
                if type(value) in (list, np.ndarray):
                    array = np.asarray(value)
                    atomic_widget = self._create_sub_grid_from_ndarray(key, array)
                    row, col = self.__calculate_new_grid_position()
                    grid.addWidget(QLabel(caption), row, col + 1)
                    grid.addLayout(atomic_widget, row, col + 2)
                    continue
                else:
                    logger.error("Unexpected type in config dictionary")

                continue

            # import ipdb; ipdb.set_trace()
            row, col = self.__calculate_new_grid_position()
            grid.addWidget(QLabel(caption), row, col + 1)
            grid.addWidget(atomic_widget, row, col + 2)

        # gd.setColumnMinimumWidth(text_col, 500)

        if self.accept_button:
            btn_accept = QPushButton("Accept", self)
            btn_accept.clicked.connect(self.btn_accept)
            text_col = (self.ncols * 2) + 3
            grid.addWidget(btn_accept, (self.grid_i / 2), text_col)

        self.config.updated.connect(self.on_config_update)

    # def __add_line
    def __get_widget_for_primitive_types(self, key, value):

        """
        return right widget and connect the value with config_manager
        :param key:
        :param value:
        :return:
        """

        if key in self.dropdownboxes.keys():
            atomic_widget = self._create_dropdownbox(key,value)
            self.config.add_handler(key, atomic_widget)
        elif key in self.radiobuttons.keys():
            atomic_widget = self._create_radiobutton(key,value)
            self.config.add_handler(key, atomic_widget)
        elif type(value) is int:
            atomic_widget = QSpinBox()
            atomic_widget.setRange(-100000, 100000)
            self.config.add_handler(key, atomic_widget)
        elif type(value) is float:
            atomic_widget = QDoubleSpinBox()
            atomic_widget.setDecimals(6)
            atomic_widget.setMaximum(1000000000)
            self.config.add_handler(key, atomic_widget)
        elif type(value) is str:
            atomic_widget = QLineEdit()
            self.config.add_handler(key, atomic_widget)
        elif type(value) is bool:
            atomic_widget = QCheckBox()
            self.config.add_handler(key, atomic_widget)
        else:
            return None
        return atomic_widget

    def _create_sub_grid_from_ndarray(self, key, ndarray):
        hgrid = QGridLayout(self)
        hgrid_i = 0
        for val in ndarray.tolist():
            # key_i = key + str(hgrid_i)
            key_i = (key, hgrid_i)
            atomic_widget = self.__get_widget_for_primitive_types(key_i, val)

            hgrid.addWidget(atomic_widget, 0, hgrid_i)
            hgrid_i += 1

        return hgrid

    def __calculate_new_grid_position(self):
        row = self.grid_i / self.ncols
        col = (self.grid_i % self.ncols) * 2
        self.grid_i += 1
        if self.horizontal:
            return col, row
        return row, col

    def btn_accept(self):
        print ("btn_accept: " + str(self.config_as_dict()))

    def on_config_update(self):
        pass

    def config_as_dict(self):
        def _primitive_type(value):
            if type(value) == PyQt4.QtCore.QString:
                value = str(value)
            return value

        dictionary = self.config.as_dict()
        dictionary = copy.copy(dictionary)
        for key, value in dictionary.iteritems():
            from PyQt4.QtCore import pyqtRemoveInputHook
            #pyqtRemoveInputHook()
            # import ipdb; ipdb.set_trace() #  noqa BREAKPOINT
            # if type(key) == tuple:
            if type(key) == ComposedDictMetadata:

                dict_key, value_index = key
                dict_key = (dict_key)
                # if dict_key not in dictionary.keys():
                #     dictionary[dict_key] = {}

                dictionary[dict_key][value_index] = _primitive_type(value)

            else:
                dictionary[key] = _primitive_type(value)

        for key in dictionary.keys():
            # if type(key) == tuple:
            if type(key) == ComposedDictMetadata:
                dictionary.pop(key)

        # for key, value in dictionary.iteritems():
        #     if type(key) == tuple:
        #         dictionary

        return dictionary
예제 #6
0
파일: base.py 프로젝트: pchj/nmrbrew
class ToolBase(QObject):
    '''
    Base tool definition for inclusion in the UI. Define specific config settings;
    attach a panel widget for configuration.
    '''

    is_manual_runnable = True

    is_auto_runnable = True
    is_auto_rerunnable = True
    is_disableable = True

    progress = pyqtSignal(float)
    status = pyqtSignal(str)

    config_panel_size = 250
    view_widget = 'SpectraViewer'

    def __init__(self, parent, *args, **kwargs):
        super(ToolBase, self).__init__(parent, *args, **kwargs)

        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())
        self.config.set_defaults({
            'is_active': True,
            'auto_run_on_config_change': True
        })

        self.config.updated.connect(self.auto_run_on_config_change)

        self.buttonBar = QWidget()

        self.configPanels = QWidget()
        self.configLayout = QVBoxLayout()
        self.configLayout.setContentsMargins(0, 0, 0, 0)

        self.configPanels.setLayout(self.configLayout)

        self._previous_config_backup_ = {}

        self._worker_thread_ = None
        self._worker_thread_lock_ = False

        self.data = {
            'spc': None,
        }

        self.current_status = 'ready'
        self.current_progress = 0

        self.progress.connect(self.progress_callback)
        self.status.connect(self.status_callback)

    def addConfigPanel(self, panel):
        self.configLayout.addWidget(panel(self))

    def addButtonBar(self, buttons):
        '''
        Create a button bar

        Supplied with a list of QPushButton objects (already created using helper stubs; see below)

        :param buttons:
        :return:
        '''

        btnlayout = QHBoxLayout()
        btnlayout.addSpacerItem(
            QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))
        for btn in buttons:
            btnlayout.addWidget(btn)

        self.configLayout.addLayout(btnlayout)
        btnlayout.addSpacerItem(
            QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))

    def run_manual(self):
        pass

    def disable(self):
        self.status.emit('inactive')
        self.config.set('is_active', False)
        self.item.setFlags(Qt.NoItemFlags)

    def reset(self):
        self.config.set_many(self.config.defaults)

    def undo(self):
        self.config.set_many(self._config_backup_)

    def deftaultButtons(self):

        buttons = []

        if self.is_disableable:
            disable = QPushButton(
                QIcon(os.path.join(utils.scriptdir, 'icons', 'cross.png')),
                'Disable')
            disable.setToolTip('Disable this tool')
            disable.pressed.connect(self.disable)
            buttons.append(disable)

        reset = QPushButton(
            QIcon(
                os.path.join(utils.scriptdir, 'icons',
                             'arrow-turn-180-left.png')), 'Reset to defaults')
        reset.setToolTip('Reset to defaults')
        reset.pressed.connect(self.reset)
        buttons.append(reset)

        undo = QPushButton(
            QIcon(
                os.path.join(utils.scriptdir, 'icons',
                             'arrow-turn-180-left.png')), 'Undo')
        undo.setToolTip('Undo recent changes')
        undo.pressed.connect(self.undo)
        buttons.append(undo)

        if self.is_auto_runnable:
            auto = QPushButton(
                QIcon(os.path.join(utils.scriptdir, 'icons', 'lightning.png')),
                'Auto')
            auto.setToolTip('Auto-update spectra when settings change')
            auto.setCheckable(True)
            auto.pressed.connect(self.run_manual)
            self.config.add_handler('auto_run_on_config_change', auto)
            buttons.append(auto)

        if self.is_manual_runnable:
            apply = QPushButton(
                QIcon(os.path.join(utils.scriptdir, 'icons', 'play.png')),
                'Apply')
            apply.setToolTip('Apply current settings to spectra')
            apply.pressed.connect(self.run_manual)
            buttons.append(apply)

        return buttons

    def enable(self):
        if self.current_status == 'inactive':
            self.status.emit('ready')
            self.item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)

        self.config.set('is_active', True)

    def activate(self):
        self.parent().current_tool = self
        self.enable()

        self._config_backup_ = self.config.as_dict()

        self._refresh_plot_timer_ = QTimer.singleShot(0, self.plot)

        self.parent().viewStack.setCurrentWidget(self.parent().spectraViewer)

        self.parent().configstack.setCurrentWidget(self.configPanels)
        self.parent().configstack.setMaximumHeight(self.config_panel_size)

    def set_active(self, active):
        self.config.set('is_active', active)

    def get_previous_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n - 1::-1]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None

    def get_previous_spc(self):
        t = self.get_previous_tool()
        if t:
            return t.data['spc']
        else:
            return None

    def plot(self, **kwargs):
        if 'spc' in self.data:
            self.parent().spectraViewer.plot(self.data['spc'], **kwargs)

    def get_plotitem(self):
        return self.parent().spectraViewer.spectraViewer.plotItem

    def auto_run_on_config_change(self):
        pass
        #if self.is_auto_runnable and self.config.get('is_active') and self.config.get('auto_run_on_config_change'):
        #    self.run_manual()

    def run(self, fn):
        '''
        Run the target function, passing in the current spectra, and config settings (as dict)
        :param fn:
        :return:
        '''
        if self._worker_thread_lock_:
            return False  # Can't run

        self.progress.emit(0)
        self.status.emit('active')

        spc = self.get_previous_spc()

        self._worker_thread_lock_ = True

        print(self.config.as_dict())
        self._worker_thread_ = Worker(fn=fn,
                                      **{
                                          'spc': deepcopy(spc),
                                          'config': self.config.as_dict(),
                                          'progress_callback':
                                          self.progress.emit,
                                      })

        self._worker_thread_.signals.finished.connect(self.finished)
        self._worker_thread_.signals.result.connect(self.result)
        self._worker_thread_.signals.error.connect(self.error)

        self.parent().threadpool.start(self._worker_thread_)

    def error(self, error):
        self.progress.emit(1.0)
        self.status.emit('error')
        logging.error(error)
        self._worker_thread_lock_ = False

    def result(self, result):
        self.progress.emit(1)
        self.status.emit('complete')

        # Apply post-processing
        if 'spc' in result:
            result['spc'] = self.post_process_spc(result['spc'])

        self.data = result
        self.plot()

    def finished(self):
        # Cleanup
        self._worker_thread_lock_ = False

    def progress_callback(self, progress):
        self.current_progress = progress
        self.item.setData(Qt.UserRole + 2, progress)

    def status_callback(self, status):
        self.current_status = status
        self.item.setData(Qt.UserRole + 3, status)

    def post_process_spc(self, spc):
        '''
        Apply post-processing to the spectra before loading into the data store, e.g. for outlier
        detection, stats etc.

        :param spc:
        :return:
        '''

        # Outliers

        def identify_outliers(data, m=2):
            return abs(data - np.mean(data, axis=0)) < (m *
                                                        np.std(data, axis=0))

        # Identify outliers on a point by point basis. Count up 'outliers' and score ratio of points that are
        # outliers for each specra > 5% (make this configurable) is an outlier.
        spc.outliers = np.sum(~identify_outliers(spc.data), axis=1) / float(
            spc.data.shape[1])
        return spc
예제 #7
0
class ToolBase(QObject):
    '''
    Base tool definition for inclusion in the UI. Define specific config settings;
    attach a panel widget for configuration.
    '''

    is_manual_runnable = True
    is_auto_runnable = False
    is_auto_rerunnable = True
    is_disableable = True

    progress = pyqtSignal(float)
    status = pyqtSignal(str)
    complete = pyqtSignal()

    config_panel_size = 150
    view = None

    def __init__(self, parent, *args, **kwargs):
        super(ToolBase, self).__init__(parent, *args, **kwargs)


        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())
        self.config.set_defaults({
            'auto_run_on_config_change': True
            })
        self.current_status = 'inactive'
        self.config.updated.connect(self.auto_run_on_config_change)

        self.buttonBar = QWidget()

        self.configPanels = QWidget()
        self.configLayout = QVBoxLayout()
        self.configLayout.setContentsMargins(0,0,0,0)

        self.configPanels.setLayout(self.configLayout)

        self._previous_config_backup_ = {}

        self._worker_thread_ = None
        self._worker_thread_lock_ = False

        self.view = MplView(self.parent())

        self.setup()

        self.current_progress = 0

        self.progress.connect(self.progress_callback)
        self.status.connect(self.status_callback)


    def setup(self):
        self.data = {
            'data': None,
        }
        self.view.figure.clear()
        self.view.redraw()
        self.status.emit('inactive' if self.current_status == 'inactive' else 'ready')



    def addConfigPanel(self, panel):
        self.configLayout.addWidget( panel(self) )

    def addButtonBar(self, buttons):
        '''
        Create a button bar

        Supplied with a list of QPushButton objects (already created using helper stubs; see below)

        :param buttons:
        :return:
        '''

        btnlayout = QHBoxLayout()
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))
        for btn in buttons:
            btnlayout.addWidget(btn)

        self.configLayout.addLayout(btnlayout)
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))

    def run_manual(self):
        pass


    def disable(self):
        self.status.emit('inactive')
        self.item.setFlags(Qt.NoItemFlags)

    def reset(self):
        self.config.set_many( self.config.defaults )

    def undo(self):
        self.config.set_many(self._config_backup_)

    def defaultButtons(self):

        buttons = []

        reset = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'arrow-turn-180-left.png')), 'Reset to defaults')
        reset.setToolTip('Reset to defaults')
        reset.pressed.connect(self.reset)
        buttons.append(reset)

        apply = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'play.png')), 'Apply')
        apply.setToolTip('Apply current settings to spectra')
        apply.pressed.connect(self.run_manual)
        buttons.append(apply)

        return buttons

    def enable(self):
        if self.current_status == 'inactive':
            self.current_status = 'ready'
            self.status.emit('ready')
            self.item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)

    def activate(self):
        self.parent().current_tool = self
        self.enable()

        self._config_backup_ = self.config.as_dict()

        self._refresh_plot_timer_ = QTimer.singleShot(0, self.plot)

        if self.view:
            self.parent().viewStack.setCurrentWidget(self.view)

        self.parent().configstack.setCurrentWidget(self.configPanels)
        self.parent().configstack.setMaximumHeight(self.config_panel_size)

    def set_active(self, active):
        self.config.set('is_active', active)

    def get_previous_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n-1::-1]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None

    def get_next_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n+1:]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None



    def get_previous_data(self):
        t = self.get_previous_tool()
        if t and 'data' in t.data:
            return t.data['data']
        else:
            return None

    def plot(self, **kwargs):
        pass
        #if 'spc' in self.data:
        #    self.parent().spectraViewer.plot(self.data['spc'], **kwargs)

    def get_plotitem(self):
        return self.parent().spectraViewer.spectraViewer.plotItem

    def auto_run_on_config_change(self):
        if self.is_auto_runnable and self.current_status == 'ready' and self.config.get('auto_run_on_config_change'):
            self.run_manual()

    def run(self, fn):
        '''
        Run the target function, passing in the current spectra, and config settings (as dict)
        :param fn:
        :return:
        '''
        if self._worker_thread_lock_:
            return False # Can't run

        self.progress.emit(0)
        self.status.emit('active')

        data = self.get_previous_data()

        self._worker_thread_lock_ = True

        kwargs = {
            'config': self.config.as_dict(),
            'progress_callback': self.progress.emit,
        }
        if data:
            kwargs.update(deepcopy(data))

        # Close any open figures; ensure new axes.
        plt.close()

        self._worker_thread_ = Worker(fn = fn, **kwargs)

        self._worker_thread_.signals.finished.connect(self.finished)
        self._worker_thread_.signals.result.connect(self.result)
        self._worker_thread_.signals.error.connect(self.error)

        self.parent().threadpool.start(self._worker_thread_)


    def error(self, error):
        self.progress.emit(1.0)
        self.status.emit('error')
        logging.error(error)
        self._worker_thread_lock_ = False



    def result(self, result):

        # Apply post-processing
        if 'fig' in result and result['fig']:
            fig = result['fig']
            fig.set_size_inches(self.view.get_size_inches(fig.get_dpi()))
            fig.set_tight_layout(False)
            fig.tight_layout(pad=0.5, rect=[0.25, 0.10, 0.75, 0.90])
            self.view.figure = fig
            self.view.redraw()

        self.data = result
        self.plot()

        self.progress.emit(1)
        self.status.emit('complete')

    def finished(self):
        # Cleanup
        self._worker_thread_lock_ = False
        self.complete.emit()


    def progress_callback(self, progress):
        self.current_progress = progress
        self.item.setData(Qt.UserRole + 2, progress)

    def status_callback(self, status):
        self.current_status = status
        self.item.setData(Qt.UserRole + 3, status)
예제 #8
0
class MainWindow(QMainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('PyQtConfig Demo')
        self.vis = ConfigManager()
        #
        # CHOICE_A = 1
        # CHOICE_B = 2
        # CHOICE_C = 3
        # CHOICE_D = 4
        #
        # map_dict = {
        #     'Choice A': CHOICE_A,
        #     'Choice B': CHOICE_B,
        #     'Choice C': CHOICE_C,
        #     'Choice D': CHOICE_D,
        # }

        self.vis.set_defaults({
            'text1': 'hello1',
            'text2': 'hello2',
            'text3': 'hello3',
            'text4': 'hello4',
        })

        # self.vis.set_defaults({
        #     'number': 13,
        #     'text': 'hello',
        #     'active': True,
        #     'combo': CHOICE_C,
        # })

        gd = QGridLayout()
        #
        # sb = QSpinBox()
        # gd.addWidget(sb, 0, 1)
        # self.vis.add_handler('number', sb)
        #
        # te = QLineEdit()
        # gd.addWidget(te, 1, 1)
        # self.vis.add_handler('text', te)
        #
        # cb = QCheckBox()
        # gd.addWidget(cb, 2, 1)
        # self.vis.add_handler('active', cb)
        #
        # cmb = QComboBox()
        # cmb.addItems(map_dict.keys())
        # gd.addWidget(cmb, 3, 1)
        # self.vis.add_handler('combo', cmb, mapper=map_dict)
        #
        # self.current_config_output = QTextEdit()
        # gd.addWidget(self.current_config_output, 0, 3, 3, 1)

        i=0
        print self.vis.as_dict()
        for item in self.vis.as_dict().keys():
            te = QLineEdit()
            te.setEnabled(False)
            self.vis.add_handler(item,te)
            gd.addWidget(te,i,1)
            i=i+1

        # self.vis.updated.connect(self.show_config)

        # self.show_config()

        self.window = QWidget()
        self.window.setLayout(gd)
        self.setCentralWidget(self.window)
예제 #9
0
class SerialDialog(QDialog):

    def __init__(self, settings, parent=None):
        super().__init__(parent)
        self.settings = settings
        self.serialports = []

        # port
        self.portLabel = QLabel(self.tr("COM Port:"))
        self.portComboBox = QComboBox()
        self.portLabel.setBuddy(self.portComboBox)
        self.refresh_comports(self.portComboBox)

        # baudrate
        self.baudrateLabel = QLabel(self.tr("Baudrate:"))
        self.baudrateComboBox = QComboBox()
        self.baudrateLabel.setBuddy(self.baudrateComboBox)
        for br in BAUDRATES:
            self.baudrateComboBox.addItem(str(br), br)

        # buttons
        self.dlgbuttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal)
        self.dlgbuttons.rejected.connect(self.reject)
        self.dlgbuttons.accepted.connect(self.accept)

        # layout
        layout = QGridLayout()
        layout.addWidget(self.portLabel, 0, 0)
        layout.addWidget(self.portComboBox, 0, 1)
        layout.addWidget(self.baudrateLabel, 1, 0)
        layout.addWidget(self.baudrateComboBox, 1, 1)
        layout.addWidget(self.dlgbuttons, 2, 0, 1, 2)
        self.setLayout(layout)
        self.setWindowTitle(self.tr("Serial Settings"))

        # settings
        defaults = {
            PORT_SETTING: "",
            BAUDRATE_SETTING: "115200"
        }
        self.tmp_settings = ConfigManager()
        self.tmp_settings.set_defaults(defaults)
        self.tmp_settings.set_many(
            {key: self.settings.get(key) for key in defaults.keys()}
        )
        self.tmp_settings.add_handler(PORT_SETTING, self.portComboBox)
        self.tmp_settings.add_handler(BAUDRATE_SETTING, self.baudrateComboBox)

    def accept(self):
        d = self.tmp_settings.as_dict()
        self.settings.set_many(d)
        super().accept()

    def refresh_comports(self, combobox):
        self.serialports = serial_ports()
        for port in self.serialports:
            combobox.addItem(port)

    @property
    def port(self):
        return self.portComboBox.currentText()

    @port.setter
    def port(self, value):
        if value in self.serialports:
            self.portComboBox.setCurrentIndex(
                self.portComboBox.findText(value))
        else:
            raise ValueError("serial port '%s' not available" % value)

    @property
    def baudrate(self):
        return self.baudrateComboBox.currentData()
예제 #10
0
파일: ui.py 프로젝트: hupratt/PyQT-client
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        self.LUXEMBOURG = "LUXEMBOURG"
        self.MONACO = "MONACO"
        self.NASSAU = "NASSAU"
        self.GERMANY = "GERMANY"

        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
        self.title = "ARIS - JIRA Interface GUI"
        self.left, self.top, self.width, self.height = (0, 30, 1600, 480)
        self.config = ConfigManager()
        self.aris_config = self.open_conf_lux()
        self.apps = os.path.join(os.path.dirname(os.getcwd()),
                                 self.aris_config["apps"][0])
        self.aris_config_no_tooltips = {
            key: val[0]
            for (key, val) in self.aris_config.items()
        }
        self.aris_config_list = [(key, value[1])
                                 for key, value in self.aris_config.items()]
        self.initUI(self)
        self.statusBar().showMessage("Ready.")

        self.scrape_ARIS_widget.clicked.connect(self.scrape_ARIS)
        self.create_TC_widget.clicked.connect(self.create_TC)
        self.sync_TC_widget.clicked.connect(self.sync_TC)
        self.config.updated.connect(self.show_config)
        self.config.updated.connect(self.save_config)
        self.cmb.activated[str].connect(self.load_preconfigured_json)
        self.event_stop = threading.Event()
        QtWidgets.QShortcut("Ctrl+C", self, activated=self.end_button_func)

    def load_preconfigured_json(self, text):
        if text == "MONACO":
            self.config.config = {
                key: val[0]
                for (key, val) in self.open_conf_mco().items()
            }
            self.save_config()
            self.show_config()

        elif text == "LUXEMBOURG":
            self.config.config = {
                key: val[0]
                for (key, val) in self.open_conf_lux().items()
            }
            self.save_config()
            self.show_config()

        elif text == "NASSAU":
            self.config.config = {
                key: val[0]
                for (key, val) in self.open_conf_nas().items()
            }
            self.save_config()
            self.show_config()

        elif text == "GERMANY":
            self.config.config = {
                key: val[0]
                for (key, val) in self.open_conf_ger().items()
            }
            self.save_config()
            self.show_config()

    def scrape_ARIS(self) -> None:
        self.would_like_to_clear_everything_scrape()
        if self.config.config["would_like_to_clear_everything_scrape"] is False:
            self.would_like_to_delete_all_xls_files_from_temp_and_download()
            self.would_like_delete_mapping_file()
            self.would_like_delete_pickle()
            self.would_like_to_skip_url_retrieval()
        self.save_config()
        # Instantiate and feed the progress bar to the scraper instance to get real time data
        self.statusBar().showMessage(
            "Program paused, please refer to the console")
        runnable = scrape_aris.Scrape_ARIS(self.progressBar, self.statusBar())
        # Execute
        QtCore.QThreadPool.globalInstance().start(runnable)

    def sync_TC(self) -> None:
        # Instantiate and feed the progress bar to the scraper instance to get real time data
        runnable = sync.SyncJIRA(self.progressBar, self.statusBar())
        # Execute
        QtCore.QThreadPool.globalInstance().start(runnable)

    def create_TC(self) -> None:
        # notifications
        self.would_like_to_clear_everything_create()
        if self.config.config["would_like_to_clear_everything_create"] is False:
            self.would_like_delete_json_dump_file()
            self.would_like_delete_xlsx_files()
        self.save_config()

        # Instantiate and feed the progress bar to the creator instance to get real time data
        self.statusBar().showMessage(
            "Program paused, please refer to the console")
        runnable = create_tcs.CreateTCS(self.progressBar, self.statusBar())
        # Execute
        QtCore.QThreadPool.globalInstance().start(runnable)

    @QtCore.pyqtSlot()
    def save_config(self) -> None:
        """
        Once edited, the config file is stored in a yml file that will be used by the apps
        """
        with open("generated_config_aris.yml", "w") as file:
            yaml.dump(self.config.config, file)

    @QtCore.pyqtSlot()
    def end_button_func(self):
        self.event_stop.set()

    def show_config(self) -> None:
        self.current_config_output.setText(str(self.config.as_dict()))

    def open_conf_lux(self) -> Dict[str, Tuple[str, str]]:
        """
        load LUX default parameters
        """
        return {
            "combo":
            (self.LUXEMBOURG,
             "Choose a configuration pre-set or manually configure it through the input boxes below"
             ),
            "FirefoxBinary":
            ("FirefoxPortableESR\\App\\Firefox64\\firefox.exe",
             "firefox binaries location"),
            "Geckodriver_binary":
            ("FirefoxPortableESR\\geckodriver\\geckodriver.exe",
             "firefox driver location"),
            "search_value": ("lux",
                             "search term that you will search for on ARIS"),
            "log_name": ("aris lux.log",
                         "log name of all scripts in this app"),
            "mapping_file_name":
            ("mapping -lux.xlsx",
             "db that holds the 1 to 1 relationship between ARIS id and JIRA id"
             ),
            "target": ("https://jira-uat4.com/",
                       "url for ticket creation and sync"),
            "config_path":
            ("C:\\Users\\u46022\\Documents",
             "path that holds a configuration.py file that holds sensitive credentials"
             ),
            "master":
            ("ARIS",
             "master path that holds all of the downloads and the mapping file"
             ),
            "apps":
            ("ARIS_apps",
             "master path that holds all of the scripts logs, intermediary pickles as well as consolidated xls and csv files"
             ),
            "json_dump_file":
            ("data lux.json",
             "Pickle that holds all of the consolidated data. This is an important input for the sync script"
             ),
            "reporting": ("reporting", "path to reporting folder"),
            "process_url": ("http://srp07000wn.com/#default/item/",
                            "specific ARIS url to consult a process"),
            "search_url": ("http://srp07000wn.com/#default/search",
                           "ARIS url to perform a search"),
            "pickle_file": ("liste -lux.txt",
                            "pickle that holds all the urls we should visit"),
            "download_folder":
            ("download lux",
             "download master folder that holds the renamed processes"),
            "temp_folder":
            ("temp",
             "download master folder that holds the soon to be renamed processes"
             ),
            "download_folder":
            ("download lux",
             "download master folder that holds the renamed processes"),
            "test_path":
            ("/Testing/LUX_processes",
             "specific xray field that creates a tree for the test storage"),
            "JIRA_project":
            ("T2L", "which jria project should the ticket be created in?"),
            "consolidated_file_name":
            ("Consolidated_lux",
             "file name of the consolidated csv and xlsx ouput"),
        }

    def open_conf_mco(self) -> Dict[str, Tuple[str, str]]:
        """
        load MCO default parameters
        """
        return {
            "combo":
            (self.MONACO,
             "Choose a configuration pre-set or manually configure it through the input boxes below"
             ),
            "FirefoxBinary":
            ("FirefoxPortableESR\\App\\Firefox64\\firefox.exe",
             "firefox binaries location"),
            "Geckodriver_binary":
            ("FirefoxPortableESR\\geckodriver\\geckodriver.exe",
             "firefox driver location"),
            "search_value": ("mco",
                             "search term that you will search for on ARIS"),
            "log_name": ("aris mco.log",
                         "log name of all scripts in this app"),
            "mapping_file_name":
            ("mapping -mco.xlsx",
             "db that holds the 1 to 1 relationship between ARIS id and JIRA id"
             ),
            "target": ("https://jira-uat4.com/",
                       "url for ticket creation and sync"),
            "config_path":
            ("C:\\Users\\u46022\\Documents",
             "path that holds a configuration.py file that holds sensitive credentials"
             ),
            "master":
            ("ARIS",
             "master path that holds all of the downloads and the mapping file"
             ),
            "apps":
            ("ARIS_apps",
             "master path that holds all of the scripts logs, intermediary pickles as well as consolidated xls and csv files"
             ),
            "json_dump_file":
            ("data mco.json",
             "Pickle that holds all of the consolidated data. This is an important input for the sync script"
             ),
            "reporting": ("reporting", "path to reporting folder"),
            "process_url": ("http://srp07000wn.com/#default/item/",
                            "specific ARIS url to consult a process"),
            "search_url": ("http://srp07000wn.com/#default/search",
                           "ARIS url to perform a search"),
            "pickle_file": ("liste -mco.txt",
                            "pickle that holds all the urls we should visit"),
            "download_folder":
            ("download mco",
             "download master folder that holds the renamed processes"),
            "temp_folder":
            ("temp",
             "download master folder that holds the soon to be renamed processes"
             ),
            "download_folder":
            ("download mco",
             "download master folder that holds the renamed processes"),
            "test_path":
            ("/Testing/MCO_processes",
             "specific xray field that creates a tree for the test storage"),
            "JIRA_project":
            ("T2L", "which jria project should the ticket be created in?"),
            "consolidated_file_name":
            ("Consolidated_mco",
             "file name of the consolidated csv and xlsx ouput"),
        }

    def open_conf_nas(self) -> Dict[str, Tuple[str, str]]:
        """
        load NASSAU default parameters
        """
        return {
            "combo":
            (self.NASSAU,
             "Choose a configuration pre-set or manually configure it through the input boxes below"
             ),
            "FirefoxBinary":
            ("FirefoxPortableESR\\App\\Firefox64\\firefox.exe",
             "firefox binaries location"),
            "Geckodriver_binary":
            ("FirefoxPortableESR\\geckodriver\\geckodriver.exe",
             "firefox driver location"),
            "search_value": ("nas",
                             "search term that you will search for on ARIS"),
            "log_name": ("aris nas.log",
                         "log name of all scripts in this app"),
            "mapping_file_name":
            ("mapping -nas.xlsx",
             "db that holds the 1 to 1 relationship between ARIS id and JIRA id"
             ),
            "target": ("https://jira-uat4.com/",
                       "url for ticket creation and sync"),
            "config_path":
            ("C:\\Users\\u46022\\Documents",
             "path that holds a configuration.py file that holds sensitive credentials"
             ),
            "master":
            ("ARIS",
             "master path that holds all of the downloads and the mapping file"
             ),
            "apps":
            ("ARIS_apps",
             "master path that holds all of the scripts logs, intermediary pickles as well as consolidated xls and csv files"
             ),
            "json_dump_file":
            ("data nas.json",
             "Pickle that holds all of the consolidated data. This is an important input for the sync script"
             ),
            "reporting": ("reporting", "path to reporting folder"),
            "process_url": ("http://srp07000wn.com/#default/item/",
                            "specific ARIS url to consult a process"),
            "search_url": ("http://srp07000wn.com/#default/search",
                           "ARIS url to perform a search"),
            "pickle_file": ("liste -nas.txt",
                            "pickle that holds all the urls we should visit"),
            "download_folder":
            ("download nas",
             "download master folder that holds the renamed processes"),
            "temp_folder":
            ("temp",
             "download master folder that holds the soon to be renamed processes"
             ),
            "download_folder":
            ("download nas",
             "download master folder that holds the renamed processes"),
            "test_path":
            ("/Testing/NAS_processes",
             "specific xray field that creates a tree for the test storage"),
            "JIRA_project":
            ("T2L", "which jria project should the ticket be created in?"),
            "consolidated_file_name":
            ("Consolidated_nas",
             "file name of the consolidated csv and xlsx ouput"),
        }

    def open_conf_ger(self) -> Dict[str, Tuple[str, str]]:
        """
        load GERMANY default parameters
        """
        return {
            "combo":
            (self.GERMANY,
             "Choose a configuration pre-set or manually configure it through the input boxes below"
             ),
            "FirefoxBinary":
            ("FirefoxPortableESR\\App\\Firefox64\\firefox.exe",
             "firefox binaries location"),
            "Geckodriver_binary":
            ("FirefoxPortableESR\\geckodriver\\geckodriver.exe",
             "firefox driver location"),
            "search_value": ("ger",
                             "search term that you will search for on ARIS"),
            "log_name": ("aris ger.log",
                         "log name of all scripts in this app"),
            "mapping_file_name":
            ("mapping -ger.xlsx",
             "db that holds the 1 to 1 relationship between ARIS id and JIRA id"
             ),
            "target": ("https://jira-uat4.com/",
                       "url for ticket creation and sync"),
            "config_path":
            ("C:\\Users\\u46022\\Documents",
             "path that holds a configuration.py file that holds sensitive credentials"
             ),
            "master":
            ("ARIS",
             "master path that holds all of the downloads and the mapping file"
             ),
            "apps":
            ("ARIS_apps",
             "master path that holds all of the scripts logs, intermediary pickles as well as consolidated xls and csv files"
             ),
            "json_dump_file":
            ("data ger.json",
             "Pickle that holds all of the consolidated data. This is an important input for the sync script"
             ),
            "reporting": ("reporting", "path to reporting folder"),
            "process_url": ("http://srp07000wn.com/#default/item/",
                            "specific ARIS url to consult a process"),
            "search_url": ("http://srp07000wn.com/#default/search",
                           "ARIS url to perform a search"),
            "pickle_file": ("liste -ger.txt",
                            "pickle that holds all the urls we should visit"),
            "download_folder":
            ("download ger",
             "download master folder that holds the renamed processes"),
            "temp_folder":
            ("temp",
             "download master folder that holds the soon to be renamed processes"
             ),
            "download_folder":
            ("download ger",
             "download master folder that holds the renamed processes"),
            "test_path":
            ("/Testing/GER_processes",
             "specific xray field that creates a tree for the test storage"),
            "JIRA_project":
            ("T2L", "which jria project should the ticket be created in?"),
            "consolidated_file_name":
            ("Consolidated_ger",
             "file name of the consolidated csv and xlsx ouput"),
        }

    def would_like_delete_pickle(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title, "Would you like to delete the pickle_file?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["delete_pickle"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["delete_pickle"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_to_skip_url_retrieval(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would you like to skip url retrieval and jump straight into ARIS download?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["skip_url_retrieval"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["skip_url_retrieval"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_to_delete_all_xls_files_from_temp_and_download(
            self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would like to delete all xls files from temp and download?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config[
                "delete_all_xls_files_from_temp_and_download"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config[
                "delete_all_xls_files_from_temp_and_download"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_delete_mapping_file(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title, "Would you like to delete the mapping_file?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["delete_mapping_file"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["delete_mapping_file"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_delete_json_dump_file(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would you like to delete the json database file?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["delete_json_dump_file"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["delete_json_dump_file"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_delete_xlsx_files(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would like to delete all xlsx files from the download folder?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config[
                "delete_all_xlsx_files_from_temp_and_download"] = True
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config[
                "delete_all_xlsx_files_from_temp_and_download"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_to_clear_everything_scrape(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would you like to clear everything and start a fresh scrape?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["would_like_to_clear_everything_scrape"] = True
            self.config.config["delete_mapping_file"] = False
            self.config.config[
                "delete_all_xls_files_from_temp_and_download"] = False
            self.config.config["skip_url_retrieval"] = False
            self.config.config["delete_pickle"] = False
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["would_like_to_clear_everything_scrape"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()

    def would_like_to_clear_everything_create(self) -> None:
        assert isinstance(self.config.config, dict)
        buttonReply = QtWidgets.QMessageBox.question(
            self, self.title,
            "Would you like to clear everything and start a fresh test case creation?",
            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
            | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
        if buttonReply == QtWidgets.QMessageBox.Yes:
            self.config.config["would_like_to_clear_everything_create"] = True
            self.config.config[
                "delete_all_xlsx_files_from_temp_and_download"] = False
            self.config.config["delete_json_dump_file"] = False
        elif buttonReply == QtWidgets.QMessageBox.No:
            self.config.config["would_like_to_clear_everything_create"] = False
        elif buttonReply == QtWidgets.QMessageBox.Cancel:
            sys.exit()
예제 #11
0
파일: base.py 프로젝트: mfitzp/nmrbrew
class ToolBase(QObject):
    '''
    Base tool definition for inclusion in the UI. Define specific config settings;
    attach a panel widget for configuration.
    '''

    is_manual_runnable = True

    is_auto_runnable = True
    is_auto_rerunnable = True
    is_disableable = True

    progress = pyqtSignal(float)
    status = pyqtSignal(str)

    config_panel_size = 250
    view_widget = 'SpectraViewer'

    def __init__(self, parent, *args, **kwargs):
        super(ToolBase, self).__init__(parent, *args, **kwargs)

        self.config = ConfigManager()
        self.config.hooks.update(custom_pyqtconfig_hooks.items())
        self.config.set_defaults({
            'is_active': True,
            'auto_run_on_config_change': True
            })

        self.config.updated.connect(self.auto_run_on_config_change)

        self.buttonBar = QWidget()

        self.configPanels = QWidget()
        self.configLayout = QVBoxLayout()
        self.configLayout.setContentsMargins(0,0,0,0)

        self.configPanels.setLayout(self.configLayout)

        self._previous_config_backup_ = {}

        self._worker_thread_ = None
        self._worker_thread_lock_ = False

        self.data = {
            'spc': None,

        }

        self.current_status = 'ready'
        self.current_progress = 0

        self.progress.connect(self.progress_callback)
        self.status.connect(self.status_callback)

    def addConfigPanel(self, panel):
        self.configLayout.addWidget( panel(self) )

    def addButtonBar(self, buttons):
        '''
        Create a button bar

        Supplied with a list of QPushButton objects (already created using helper stubs; see below)

        :param buttons:
        :return:
        '''

        btnlayout = QHBoxLayout()
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))
        for btn in buttons:
            btnlayout.addWidget(btn)

        self.configLayout.addLayout(btnlayout)
        btnlayout.addSpacerItem(QSpacerItem(250, 1, QSizePolicy.Maximum, QSizePolicy.Maximum))

    def run_manual(self):
        pass


    def disable(self):
        self.status.emit('inactive')
        self.config.set('is_active', False)
        self.item.setFlags(Qt.NoItemFlags)

    def reset(self):
        self.config.set_many( self.config.defaults )

    def undo(self):
        self.config.set_many(self._config_backup_)

    def deftaultButtons(self):

        buttons = []

        if self.is_disableable:
            disable = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'cross.png')), 'Disable')
            disable.setToolTip('Disable this tool')
            disable.pressed.connect(self.disable)
            buttons.append(disable)

        reset = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'arrow-turn-180-left.png')), 'Reset to defaults')
        reset.setToolTip('Reset to defaults')
        reset.pressed.connect(self.reset)
        buttons.append(reset)

        undo = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'arrow-turn-180-left.png')), 'Undo')
        undo.setToolTip('Undo recent changes')
        undo.pressed.connect(self.undo)
        buttons.append(undo)

        if self.is_auto_runnable:
            auto = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'lightning.png')), 'Auto')
            auto.setToolTip('Auto-update spectra when settings change')
            auto.setCheckable(True)
            auto.pressed.connect(self.run_manual)
            self.config.add_handler('auto_run_on_config_change', auto)
            buttons.append(auto)

        if self.is_manual_runnable:
            apply = QPushButton(QIcon(os.path.join(utils.scriptdir, 'icons', 'play.png')), 'Apply')
            apply.setToolTip('Apply current settings to spectra')
            apply.pressed.connect(self.run_manual)
            buttons.append(apply)

        return buttons

    def enable(self):
        if self.current_status == 'inactive':
            self.status.emit('ready')
            self.item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)

        self.config.set('is_active', True)


    def activate(self):
        self.parent().current_tool = self
        self.enable()

        self._config_backup_ = self.config.as_dict()

        self._refresh_plot_timer_ = QTimer.singleShot(0, self.plot)

        self.parent().viewStack.setCurrentWidget(self.parent().spectraViewer)

        self.parent().configstack.setCurrentWidget(self.configPanels)
        self.parent().configstack.setMaximumHeight(self.config_panel_size)

    def set_active(self, active):
        self.config.set('is_active', active)

    def get_previous_tool(self):
        # Get the previous ACTIVE tool in the tool table
        n = self.parent().tools.index(self)
        for tool in self.parent().tools[n-1::-1]:
            if tool.current_status != 'inactive':
                return tool

        else:
            return None


    def get_previous_spc(self):
        t = self.get_previous_tool()
        if t:
            return t.data['spc']
        else:
            return None

    def plot(self, **kwargs):
        if 'spc' in self.data:
            self.parent().spectraViewer.plot(self.data['spc'], **kwargs)

    def get_plotitem(self):
        return self.parent().spectraViewer.spectraViewer.plotItem

    def auto_run_on_config_change(self):
        pass
        #if self.is_auto_runnable and self.config.get('is_active') and self.config.get('auto_run_on_config_change'):
        #    self.run_manual()

    def run(self, fn):
        '''
        Run the target function, passing in the current spectra, and config settings (as dict)
        :param fn:
        :return:
        '''
        if self._worker_thread_lock_:
            return False # Can't run

        self.progress.emit(0)
        self.status.emit('active')

        spc = self.get_previous_spc()

        self._worker_thread_lock_ = True

        print(self.config.as_dict())
        self._worker_thread_ = Worker(fn = fn, **{
            'spc': deepcopy(spc),
            'config': self.config.as_dict(),
            'progress_callback': self.progress.emit,
        })

        self._worker_thread_.signals.finished.connect(self.finished)
        self._worker_thread_.signals.result.connect(self.result)
        self._worker_thread_.signals.error.connect(self.error)

        self.parent().threadpool.start(self._worker_thread_)


    def error(self, error):
        self.progress.emit(1.0)
        self.status.emit('error')
        logging.error(error)
        self._worker_thread_lock_ = False

    def result(self, result):
        self.progress.emit(1)
        self.status.emit('complete')

        # Apply post-processing
        if 'spc' in result:
            result['spc'] = self.post_process_spc(result['spc'])

        self.data = result
        self.plot()

    def finished(self):
        # Cleanup
        self._worker_thread_lock_ = False


    def progress_callback(self, progress):
        self.current_progress = progress
        self.item.setData(Qt.UserRole + 2, progress)

    def status_callback(self, status):
        self.current_status = status
        self.item.setData(Qt.UserRole + 3, status)

    def post_process_spc(self, spc):
        '''
        Apply post-processing to the spectra before loading into the data store, e.g. for outlier
        detection, stats etc.

        :param spc:
        :return:
        '''

        # Outliers

        def identify_outliers(data, m=2):
            return abs(data - np.mean(data, axis=0)) < (m * np.std(data,axis=0))

        # Identify outliers on a point by point basis. Count up 'outliers' and score ratio of points that are
        # outliers for each specra > 5% (make this configurable) is an outlier.
        spc.outliers = np.sum( ~identify_outliers(spc.data), axis=1 ) / float(spc.data.shape[1])
        return spc