def _add_dblink_from(self, src, label=None, link_type=LinkType.UNSPECIFIED): from aiida.backends.sqlalchemy import session if not isinstance(src, Node): raise ValueError("src must be a Node instance") if self.uuid == src.uuid: raise ValueError("Cannot link to itself") if self._to_be_stored: raise ModificationNotAllowed( "Cannot call the internal _add_dblink_from if the " "destination node is not stored") if src._to_be_stored: raise ModificationNotAllowed( "Cannot call the internal _add_dblink_from if the " "source node is not stored") # Check for cycles. This works if the transitive closure is enabled; if # it isn't, this test will never fail, but then having a circular link # is not meaningful but does not pose a huge threat # # I am linking src->self; a loop would be created if a DbPath exists # already in the TC table from self to src c = session.query(literal(True)).filter( DbPath.query.filter_by(parent_id=self.dbnode.id, child_id=src.dbnode.id).exists()).scalar() if c: raise ValueError( "The link you are attempting to create would generate a loop") if label is None: autolabel_idx = 1 existing_from_autolabels = session.query(DbLink.label).filter( DbLink.output_id == self.dbnode.id, DbLink.label.like("link%")) while "link_{}".format(autolabel_idx) in existing_from_autolabels: autolabel_idx += 1 safety_counter = 0 while True: safety_counter += 1 if safety_counter > 3: # Well, if you have more than 100 concurrent addings # to the same node, you are clearly doing something wrong... raise InternalError( "Hey! We found more than 100 concurrent" " adds of links " "to the same nodes! Are you really doing that??") try: self._do_create_link(src, "link_{}".format(autolabel_idx), link_type) break except UniquenessError: # Retry loop until you find a new loop autolabel_idx += 1 else: self._do_create_link(src, label, link_type)
def get_global_setting_description(key): """ Return the description for the given setting variable, as stored in the DB, or raise a KeyError if the setting is not present in the DB. """ try: return (session.query(DbSetting).filter_by( key=key).one().get_description()) except NoResultFound: raise KeyError("No global setting with key={}".format(key))
def get_global_setting(key): """ Return the value of the given setting, or raise a KeyError if the setting is not present in the DB. :raise KeyError: if the setting does not exist in the DB """ try: return session.query(DbSetting).filter_by(key=key).one().getvalue() except NoResultFound: raise KeyError("No global setting with key={}".format(key))
def get_global_setting_description(key): """ Return the description for the given setting variable, as stored in the DB, or raise a KeyError if the setting is not present in the DB or the table doesn't exist. """ from aiida.backends.sqlalchemy.models.utils import validate_key # Check first that the table exists table_check_test() validate_key(key) try: return (session.query(DbSetting).filter_by( key=key).one().get_description()) except NoResultFound: raise KeyError("No global setting with key={}".format(key))
def get_global_setting(key): """ Return the value of the given setting, or raise a KeyError if the setting is not present in the DB. :raise KeyError: if the setting does not exist in the DB """ from aiida.backends.sqlalchemy.models.utils import get_value_of_sub_field # Check first that the table exists table_check_test() try: return get_value_of_sub_field( key, lambda given_key: session.query(DbSetting).filter_by( key=given_key).one().getvalue()) except NoResultFound: raise KeyError("No global setting with key={}".format(key))
def get_authinfo(computer, aiidauser): if settings.BACKEND == BACKEND_DJANGO: from aiida.backends.djsite.db.models import DbComputer, DbAuthInfo from django.core.exceptions import (ObjectDoesNotExist, MultipleObjectsReturned) try: authinfo = DbAuthInfo.objects.get( # converts from name, Computer or DbComputer instance to # a DbComputer instance dbcomputer=DbComputer.get_dbcomputer(computer), aiidauser=aiidauser) except ObjectDoesNotExist: raise AuthenticationError( "The aiida user {} is not configured to use computer {}". format(aiidauser.email, computer.name)) except MultipleObjectsReturned: raise ConfigurationError( "The aiida user {} is configured more than once to use " "computer {}! Only one configuration is allowed".format( aiidauser.email, computer.name)) elif settings.BACKEND == BACKEND_SQLA: from aiida.backends.sqlalchemy.models.authinfo import DbAuthInfo from aiida.backends.sqlalchemy import session from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound try: authinfo = session.query(DbAuthInfo).filter_by( dbcomputer_id=computer.id, aiidauser_id=aiidauser.id, ).one() except NoResultFound: raise AuthenticationError( "The aiida user {} is not configured to use computer {}". format(aiidauser.email, computer.name)) except MultipleResultsFound: raise ConfigurationError( "The aiida user {} is configured more than once to use " "computer {}! Only one configuration is allowed".format( aiidauser.email, computer.name)) else: raise Exception("unknown backend {}".format(settings.BACKEND)) return authinfo
def get_most_recent_daemon_timestamp(): """ Try to detect any last timestamp left by the daemon, for instance to get a hint on whether the daemon is running or not. :return: a datetime.datetime object with the most recent time. Return None if no information is found in the DB. """ import datetime # I go low-level here if settings.BACKEND == BACKEND_DJANGO: from aiida.backends.djsite.db.models import DbSetting daemon_timestamps = DbSetting.objects.filter( key__startswith='daemon|task_') timestamps = [] for timestamp_setting in daemon_timestamps: timestamp = timestamp_setting.getvalue() if isinstance(timestamp, datetime.datetime): timestamps.append(timestamp) if timestamps: # The most recent timestamp return max(timestamps) else: return None elif settings.BACKEND == BACKEND_SQLA: from aiida.backends.sqlalchemy.models.settings import DbSetting from aiida.backends.sqlalchemy import session from sqlalchemy import func from pytz import utc from sqlalchemy.dialects.postgresql import TIMESTAMP maxtimestamp, = session.query( func.max(DbSetting.val[()].cast(TIMESTAMP))).filter( DbSetting.key.like("daemon|task%")).first() if maxtimestamp is None: return None else: return utc.localize(maxtimestamp)
def get_log_messages(obj): """ Get the log messages for the object. """ from aiida.backends.sqlalchemy.models.log import DbLog from aiida.backends.sqlalchemy import session extra = get_dblogger_extra(obj) log_messages = [] for log_message in (session.query(DbLog).filter_by( **extra).order_by('time').all()): val_dict = log_message.__dict__ updated_val_dict = { "loggername": val_dict["loggername"], "levelname": val_dict["levelname"], "message": val_dict["message"], "metadata": val_dict["_metadata"], "time": val_dict["time"] } log_messages.append(updated_val_dict) return log_messages
def computer_configure(self, *args): """ Configure the authentication information for a given computer """ if not is_dbenv_loaded(): load_dbenv() import readline import inspect from django.core.exceptions import ObjectDoesNotExist from aiida.common.exceptions import (NotExistent, ValidationError) from aiida.backends.utils import get_automatic_user from aiida.common.utils import get_configured_user_email from aiida.backends.settings import BACKEND from aiida.backends.profile import BACKEND_SQLA, BACKEND_DJANGO import argparse parser = argparse.ArgumentParser( prog=self.get_full_command_name(), description='Configure a computer for a given AiiDA user.') # The default states are those that are shown if no option is given parser.add_argument( '-u', '--user', type=str, metavar='EMAIL', help= "Configure the computer for the given AiiDA user (otherwise, configure the current default user)", ) parser.add_argument( 'computer', type=str, help="The name of the computer that you want to configure") parsed_args = parser.parse_args(args) user_email = parsed_args.user computername = parsed_args.computer try: computer = self.get_computer(name=computername) except NotExistent: print >> sys.stderr, "No computer exists with name '{}'".format( computername) sys.exit(1) if user_email is None: user = get_automatic_user() else: from aiida.orm.querybuilder import QueryBuilder qb = QueryBuilder() qb.append(type="user", filters={'email': user_email}) user = qb.first() if user is None: print >> sys.stderr, ("No user with email '{}' in the " "database.".format(user_email)) sys.exit(1) if BACKEND == BACKEND_DJANGO: from aiida.backends.djsite.db.models import DbAuthInfo try: authinfo = DbAuthInfo.objects.get( dbcomputer=computer.dbcomputer, aiidauser=user) old_authparams = authinfo.get_auth_params() except ObjectDoesNotExist: authinfo = DbAuthInfo(dbcomputer=computer.dbcomputer, aiidauser=user) old_authparams = {} elif BACKEND == BACKEND_SQLA: from aiida.backends.sqlalchemy.models.authinfo import DbAuthInfo from aiida.backends.sqlalchemy import session authinfo = session.query(DbAuthInfo).filter( DbAuthInfo.dbcomputer == computer.dbcomputer).filter( DbAuthInfo.aiidauser == user).first() if authinfo is None: authinfo = DbAuthInfo(dbcomputer=computer.dbcomputer, aiidauser=user) old_authparams = {} else: old_authparams = authinfo.get_auth_params() else: raise Exception("Unknown backend {}".format(BACKEND)) Transport = computer.get_transport_class() print("Configuring computer '{}' for the AiiDA user '{}'".format( computername, user.email)) print "Computer {} has transport of type {}".format( computername, computer.get_transport_type()) if user.email != get_configured_user_email(): print "*" * 72 print "** {:66s} **".format("WARNING!") print "** {:66s} **".format( " You are configuring a different user.") print "** {:66s} **".format( " Note that the default suggestions are taken from your") print "** {:66s} **".format( " local configuration files, so they may be incorrect.") print "*" * 72 valid_keys = Transport.get_valid_auth_params() default_authparams = {} for k in valid_keys: if k in old_authparams: default_authparams[k] = old_authparams.pop(k) if old_authparams: print( "WARNING: the following keys were previously in the " "authorization parameters,") print "but have not been recognized and have been deleted:" print ", ".join(old_authparams.keys()) if not valid_keys: print "There are no special keys to be configured. Configuration completed." authinfo.set_auth_params({}) authinfo.save() return print "" print "Note: to leave a field unconfigured, leave it empty and press [Enter]" # I strip out the old auth_params that are not among the valid keys new_authparams = {} for k in valid_keys: key_set = False while not key_set: try: converter_name = '_convert_{}_fromstring'.format(k) try: converter = dict( inspect.getmembers(Transport))[converter_name] except KeyError: print >> sys.stderr, ( "Internal error! " "No {} defined in Transport {}".format( converter_name, computer.get_transport_type())) sys.exit(1) if k in default_authparams: readline.set_startup_hook(lambda: readline.insert_text( str(default_authparams[k]))) else: # Use suggestion only if parameters were not already set suggester_name = '_get_{}_suggestion_string'.format(k) try: suggester = dict( inspect.getmembers(Transport))[suggester_name] suggestion = suggester(computer) readline.set_startup_hook( lambda: readline.insert_text(suggestion)) except KeyError: readline.set_startup_hook() txtval = raw_input("=> {} = ".format(k)) if txtval: new_authparams[k] = converter(txtval) key_set = True except ValidationError as e: print "Error in the inserted value: {}".format(e.message) authinfo.set_auth_params(new_authparams) authinfo.save() print "Configuration stored for your user on computer '{}'.".format( computername)
def has_parents(self): return session.query(literal(True)).filter( self.dbnode.parent_paths.exists()).scalar() or False
def list_names(cls): from aiida.backends.sqlalchemy import session return session.query(DbComputer.name).all()