Beispiel #1
0
    def __init__(
        self,
        f_tee: Optional[tuple] = None,
        f_mock: Optional[Any] = None,
    ) -> None:
        log.debug('creating core')

        fname_precomputed_preorders: Optional[str]
        try:
            fname_precomputed_preorders = platform_specific.get_embedded_file_path(
                'preorders-7.bin')
        except platform_specific.FileNotFound:
            fname_precomputed_preorders = None

        cmdline = [
            platform_specific.get_embedded_file_path(
                'prest-core.exe',  # deployment Windows
                'prest-core',  # deployment elsewhere (?)
                'core/target/release/prest-core.exe',  # CI Windows
                'core/target/release/prest-core',  # CI elsewhere
            )
        ]
        if fname_precomputed_preorders:
            cmdline += ['--precomputed-preorders', fname_precomputed_preorders]

        try:
            self.core = subprocess.Popen(
                cmdline,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )

            self.stdin: FileOut
            self.stdout: FileIn

            if f_tee:
                f_in, f_out = f_tee
                self.stdin = typing.cast(FileOut, Tee(self.core.stdin, f_in))
                self.stdout = typing.cast(FileIn, Tee(self.core.stdout, f_out))
            else:
                self.stdin = typing.cast(FileOut, self.core.stdin)

                if f_mock:
                    self.stdout = typing.cast(FileIn, f_mock)
                else:
                    self.stdout = typing.cast(FileIn, self.core.stdout)

            self.stderr: FileIn = typing.cast(FileIn, self.core.stderr)
        except OSError:
            raise CoreError('could not run core')

        self.stderr_reader = StreamReader(self.stderr)
        self.stderr_reader.start()

        log.debug('the core is running')
Beispiel #2
0
        def __init__(self, ds: 'BudgetaryConsistency') -> None:
            QDialog.__init__(self)
            self.setupUi(self)

            help_icon = QIcon(
                platform_specific.get_embedded_file_path(
                    'images/qm-16.png',  # deploy
                    'gui/images/qm-16.png',  # devel
                ))
            F = util.tree_model.Field

            self.ds = ds
            self.model = util.tree_model.TreeModel(
                RootNode(ds.subjects),
                headers=[
                    'Subject',
                    'Cycle length',
                    F(
                        'GARP', help_icon,
                        'consistency/cons_budgetary.html#generalized-axiom-of-revealed-preference-garp'
                    ),
                    F(
                        'SARP', help_icon,
                        'consistency/cons_budgetary.html#strong-axiom-of-revealed-preference-sarp'
                    ),
                    F(
                        'WARP (strict)', help_icon,
                        'consistency/cons_budgetary.html#weak-axiom-of-revealed-preference-warp'
                    ),
                    F(
                        'WARP (non-strict)', help_icon,
                        'consistency/cons_budgetary.html#weak-axiom-of-revealed-preference-warp'
                    ),
                    F('HM (GARP)', help_icon,
                      'consistency/cons_budgetary.html#houtman-maks-index-hm'),
                    F('HM (SARP)', help_icon,
                      'consistency/cons_budgetary.html#houtman-maks-index-hm'),
                    F('HM (WARP strict)', help_icon,
                      'consistency/cons_budgetary.html#houtman-maks-index-hm'),
                    F('HM (WARP non-strict)', help_icon,
                      'consistency/cons_budgetary.html#houtman-maks-index-hm'),
                ],
            )

            self.twRows.setModel(self.model)

            hdr = self.twRows.header()
            hdr.setSectionResizeMode(QHeaderView.ResizeToContents)
            hdr.setStretchLastSection(False)

            hdr.setSectionsClickable(True)
            hdr.sectionClicked.connect(self.header_clicked)
Beispiel #3
0
    def __init__(self) -> None:
        QDialog.__init__(self)
        self.setupUi(self)

        self.lblPrest.setPixmap(
            QPixmap(
                platform_specific.get_embedded_file_path(
                    'images/prest-logo.png',  # deployment
                    'gui/images/prest-logo.png',  # development
                )))
        self.lblVersion.setText(branding.VERSION)
        self.lblLicense.linkActivated.connect(self.catch_exc(
            self.open_license))
