class DialogPlotEscapePeak(QDialog): def __init__(self): super().__init__() self.setWindowTitle("Escape Peak Settings") self.grp_show_escape_peak = QGroupBox("Show Escape Peak") self.grp_show_escape_peak.setCheckable(True) self.grp_show_escape_peak.setChecked(False) # Set based on data !!! self.le_incident_energy = LineEditReadOnly() set_tooltip( self.le_incident_energy, "<b>Incident energy</b>. Use <b>General...</b> button of <b>Model</b> tab " "to change the value if needed.", ) self.combo_detector_type = QComboBox() set_tooltip(self.combo_detector_type, "Select <b>detector</b> material. The typical choice is <b>Si</b>") self._detector_types = ["Si", "Ge"] self.combo_detector_type.addItems(self._detector_types) grid = QGridLayout() grid.addWidget(QLabel("Incident energy, kev:"), 0, 0) grid.addWidget(self.le_incident_energy, 0, 1) grid.addWidget(QLabel("Detectory type:"), 1, 0) grid.addWidget(self.combo_detector_type, 1, 1) self.grp_show_escape_peak.setLayout(grid) # Yes/No button box button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) vbox = QVBoxLayout() vbox.addWidget(self.grp_show_escape_peak) vbox.addWidget(button_box) self.setLayout(vbox) def set_parameters(self, plot_escape_peak, incident_energy, detector_material): index_material = -1 if detector_material in self._detector_types: index_material = self._detector_types.index(detector_material) self.combo_detector_type.setCurrentIndex(index_material) self.le_incident_energy.setText(f"{incident_energy:.10g}") self.grp_show_escape_peak.setChecked(plot_escape_peak) def get_parameters(self): plot_escape_peak = self.grp_show_escape_peak.isChecked() index = self.combo_detector_type.currentIndex() if index >= 0: detector_material = self._detector_types[self.combo_detector_type.currentIndex()] else: detector_material = "" return plot_escape_peak, detector_material
class KernelConnectionDialog(QDialog, SpyderConfigurationAccessor): """Dialog to connect to existing kernels (either local or remote).""" CONF_SECTION = 'existing-kernel' def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel( _("<p>Please select the JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel, and enter " "the SSH information if connecting to a remote machine. " "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 2, 1, 3) # SSH authentication layout auth_layout = QGridLayout() auth_layout.addWidget(self.pw_radio, 1, 0) auth_layout.addWidget(pw_label, 1, 1) auth_layout.addWidget(self.pw, 1, 2) auth_layout.addWidget(self.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_group.setLayout(auth_layout) # Remote kernel layout rm_layout = QVBoxLayout() rm_layout.addLayout(ssh_layout) rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) rm_layout.addWidget(auth_group) self.rm_group.setLayout(rm_layout) self.rm_group.setCheckable(True) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.save_connection_settings) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Save connection settings checkbox self.save_layout = QCheckBox(self) self.save_layout.setText(_("Save connection settings")) btns_layout = QHBoxLayout() btns_layout.addWidget(self.save_layout) btns_layout.addWidget(self.accept_btns) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addLayout(btns_layout) self.cf.setFocus() self.load_connection_settings() def load_connection_settings(self): """Load the user's previously-saved kernel connection settings.""" existing_kernel = self.get_conf("settings", {}) connection_file_path = existing_kernel.get("json_file_path", "") is_remote = existing_kernel.get("is_remote", False) username = existing_kernel.get("username", "") hostname = existing_kernel.get("hostname", "") port = str(existing_kernel.get("port", 22)) is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False) ssh_kf = existing_kernel.get("ssh_key_file_path", "") if connection_file_path != "": self.cf.setText(connection_file_path) if username != "": self.un.setText(username) if hostname != "": self.hn.setText(hostname) if ssh_kf != "": self.kf.setText(ssh_kf) self.rm_group.setChecked(is_remote) self.pn.setText(port) self.kf_radio.setChecked(is_ssh_kf) self.pw_radio.setChecked(not is_ssh_kf) try: import keyring ssh_passphrase = keyring.get_password("spyder_remote_kernel", "ssh_key_passphrase") ssh_password = keyring.get_password("spyder_remote_kernel", "ssh_password") if ssh_passphrase: self.kfp.setText(ssh_passphrase) if ssh_password: self.pw.setText(ssh_password) except Exception: pass def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text() } self.set_conf("settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass def select_connection_file(self): cf = getopenfilename(self, _('Select kernel connection file'), jupyter_runtime_dir(), '*.json;;*.*')[0] self.cf.setText(cf) def select_ssh_key(self): kf = getopenfilename(self, _('Select SSH keyfile'), get_home_dir(), '*.pem;;*')[0] self.kf.setText(kf) @staticmethod def get_connection_parameters(parent=None, dialog=None): if not dialog: dialog = KernelConnectionDialog(parent) result = dialog.exec_() is_remote = bool(dialog.rm_group.isChecked()) accepted = result == QDialog.Accepted if is_remote: def falsy_to_none(arg): return arg if arg else None if dialog.hn.text() and dialog.un.text(): port = dialog.pn.text() if dialog.pn.text() else '22' hostname = "{0}@{1}:{2}".format(dialog.un.text(), dialog.hn.text(), port) else: hostname = None if dialog.pw_radio.isChecked(): password = falsy_to_none(dialog.pw.text()) keyfile = None elif dialog.kf_radio.isChecked(): keyfile = falsy_to_none(dialog.kf.text()) password = falsy_to_none(dialog.kfp.text()) else: # imposible? keyfile = None password = None return (dialog.cf.text(), hostname, keyfile, password, accepted) else: path = dialog.cf.text() _dir, filename = osp.dirname(path), osp.basename(path) if _dir == '' and not filename.endswith('.json'): path = osp.join(jupyter_runtime_dir(), 'kernel-' + path + '.json') return (path, None, None, None, accepted)
class KernelConnectionDialog(QDialog): """Dialog to connect to existing kernels (either local or remote).""" def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel( _("<p>Please select a local JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel. " "<br><br>" "If connecting to a remote machine, enter the SSH information, " "adjust the command how to get jupyter runtime directory (if needed) " "push the button to fetch remote configuration files and select one " "of the loaded options." "<br><br>" "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) self.TEXT_FETCH_REMOTE_CONN_FILES_BTN = 'Fetch remote connection files' self.DEFAULT_CMD_FOR_JUPYTER_RUNTIME = 'jupyter --runtime-dir' # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # Button to fetch JSON files listing self.kf_fetch_conn_files_btn = QPushButton( _(self.TEXT_FETCH_REMOTE_CONN_FILES_BTN)) self.kf_fetch_conn_files_btn.clicked.connect( self.fill_combobox_with_fetched_remote_connection_files) self.cb_remote_conn_files = QComboBox() self.cb_remote_conn_files.currentIndexChanged.connect( self._take_over_selected_remote_configuration_file) # Remote kernel groupbox self.start_remote_kernel_group = QGroupBox(_("Start remote kernel")) # Advanced settings to get remote connection files jupyter_runtime_location_cmd_label = QLabel( _('Command to get Jupyter runtime:')) self.jupyter_runtime_location_cmd_lineedit = QLineEdit() self.jupyter_runtime_location_cmd_lineedit.setPlaceholderText( _(self.DEFAULT_CMD_FOR_JUPYTER_RUNTIME)) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 2, 1, 3) # SSH authentication layout auth_layout = QGridLayout() auth_layout.addWidget(self.pw_radio, 1, 0) auth_layout.addWidget(pw_label, 1, 1) auth_layout.addWidget(self.pw, 1, 2) auth_layout.addWidget(self.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_layout.addWidget(jupyter_runtime_location_cmd_label, 4, 1) auth_layout.addWidget(self.jupyter_runtime_location_cmd_lineedit, 4, 2) auth_layout.addWidget(self.kf_fetch_conn_files_btn, 5, 1) auth_layout.addWidget(self.cb_remote_conn_files, 5, 2) auth_group.setLayout(auth_layout) # Remote kernel layout rm_layout = QVBoxLayout() rm_layout.addLayout(ssh_layout) rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) rm_layout.addWidget(auth_group) self.rm_group.setLayout(rm_layout) self.rm_group.setCheckable(True) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.save_connection_settings) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Save connection settings checkbox self.save_layout = QCheckBox(self) self.save_layout.setText(_("Save connection settings")) btns_layout = QHBoxLayout() btns_layout.addWidget(self.save_layout) btns_layout.addWidget(self.accept_btns) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addLayout(btns_layout) # List with connection file paths found on the remote host self.remote_conn_file_paths = [] self.load_connection_settings() def load_connection_settings(self): """Load the user's previously-saved kernel connection settings.""" existing_kernel = CONF.get("existing-kernel", "settings", {}) connection_file_path = existing_kernel.get("json_file_path", "") is_remote = existing_kernel.get("is_remote", False) username = existing_kernel.get("username", "") hostname = existing_kernel.get("hostname", "") port = str(existing_kernel.get("port", 22)) is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False) ssh_kf = existing_kernel.get("ssh_key_file_path", "") cmd_jupyter_runtime = existing_kernel.get("cmd_jupyter_runtime") if connection_file_path != "": self.cf.setText(connection_file_path) if username != "": self.un.setText(username) if hostname != "": self.hn.setText(hostname) if ssh_kf != "": self.kf.setText(ssh_kf) if cmd_jupyter_runtime != "": self.jupyter_runtime_location_cmd_lineedit.setText( cmd_jupyter_runtime) self.rm_group.setChecked(is_remote) self.pn.setText(port) self.kf_radio.setChecked(is_ssh_kf) self.pw_radio.setChecked(not is_ssh_kf) try: import keyring ssh_passphrase = keyring.get_password("spyder_remote_kernel", "ssh_key_passphrase") ssh_password = keyring.get_password("spyder_remote_kernel", "ssh_password") if ssh_passphrase: self.kfp.setText(ssh_passphrase) if ssh_password: self.pw.setText(ssh_password) except Exception: pass def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text(), "cmd_jupyter_runtime": self.jupyter_runtime_location_cmd_lineedit.text() } CONF.set("existing-kernel", "settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass def select_connection_file(self): cf = getopenfilename(self, _('Select kernel connection file'), jupyter_runtime_dir(), '*.json;;*.*')[0] self.cf.setText(cf) def select_ssh_key(self): kf = getopenfilename(self, _('Select SSH keyfile'), get_home_dir(), '*.pem;;*')[0] self.kf.setText(kf) def _take_over_selected_remote_configuration_file( self, chosen_idx_of_combobox_with_remote_conn_files): remote_path_filename = self.remote_conn_file_paths[ chosen_idx_of_combobox_with_remote_conn_files] self.cf.setText(remote_path_filename) def fill_combobox_with_fetched_remote_connection_files(self): """ Fill the combobox with found remote connection json files. :return: None """ _, username, _, only_host, port, keyfile, password = KernelConnectionDialog._get_remote_config( self) cmd_to_get_location_of_jupyter_runtime_files = self.jupyter_runtime_location_cmd_lineedit.text( ) self.remote_conn_file_paths = self._fetch_connection_files_list( host=only_host, keyfile=keyfile, password=password, username=username, port=port, cmd_to_get_location_of_jupyter_runtime_files= cmd_to_get_location_of_jupyter_runtime_files) conn_files_short = [ c.rsplit('/', 1)[1] if '/' in c else c for c in self.remote_conn_file_paths ] self.cb_remote_conn_files.addItems(conn_files_short) def _fetch_connection_files_list( self, host: str, keyfile: Optional[str], password: Optional[str], username: Optional[str], port: str, cmd_to_get_location_of_jupyter_runtime_files: Optional[str]): """ :param host: URL or IP of the host. :param keyfile: SSH key path or None if no key was provided. :param password: Password for SSH connection or None if no password is used. :rtype: List[str] :return: """ import paramiko client = paramiko.SSHClient() self.kf_fetch_conn_files_btn.setDisabled(True) list_of_copied_connection_files = [] try: client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=host, port=int(port), key_filename=keyfile, passphrase=password, username=username, timeout=10, auth_timeout=10) if cmd_to_get_location_of_jupyter_runtime_files is None: cmd_to_get_location_of_jupyter_runtime_files = self.DEFAULT_CMD_FOR_JUPYTER_RUNTIME self.kf_fetch_conn_files_btn.setText( 'Getting location of jupyter runtime...') stdin, stdout, stderr = client.exec_command( cmd_to_get_location_of_jupyter_runtime_files) location_of_jupyter_runtime = stdout.readlines() if len(location_of_jupyter_runtime) > 0: location_of_jupyter_runtime = location_of_jupyter_runtime[ 0].strip() # get absolute paths stdin, stdout, stderr = client.exec_command( f'ls -d {location_of_jupyter_runtime}/*') list_of_connection_files = stdout.readlines() if len(list_of_connection_files) > 0: list_of_connection_files = [ l.strip() for l in list_of_connection_files ] import tempfile import os temp_dir = tempfile.gettempdir() only_filenames = [ f.rsplit('/', 1)[1] for f in list_of_connection_files ] list_of_copied_connection_files = [ os.path.join(temp_dir, f) for f in only_filenames ] self.kf_fetch_conn_files_btn.setText( f'Downloading {len(list_of_connection_files)} connection files...' ) for remote_path, filename_only in zip( list_of_connection_files, only_filenames): sftp = client.open_sftp() sftp.get(remote_path, os.path.join(temp_dir, filename_only)) sftp.close() else: show_info_dialog( "Warning", f"Could not find any jupyter configuration files in {location_of_jupyter_runtime}." ) else: show_info_dialog( "Warning", f"Could not extract jupyter runtime location. Error from command line: {stderr.readlines()}" ) finally: client.close() self.kf_fetch_conn_files_btn.setText( self.TEXT_FETCH_REMOTE_CONN_FILES_BTN) self.kf_fetch_conn_files_btn.setEnabled(True) return list_of_copied_connection_files @staticmethod def _get_remote_config(dialog): only_host = None username = None port = '22' if dialog.hn.text() and dialog.un.text(): port = dialog.pn.text() if dialog.pn.text() else '22' only_host = dialog.hn.text() username = dialog.un.text() hostname = "{0}@{1}:{2}".format(username, only_host, port) else: hostname = None if dialog.pw_radio.isChecked(): password = _falsy_to_none(dialog.pw.text()) keyfile = None elif dialog.kf_radio.isChecked(): keyfile = _falsy_to_none(dialog.kf.text()) password = _falsy_to_none(dialog.kfp.text()) else: # imposible? keyfile = None password = None return dialog.cf.text( ), username, hostname, only_host, port, keyfile, password @staticmethod def get_connection_parameters(parent=None, dialog=None): if not dialog: dialog = KernelConnectionDialog(parent) result = dialog.exec_() is_remote = bool(dialog.rm_group.isChecked()) accepted = result == QDialog.Accepted if is_remote: cf_text, _, hostname, _, _, keyfile, password = KernelConnectionDialog._get_remote_config( dialog) return cf_text, hostname, keyfile, password, accepted else: path = dialog.cf.text() _dir, filename = osp.dirname(path), osp.basename(path) if _dir == '' and not filename.endswith('.json'): path = osp.join(jupyter_runtime_dir(), 'kernel-' + path + '.json') return path, None, None, None, accepted
class KernelConnectionDialog(QDialog): """Dialog to connect to existing kernels (either local or remote).""" def __init__(self, parent=None): super(KernelConnectionDialog, self).__init__(parent) self.setWindowTitle(_('Connect to an existing kernel')) main_label = QLabel(_( "<p>Please select the JSON connection file (<i>e.g.</i> " "<tt>kernel-1234.json</tt>) of the existing kernel, and enter " "the SSH information if connecting to a remote machine. " "To learn more about starting external kernels and connecting " "to them, see <a href=\"https://docs.spyder-ide.org/" "ipythonconsole.html#connect-to-an-external-kernel\">" "our documentation</a>.</p>")) main_label.setWordWrap(True) main_label.setAlignment(Qt.AlignJustify) main_label.setOpenExternalLinks(True) # Connection file cf_label = QLabel(_('Connection file:')) self.cf = QLineEdit() self.cf.setPlaceholderText(_('Kernel connection file path')) self.cf.setMinimumWidth(350) cf_open_btn = QPushButton(_('Browse')) cf_open_btn.clicked.connect(self.select_connection_file) cf_layout = QHBoxLayout() cf_layout.addWidget(cf_label) cf_layout.addWidget(self.cf) cf_layout.addWidget(cf_open_btn) # Remote kernel groupbox self.rm_group = QGroupBox(_("This is a remote kernel (via SSH)")) # SSH connection hn_label = QLabel(_('Hostname:')) self.hn = QLineEdit() pn_label = QLabel(_('Port:')) self.pn = QLineEdit() self.pn.setMaximumWidth(75) un_label = QLabel(_('Username:'******'Password:'******'SSH keyfile:')) self.pw = QLineEdit() self.pw.setEchoMode(QLineEdit.Password) self.pw_radio.toggled.connect(self.pw.setEnabled) self.kf_radio.toggled.connect(self.pw.setDisabled) self.kf = QLineEdit() kf_open_btn = QPushButton(_('Browse')) kf_open_btn.clicked.connect(self.select_ssh_key) kf_layout = QHBoxLayout() kf_layout.addWidget(self.kf) kf_layout.addWidget(kf_open_btn) kfp_label = QLabel(_('Passphase:')) self.kfp = QLineEdit() self.kfp.setPlaceholderText(_('Optional')) self.kfp.setEchoMode(QLineEdit.Password) self.kf_radio.toggled.connect(self.kf.setEnabled) self.kf_radio.toggled.connect(self.kfp.setEnabled) self.kf_radio.toggled.connect(kf_open_btn.setEnabled) self.kf_radio.toggled.connect(kfp_label.setEnabled) self.pw_radio.toggled.connect(self.kf.setDisabled) self.pw_radio.toggled.connect(self.kfp.setDisabled) self.pw_radio.toggled.connect(kf_open_btn.setDisabled) self.pw_radio.toggled.connect(kfp_label.setDisabled) # SSH layout ssh_layout = QGridLayout() ssh_layout.addWidget(hn_label, 0, 0, 1, 2) ssh_layout.addWidget(self.hn, 0, 2) ssh_layout.addWidget(pn_label, 0, 3) ssh_layout.addWidget(self.pn, 0, 4) ssh_layout.addWidget(un_label, 1, 0, 1, 2) ssh_layout.addWidget(self.un, 1, 2, 1, 3) # SSH authentication layout auth_layout = QGridLayout() auth_layout.addWidget(self.pw_radio, 1, 0) auth_layout.addWidget(pw_label, 1, 1) auth_layout.addWidget(self.pw, 1, 2) auth_layout.addWidget(self.kf_radio, 2, 0) auth_layout.addWidget(kf_label, 2, 1) auth_layout.addLayout(kf_layout, 2, 2) auth_layout.addWidget(kfp_label, 3, 1) auth_layout.addWidget(self.kfp, 3, 2) auth_group.setLayout(auth_layout) # Remote kernel layout rm_layout = QVBoxLayout() rm_layout.addLayout(ssh_layout) rm_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) rm_layout.addWidget(auth_group) self.rm_group.setLayout(rm_layout) self.rm_group.setCheckable(True) self.rm_group.toggled.connect(self.pw_radio.setChecked) # Ok and Cancel buttons self.accept_btns = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.accept_btns.accepted.connect(self.save_connection_settings) self.accept_btns.accepted.connect(self.accept) self.accept_btns.rejected.connect(self.reject) # Save connection settings checkbox self.save_layout = QCheckBox(self) self.save_layout.setText(_("Save connection settings")) btns_layout = QHBoxLayout() btns_layout.addWidget(self.save_layout) btns_layout.addWidget(self.accept_btns) # Dialog layout layout = QVBoxLayout(self) layout.addWidget(main_label) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8))) layout.addLayout(cf_layout) layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 12))) layout.addWidget(self.rm_group) layout.addLayout(btns_layout) self.load_connection_settings() def load_connection_settings(self): """Load the user's previously-saved kernel connection settings.""" existing_kernel = CONF.get("existing-kernel", "settings", {}) connection_file_path = existing_kernel.get("json_file_path", "") is_remote = existing_kernel.get("is_remote", False) username = existing_kernel.get("username", "") hostname = existing_kernel.get("hostname", "") port = str(existing_kernel.get("port", 22)) is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False) ssh_kf = existing_kernel.get("ssh_key_file_path", "") if connection_file_path != "": self.cf.setText(connection_file_path) if username != "": self.un.setText(username) if hostname != "": self.hn.setText(hostname) if ssh_kf != "": self.kf.setText(ssh_kf) self.rm_group.setChecked(is_remote) self.pn.setText(port) self.kf_radio.setChecked(is_ssh_kf) self.pw_radio.setChecked(not is_ssh_kf) try: import keyring ssh_passphrase = keyring.get_password("spyder_remote_kernel", "ssh_key_passphrase") ssh_password = keyring.get_password("spyder_remote_kernel", "ssh_password") if ssh_passphrase: self.kfp.setText(ssh_passphrase) if ssh_password: self.pw.setText(ssh_password) except Exception: pass def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text() } CONF.set("existing-kernel", "settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass def select_connection_file(self): cf = getopenfilename(self, _('Select kernel connection file'), jupyter_runtime_dir(), '*.json;;*.*')[0] self.cf.setText(cf) def select_ssh_key(self): kf = getopenfilename(self, _('Select SSH keyfile'), get_home_dir(), '*.pem;;*')[0] self.kf.setText(kf) @staticmethod def get_connection_parameters(parent=None, dialog=None): if not dialog: dialog = KernelConnectionDialog(parent) result = dialog.exec_() is_remote = bool(dialog.rm_group.isChecked()) accepted = result == QDialog.Accepted if is_remote: def falsy_to_none(arg): return arg if arg else None if dialog.hn.text() and dialog.un.text(): port = dialog.pn.text() if dialog.pn.text() else '22' hostname = "{0}@{1}:{2}".format(dialog.un.text(), dialog.hn.text(), port) else: hostname = None if dialog.pw_radio.isChecked(): password = falsy_to_none(dialog.pw.text()) keyfile = None elif dialog.kf_radio.isChecked(): keyfile = falsy_to_none(dialog.kf.text()) password = falsy_to_none(dialog.kfp.text()) else: # imposible? keyfile = None password = None return (dialog.cf.text(), hostname, keyfile, password, accepted) else: path = dialog.cf.text() _dir, filename = osp.dirname(path), osp.basename(path) if _dir == '' and not filename.endswith('.json'): path = osp.join(jupyter_runtime_dir(), 'kernel-'+path+'.json') return (path, None, None, None, accepted)
class EFMDialog(QDialog): """A dialog to set up EFM calculation""" def __init__(self, appdata: CnaData, centralwidget): QDialog.__init__(self) self.setWindowTitle("Elementary Flux Mode Computation") self.appdata = appdata self.centralwidget = centralwidget self.eng = appdata.engine self.out = io.StringIO() self.err = io.StringIO() self.layout = QVBoxLayout() l1 = QHBoxLayout() self.constraints = QCheckBox("consider 0 in current scenario as off") self.constraints.setCheckState(Qt.Checked) l1.addWidget(self.constraints) self.layout.addItem(l1) l2 = QHBoxLayout() self.flux_bounds = QGroupBox( "use flux bounds to calculate elementary flux vectors") self.flux_bounds.setCheckable(True) self.flux_bounds.setChecked(False) vbox = QVBoxLayout() label = QLabel("Threshold for bounds to be unconstrained") vbox.addWidget(label) self.threshold = QLineEdit("100") validator = QIntValidator() validator.setBottom(0) self.threshold.setValidator(validator) vbox.addWidget(self.threshold) self.flux_bounds.setLayout(vbox) l2.addWidget(self.flux_bounds) self.layout.addItem(l2) l3 = QHBoxLayout() self.check_reversibility = QCheckBox("check reversibility") self.check_reversibility.setCheckState(Qt.Checked) l3.addWidget(self.check_reversibility) self.layout.addItem(l3) l4 = QHBoxLayout() self.convex_basis = QCheckBox("only convex basis") l4.addWidget(self.convex_basis) self.layout.addItem(l4) l5 = QHBoxLayout() self.isozymes = QCheckBox("consider isozymes only once") l5.addWidget(self.isozymes) self.layout.addItem(l5) # TODO: choose solver l7 = QHBoxLayout() self.rational_numbers = QCheckBox("use rational numbers") l7.addWidget(self.rational_numbers) self.layout.addItem(l7) lx = QHBoxLayout() self.button = QPushButton("Compute") self.cancel = QPushButton("Close") lx.addWidget(self.button) lx.addWidget(self.cancel) self.layout.addItem(lx) self.setLayout(self.layout) # Connecting the signal self.cancel.clicked.connect(self.reject) self.button.clicked.connect(self.compute) def compute(self): # create CobraModel for matlab self.appdata.create_cobra_model() legacy.read_cnapy_model(self.eng) # get some data reac_id = self.eng.get_reacID() # setting parameters a = self.eng.eval("constraints = {};", nargout=0, stdout=self.out, stderr=self.err) scenario = {} if self.constraints.checkState( ) == Qt.Checked or self.flux_bounds.isChecked(): onoff_str = "" for r in reac_id: if r in self.appdata.project.scen_values.keys(): (vl, vu) = self.appdata.project.scen_values[r] if vl == vu: if vl > 0: onoff_str = onoff_str + " NaN" # efmtool does not support 1 elif vl == 0: scenario[r] = (0, 0) onoff_str = onoff_str + " 0" else: onoff_str = onoff_str + " NaN" print("WARN: negative value in scenario") else: onoff_str = onoff_str + " NaN" print("WARN: not fixed value in scenario") else: onoff_str = onoff_str + " NaN" onoff_str = "reaconoff = [" + onoff_str + "];" a = self.eng.eval(onoff_str, nargout=0, stdout=self.out, stderr=self.err) a = self.eng.eval("constraints.reaconoff = reaconoff;", nargout=0, stdout=self.out, stderr=self.err) if self.flux_bounds.isChecked(): threshold = float(self.threshold.text()) lb_str = "" ub_str = "" for r in reac_id: c_reaction = self.appdata.project.cobra_py_model.reactions.get_by_id( r) if r in self.appdata.project.scen_values: (vl, vu) = self.appdata.project.scen_values[r] else: vl = c_reaction.lower_bound vu = c_reaction.upper_bound if vl <= -threshold: vl = "NaN" if vu >= threshold: vu = "NaN" if vl == 0 and vu == 0: # already in reaconoff, can be skipped here vl = "NaN" vu = "NaN" lb_str = lb_str + " " + str(vl) ub_str = ub_str + " " + str(vu) lb_str = "lb = [" + lb_str + "];" a = self.eng.eval(lb_str, nargout=0, stdout=self.out, stderr=self.err) a = self.eng.eval("constraints.lb = lb;", nargout=0, stdout=self.out, stderr=self.err) ub_str = "ub = [" + ub_str + "];" a = self.eng.eval(ub_str, nargout=0, stdout=self.out, stderr=self.err) a = self.eng.eval("constraints.ub = ub;", nargout=0, stdout=self.out, stderr=self.err) # TODO set solver 4 = EFMTool 3 = MetaTool, 1 = cna Mex file, 0 = cna functions a = self.eng.eval("solver = 4;", nargout=0, stdout=self.out, stderr=self.err) if self.check_reversibility.checkState() == Qt.Checked: a = self.eng.eval("irrev_flag = 1;", nargout=0, stdout=self.out, stderr=self.err) else: a = self.eng.eval("irrev_flag = 0;", nargout=0, stdout=self.out, stderr=self.err) # convex basis computation is only possible with METATOOL solver=3 if self.convex_basis.checkState() == Qt.Checked: a = self.eng.eval("conv_basis_flag = 1; solver = 3;", nargout=0, stdout=self.out, stderr=self.err) else: a = self.eng.eval("conv_basis_flag = 0;", nargout=0, stdout=self.out, stderr=self.err) if self.isozymes.checkState() == Qt.Checked: a = self.eng.eval("iso_flag = 1;", nargout=0, stdout=self.out, stderr=self.err) else: a = self.eng.eval("iso_flag = 0;", nargout=0, stdout=self.out, stderr=self.err) # default we have no macromolecules and display is et to ALL a = self.eng.eval("c_macro=[]; display= 'ALL';", nargout=0, stdout=self.out, stderr=self.err) if self.rational_numbers.checkState() == Qt.Checked: a = self.eng.eval( "efmtool_options = {'arithmetic', 'fractional'};", nargout=0, stdout=self.out, stderr=self.err) else: a = self.eng.eval("efmtool_options = {};", nargout=0, stdout=self.out, stderr=self.err) if self.appdata.is_matlab_set(): try: a = self.eng.eval( "[ems, irrev_ems, ems_idx, ray] = CNAcomputeEFM(cnap, constraints,solver,irrev_flag,conv_basis_flag,iso_flag,c_macro,display,efmtool_options);", nargout=0) except Exception: output = io.StringIO() traceback.print_exc(file=output) exstr = output.getvalue() print(exstr) QMessageBox.warning( self, 'Unknown exception occured!', exstr + '\nPlease report the problem to:\n\ \nhttps://github.com/cnapy-org/CNApy/issues' ) return else: ems = self.eng.workspace['ems'] idx = self.eng.workspace['ems_idx'] irreversible = numpy.squeeze(self.eng.workspace['irrev_ems']) unbounded = numpy.squeeze(self.eng.workspace['ray']) ems = numpy.array(ems) self.result2ui(ems, idx, reac_id, irreversible, unbounded, scenario) self.accept() elif self.appdata.is_octave_ready(): a = self.eng.eval( "[ems, irrev_ems, ems_idx, ray] = CNAcomputeEFM(cnap, constraints,solver,irrev_flag,conv_basis_flag,iso_flag,c_macro,display,efmtool_options);", nargout=0) ems = self.eng.pull('ems') idx = self.eng.pull('ems_idx') irreversible = numpy.squeeze(self.eng.pull('irrev_ems')) unbounded = numpy.squeeze(self.eng.pull('ray')) self.result2ui(ems, idx, reac_id, irreversible, unbounded, scenario) def result2ui(self, ems, idx, reac_id, irreversible, unbounded, scenario): if len(ems) == 0: QMessageBox.information( self, 'No modes', 'Modes have not been calculated or do not exist.') else: self.appdata.project.modes = FluxVectorContainer( ems, [reac_id[int(i) - 1] for i in idx[0]], irreversible, unbounded) self.centralwidget.mode_navigator.current = 0 self.centralwidget.mode_navigator.scenario = scenario self.centralwidget.mode_navigator.title.setText("Mode Navigation") self.centralwidget.update_mode()