Source code for schrodinger.application.livedesign.login_gui

import sys

import requests

from schrodinger import get_maestro
from schrodinger.Qt import QtCore
from schrodinger.ui.qt import basewidgets
from schrodinger.ui.qt.appframework2 import settings
from schrodinger.utils import fileutils

from . import login
from . import login_ui

maestro = get_maestro()


[docs]class LiveDesignLoginDialog(settings.SettingsPanelMixin, basewidgets.BaseWidget): ui_module = login_ui
[docs] def initSetOptions(self): super(LiveDesignLoginDialog, self).initSetOptions() self.setWindowModality(QtCore.Qt.WindowModal) self.ld_client = None self.ld_models = None self.import_paths = [] self.setWindowTitle("Connect to LiveDesign") if maestro: # Add a direct connection as we need the global vars to be reset as # soon as the project is closed, not when the login panel is # reopened as it would be if the callback method decorator is used. maestro.project_close_callback_add(self.onProjectClosed)
[docs] def initSetUp(self): super(LiveDesignLoginDialog, self).initSetUp() self.ui.login_btn.clicked.connect(self.connectToLD) # Press the login btn when user presses Enter from any of the lineedits line_edits = (self.ui.host_le, self.ui.username_le, self.ui.password_le) for le in line_edits: le.returnPressed.connect(self.ui.login_btn.click) self.setDefaults()
[docs] def setDefaults(self): self._configurePanelSettings() self.setPersistent(login.HOST) self.setPersistent(login.USERNAME) self.ui.login_btn.setDefault(True) self.ui.login_btn.setAutoDefault(True)
[docs] def definePanelSettings(self): """ See parent class for docstring """ return [(login.HOST, self.ui.host_le), (login.USERNAME, self.ui.username_le), (login.CLIENT, 'ld_client'), (login.MODELS, 'ld_models')]
[docs] def connectToLD(self): """ Return False if an error occurred. :return: Whether to continue to the next panel. :rtype: bool """ msg = "" self.ui.error_label.setText(msg) if not self[login.HOST]: msg = login.ENTER_HOST_MSG elif not (self[login.USERNAME] and self.ui.password_le.text()): msg = login.ENTER_CREDENTIALS_MSG else: self.checkHost() try: msg = self.setupLDClient() except requests.exceptions.HTTPError: msg = login.INVALID_CREDENTIALS_MSG except requests.exceptions.ConnectionError as err: if 'Operation timed out' in str(err): # Show special message when the request timed out - which # is the most common exception raised. msg = login.TIMEOUT_MSG else: # Invalid host name, etc. Message will be shown on the 2nd # line in the status label. msg = login.NO_LDCLIENT_MSG + ":\n%s" % err except Exception as err: # Print the traceback to the terminal, so that we know what type # of exception to catch. Still show something to the user as # well (without crashing the GUI): msg = login.NO_LDCLIENT_MSG import traceback traceback.print_exc() if msg: self.ui.error_label.setText(msg) return else: try: self.ld_client.ping() self.ui.error_label.setText("") except requests.HTTPError as error: # somehow when running in Maestro, the HTTPError was not caught. msg = login.INVALID_CREDENTIALS_MSG if "Unauthorized" in str( error) else str(error) self.ui.error_label.setText(msg) return except RuntimeError as error: # The client version does not match the server version msg = login.VERSION_MISMATCH_MSG if 'not supported' in str( error) else str(error) self.ui.error_label.setText(msg) return self._setGlobalVars(self[login.USERNAME], self.ui.password_le.text(), self[login.HOST], self.import_paths) self.savePersistentOptions() self.close()
[docs] def checkHost(self): """ Check if the host is entered correctly. If not, updates the host string with the correct format. """ self[login.HOST] = login.format_host(self[login.HOST])
def _getFetchFiles(self): """ Return list containing tuples used to fetch files from server. :return: a list of 3-tuples, each of which contain 1. server path 2. tar filename base (no extension) 3. glob path (which can contain wildcards such as "*") :rtype: list(tuple(str, str, str)) """ return [(login.LDCLIENT_PATH, 'ldclient', 'ldclient-*')]
[docs] def setupLDClient(self): """ Fetch client.py from the given host. """ tmp_dir = fileutils.get_directory_path(fileutils.TEMP) self.import_paths = [] for server_path, tar_filename, glob_path in self._getFetchFiles(): url = self[login.HOST] + server_path try: client_path = login.download_ld_client(url, tmp_dir, tar_filename, glob_path) except RuntimeError as error: return str(error) + login.CONTACT_SUPPORT_MSG self.import_paths.append(client_path) sys.path.insert(0, client_path) try: import ldclient.client import ldclient.models except ImportError as e: return login.IMPORT_ERROR_MSG + login.CONTACT_SUPPORT_MSG # Check if LDClient can be instantiated with given login credentials ld_client_host = self[login.HOST] + login.API_PATH self.ld_client = ldclient.client.LDClient( ld_client_host, self[login.USERNAME], self.ui.password_le.text(), compatibility_mode=login.LD_VERSION_COMPATIBILITY_MODE) self.ld_models = ldclient.models
[docs] def onProjectClosed(self): """ If current project is closed, then all saved credentials will be reset. """ self._setGlobalVars(None, None, None, []) self.ui.password_le.setText('')
def _setGlobalVars(self, uname, pwd, host, paths): """ Helper method to set the global variables. :param uname: username :type uname: str :param pwd: password :type pwd: str :param host: LiveDesign server host :type host: str :param paths: the paths used to import necessary modules :type paths: List of str """ login._SESSION_USERNAME = uname login._SESSION_PWD = pwd login._SESSION_HOST = host login._SESSION_IMPORT_PATHS = paths
# ============================================================================= # For testing outside of Maestro # =============================================================================
[docs]def panel(): return LiveDesignLoginDialog.panel()
if __name__ == "__main__": panel()