Beispiel #4
0
        def __init__(self, ds: 'ConsistencyResult') -> None:
            QDialog.__init__(self)
            self.setupUi(self)

            help_icon = QIcon(
                platform_specific.get_embedded_file_path(
                    'images/qm-16.png',  # deploy
                    'gui/images/qm-16.png',  # devel
                ))

            # we assign model to self to prevent GC
            F = util.tree_model.Field
            self.model = util.tree_model.TreeModel(
                RootNode(ds.subjects),
                headers=(
                    'Subject',
                    'Cycle length',
                    F(
                        'WARP (pairs)', help_icon,
                        'consistency/cons_general.html#weak-axiom-of-revealed-preference-warp'
                    ),
                    F(
                        'WARP (all)', help_icon,
                        'consistency/cons_general.html#weak-axiom-of-revealed-preference-warp'
                    ),
                    F('Congruence', help_icon,
                      'consistency/cons_general.html#congruence'),
                    F(
                        'Strict general cycles', help_icon,
                        'consistency/cons_general.html#strict-choice-consistency'
                    ),  # SARP
                    F(
                        'Binary cycles', help_icon,
                        'consistency/cons_general.html#binary-choice-consistency'
                    ),
                    F(
                        'Strict binary cycles', help_icon,
                        'consistency/cons_general.html#strict-binary-choice-consistency'
                    ),  # SARP-binary
                ),
            )
            self.twRows.setModel(self.model)

            hdr = self.twRows.header()

            hdr.setSectionsClickable(True)
            hdr.sectionClicked.connect(self.header_clicked)

            hdr.setSectionResizeMode(QHeaderView.ResizeToContents)
            hdr.setStretchLastSection(False)
Beispiel #5
0
    def fill_table(self):
        self.checkboxes = []
        help_icon = QIcon(platform_specific.get_embedded_file_path(
            'images/qm-16.png',      # deploy
            'gui/images/qm-16.png',  # devel
        ))
        self.twModels.clear()

        def add_item(parent, item):
            if isinstance(item, model.Category):
                twi = QTreeWidgetItem(parent, [item.name, None, None])
                twi.setFirstColumnSpanned(True)
                for child in item.children:
                    add_item(twi, child)

            elif isinstance(item, model.ModelGroup):
                twi = QTreeWidgetItem(parent)
                twi.setDisabled(not item.variants)

                cell = QWidget()
                layout = QHBoxLayout(cell)
                layout.setContentsMargins(4,2,4,2) # l,t,r,b

                lblName = QLabel(item.name)
                layout.addWidget(lblName, alignment=Qt.AlignVCenter)

                self.twModels.setItemWidget(twi, 1, cell)

                if item.help_url:
                    btn = QPushButton(help_icon, '')
                    btn.setFlat(True)

                    # create a closure for `html`
                    def connect(url):
                        btn.clicked.connect(self.catch_exc(
                            lambda _checked: doc.open_in_browser(url)
                        ))
                    connect(item.help_url)

                    self.twModels.setItemWidget(twi, 0, btn)

                for i, name_model in enumerate(item.variants, 2):
                    if name_model is None: continue
                    # the identifier "model" would clash with the module import
                    name_html, model_def = name_model

                    cb = QCheckBox()
                    label = QLabel(name_html)
                    label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)

                    cell = QWidget()
                    layout = QHBoxLayout(cell)
                    layout.setSpacing(4)
                    layout.setContentsMargins(4,0,4,0) # l,t,r,b
                    layout.addWidget(cb, stretch=0, alignment=Qt.AlignVCenter)
                    layout.addWidget(label, stretch=1, alignment=Qt.AlignVCenter)
                    # all extra space (stretch) goes to the label because stretch ratio is 1:0

                    self.twModels.setItemWidget(twi, i, cell)
                    self.checkboxes.append((cb, model_def))

            else:
                raise Exception('unknown item: %s' % item)

        root = self.twModels.invisibleRootItem()
        for item in model.MODELS:
            add_item(root, item)
Beispiel #6
0
    def __init__(self):

        # window setup
        log.debug('creating GUI')
        QMainWindow.__init__(self)
        self.setupUi(self)

        # icon
        self.setWindowIcon(
            QIcon(
                platform_specific.get_embedded_file_path(
                    'images/prest.ico',  # deployment
                    'gui/images/prest.ico',  # development
                )))

        # instance attributes
        self.workspace = workspace.Workspace()

        # main menu
        self.actionGenerate_random_subjects.triggered.connect(
            self.catch_exc(self.dlg_simulation))
        self.actionWorkspaceClear.triggered.connect(
            self.catch_exc(self.dlg_workspace_clear))
        self.actionWorkspaceLoad.triggered.connect(
            self.catch_exc(self.dlg_workspace_load))
        self.actionWorkspaceSave.triggered.connect(
            self.catch_exc(self.dlg_workspace_save))
        self.actionWorkspaceSaveAs.triggered.connect(
            self.catch_exc(self.dlg_workspace_save_as))
        self.actionDatasetImport.triggered.connect(
            self.catch_exc(self.dlg_dataset_import))
        self.actionImport_budgetary_dataset.triggered.connect(
            self.catch_exc(self.dlg_budgetary_import))
        self.actionHelp.triggered.connect(self.catch_exc(self.dlg_help_show))
        self.actionAbout_Prest.triggered.connect(self.catch_exc(
            self.dlg_about))
        self.actionQuit.triggered.connect(
            self.close)  # self.close is a slot -> not wrapping

        # debug
        self.actionShow_console_window.toggled.connect(
            self.catch_exc(self.show_console_window))
        self.actionCrash_core.triggered.connect(
            self.catch_exc(self.dlg_crash_core))
        self.actionSoft_core_failure.triggered.connect(
            self.catch_exc(self.dlg_soft_core_failure))
        self.actionHidden_features.toggled.connect(
            self.catch_exc(self.enable_hidden_features))

        self.tblDataSets.doubleClicked.connect(
            self.catch_exc(self.dlg_view_current_dataset))
        self.tblDataSets.customContextMenuRequested.connect(
            self.catch_exc(self.context_menu))

        self.tblDataSets.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.tblDataSets.horizontalHeader().setStretchLastSection(False)

        if not platform_specific.is_windows():
            self.actionShow_console_window.setEnabled(False)

        self.enableDebuggingTools = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_D),
            self,
        )
        self.enableDebuggingTools.activated.connect(
            self.enable_debugging_tools)
        self.menuDebugging_tools.menuAction().setVisible(False)
        self.hidden_features_enabled = False

        try:
            doc.start_daemon(
                platform_specific.get_embedded_file_path(
                    'html',  # deployment
                    'docs/build/html',  # development
                ))
        except OSError as e:
            log.exception('could not start doc server')
Beispiel #7
0
    def context_menu(self, pos) -> None:
        item = self.tblDataSets.itemAt(pos)
        if item is None:
            log.debug('context menu requested but no item selected')
            return

        ds = self.workspace.datasets[self.tblDataSets.row(item)]

        menu = QMenu(self)
        icon_hidden = QIcon(
            platform_specific.get_embedded_file_path(
                'images/experimental.png',  # deployment
                'gui/images/experimental.png',  # development
            ))

        a_view = QAction("View...", menu)
        a_view.triggered.connect(self.catch_exc(ds.dlg_view))
        a_view.setStatusTip(
            'Display the dataset in a separate window. Also available via double click.'
        )
        menu.addAction(a_view)

        analyses = ds.get_analyses()
        if analyses:
            m_analyses = QMenu(menu)
            a_analyses = QAction("Analysis", menu)
            a_analyses.setMenu(m_analyses)
            a_analyses.setStatusTip('Run various analyses on the dataset.')
            menu.addAction(a_analyses)

            for analysis in analyses:
                if analysis.is_hidden:
                    if self.hidden_features_enabled:
                        icon = icon_hidden
                    else:
                        # skip this one
                        continue
                else:
                    icon = None

                def mkanalyse(analysis):
                    def analyse(_flag):
                        new_ds = ds.analyse(analysis)
                        if new_ds is not None:
                            self.add_dataset(new_ds)

                    return analyse

                if analysis.config:
                    analysis_name = analysis.name + '...'
                else:
                    analysis_name = analysis.name

                a_analysis = QAction(analysis_name, m_analyses)
                if icon:
                    a_analysis.setIcon(icon)
                a_analysis.analyse = mkanalyse(
                    analysis)  # create and save the closure
                a_analysis.triggered.connect(self.catch_exc(
                    a_analysis.analyse))
                m_analyses.addAction(a_analysis)

        export_variants = ds.get_export_variants()
        if export_variants:
            m_exports = QMenu(menu)
            a_exports = QAction("Export", menu)
            a_exports.setMenu(m_exports)
            a_exports.setStatusTip('Export the dataset into a file on disk.')
            menu.addAction(a_exports)

            for export_variant in export_variants:

                def mkexport(export_variant):
                    def export(_flag):
                        fname, fformat = QFileDialog.getSaveFileName(
                            self,
                            "Export dataset",
                            filter=
                            "Excel 2010+ (*.xlsx);;Comma Separated Values (*.csv)"
                        )
                        if not fname:
                            return

                        class MyWorker(Worker):
                            def work(self):
                                ds.export(fname, fformat, export_variant, self)

                        try:
                            MyWorker().run_with_progress(
                                None, "Exporting to %s..." % fname)
                        except Cancelled:
                            log.info('export cancelled')

                    return export

                a_export = QAction(export_variant.name + '...', m_exports)
                a_export.export = mkexport(
                    export_variant)  # create and save the closure
                a_export.triggered.connect(self.catch_exc(a_export.export))
                m_exports.addAction(a_export)

        menu.addSeparator()

        def delete(_flag):
            answer = QMessageBox.question(
                self,
                "Delete dataset",
                "Do you really want to delete the selected dataset?",
                defaultButton=QMessageBox.No)

            if answer == QMessageBox.Yes:
                self.delete_dataset(ds)

        a_delete = QAction("Delete", menu)
        a_delete.delete = delete
        a_delete.triggered.connect(self.catch_exc(a_delete.delete))
        a_delete.setStatusTip(
            'Remove the dataset from the workspace. Asks for confirmation.')
        menu.addAction(a_delete)

        menu.popup(self.tblDataSets.viewport().mapToGlobal(pos))
Beispiel #8
0
import platform_specific

with open(platform_specific.get_embedded_file_path('version.txt')) as f:
    VERSION = f.read().strip()

PREST_VERSION = f'Prest {VERSION}'