def selectone_by(self, *args, **params): """works like selectfirst_by(), but throws an error if not exactly one result was returned.""" ret = self.select_whereclause(self.join_by(*args, **params), limit=2) if len(ret) == 1: return ret[0] elif len(ret) == 0: raise exceptions.InvalidRequestError( 'No rows returned for selectone_by') else: raise exceptions.InvalidRequestError( 'Multiple rows returned for selectone_by')
def selectone(self, *args, **params): """works like selectfirst(), but throws an error if not exactly one result was returned.""" ret = list(self.select(*args, **params)[0:2]) if len(ret) == 1: return ret[0] elif len(ret) == 0: raise exceptions.InvalidRequestError( 'No rows returned for selectone_by') else: raise exceptions.InvalidRequestError( 'Multiple rows returned for selectone')
def refresh(self, obj): """reload the attributes for the given object from the database, clear any changes made.""" self._validate_persistent(obj) if self.query(obj.__class__)._get(obj._instance_key, reload=True) is None: raise exceptions.InvalidRequestError( "Could not refresh instance '%s'" % repr(obj))
def _update_impl(self, object, **kwargs): if self._is_attached(object) and object not in self.deleted: return if not hasattr(object, '_instance_key'): raise exceptions.InvalidRequestError( "Instance '%s' is not persisted" % repr(object)) self._attach(object)
def invalidate(self): if self.connection is None: raise exceptions.InvalidRequestError("This connection is closed") self._connection_record.invalidate() self.connection = None self._cursors = None self._close()
def get_bind(self, mapper): """return the Engine or Connection which is used to execute statements on behalf of the given Mapper. Calling connect() on the return result will always result in a Connection object. This method disregards any SessionTransaction that may be in progress. The order of searching is as follows: if an Engine or Connection was bound to this Mapper specifically within this Session, returns that Engine or Connection. if an Engine or Connection was bound to this Mapper's underlying Table within this Session (i.e. not to the Table directly), returns that Engine or Conneciton. if an Engine or Connection was bound to this Session, returns that Engine or Connection. finally, returns the Engine which was bound directly to the Table's MetaData object. If no Engine is bound to the Table, an exception is raised. """ if mapper is None: return self.bind_to elif self.binds.has_key(mapper): return self.binds[mapper] elif self.binds.has_key(mapper.mapped_table): return self.binds[mapper.mapped_table] elif self.bind_to is not None: return self.bind_to else: e = mapper.mapped_table.engine if e is None: raise exceptions.InvalidRequestError( "Could not locate any Engine bound to mapper '%s'" % str(mapper)) return e
def _locate_prop(self, key, start=None): import properties keys = [] seen = util.Set() def search_for_prop(mapper_): if mapper_ in seen: return None seen.add(mapper_) if mapper_.props.has_key(key): prop = mapper_.props[key] if isinstance(prop, properties.SynonymProperty): prop = mapper_.props[prop.name] if isinstance(prop, properties.PropertyLoader): keys.insert(0, prop.key) return prop else: for prop in mapper_.props.values(): if not isinstance(prop, properties.PropertyLoader): continue x = search_for_prop(prop.mapper) if x: keys.insert(0, prop.key) return x else: return None p = search_for_prop(start or self.mapper) if p is None: raise exceptions.InvalidRequestError( "Cant locate property named '%s'" % key) return [keys, p]
def lazyload(): if self._should_log_debug: self.logger.debug("deferred load %s group %s" % (mapperutil.attribute_str( instance, self.key), str(self.group))) try: pk = self.parent.pks_by_table[self.columns[0].table] except KeyError: pk = self.columns[0].table.primary_key clause = sql.and_() for primary_key in pk: attr = self.parent.get_attr_by_column(instance, primary_key) if not attr: return None clause.clauses.append(primary_key == attr) session = sessionlib.object_session(instance) if session is None: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) localparent = mapper.object_mapper(instance) if self.group is not None: groupcols = [ p for p in localparent.props.values() if isinstance(p.strategy, DeferredColumnLoader) and p.group == self.group ] result = session.execute( localparent, sql.select([g.columns[0] for g in groupcols], clause, use_labels=True), None) try: row = result.fetchone() for prop in groupcols: if prop is self: continue # set a scalar object instance directly on the object, # bypassing SmartProperty event handlers. sessionlib.attribute_manager.init_instance_attribute( instance, prop.key, uselist=False) instance.__dict__[prop.key] = row[prop.columns[0]] return row[self.columns[0]] finally: result.close() else: return session.scalar( localparent, sql.select([self.columns[0]], clause, use_labels=True), None)
def create(self, name_or_url, **kwargs): # create url.URL object u = url.make_url(name_or_url) # get module from sqlalchemy.databases module = u.get_module() dialect_args = {} # consume dialect arguments from kwargs for k in util.get_cls_kwargs(module.dialect): if k in kwargs: dialect_args[k] = kwargs.pop(k) # create dialect dialect = module.dialect(**dialect_args) # assemble connection arguments (cargs, cparams) = dialect.create_connect_args(u) cparams.update(kwargs.pop('connect_args', {})) # look for existing pool or create pool = kwargs.pop('pool', None) if pool is None: dbapi = kwargs.pop('module', dialect.dbapi()) if dbapi is None: raise exceptions.InvalidRequestError( "Cant get DBAPI module for dialect '%s'" % dialect) def connect(): try: return dbapi.connect(*cargs, **cparams) except Exception, e: raise exceptions.DBAPIError("Connection failed", e) creator = kwargs.pop('creator', connect) poolclass = kwargs.pop( 'poolclass', getattr(module, 'poolclass', poollib.QueuePool)) pool_args = {} # consume pool arguments from kwargs, translating a few of the arguments for k in util.get_cls_kwargs(poolclass): tk = { 'echo': 'echo_pool', 'timeout': 'pool_timeout', 'recycle': 'pool_recycle' }.get(k, k) if tk in kwargs: pool_args[k] = kwargs.pop(tk) pool_args['use_threadlocal'] = self.pool_threadlocal() pool = poolclass(creator, **pool_args)
def load(self, ident, **kwargs): """return an instance of the object based on the given identifier. If not found, raises an exception. The method will *remove all pending changes* to the object already existing in the Session. The ident argument is a scalar or tuple of primary key column values in the order of the table def's primary key columns.""" ret = self.extension.load(self, ident, **kwargs) if ret is not mapper.EXT_PASS: return ret key = self.mapper.identity_key(ident) instance = self._get(key, ident, reload=True, **kwargs) if instance is None: raise exceptions.InvalidRequestError( "No instance found for identity %s" % repr(ident)) return instance
def _save_impl(self, object, **kwargs): if hasattr(object, '_instance_key'): if not self.identity_map.has_key(object._instance_key): raise exceptions.InvalidRequestError( "Instance '%s' is a detached instance or is already persistent in a different Session" % repr(object)) else: m = _class_mapper(object.__class__, entity_name=kwargs.get('entity_name', None)) # this would be a nice exception to raise...however this is incompatible with a contextual # session which puts all objects into the session upon construction. #if m._is_orphan(object): # raise exceptions.InvalidRequestError("Instance '%s' is an orphan, and must be attached to a parent object to be saved" % (repr(object))) m._assign_entity_name(object) self._register_pending(object)
def _attach(self, obj): """Attach the given object to this Session.""" if getattr(obj, '_sa_session_id', None) != self.hash_key: old = getattr(obj, '_sa_session_id', None) if old is not None and _sessions.has_key(old): raise exceptions.InvalidRequestError( "Object '%s' is already attached to session '%s' (this is '%s')" % (repr(obj), old, id(self))) # auto-removal from the old session is disabled. but if we decide to # turn it back on, do it as below: gingerly since _sessions is a WeakValueDict # and it might be affected by other threads #try: # sess = _sessions[old] #except KeyError: # sess = None #if sess is not None: # sess.expunge(old) key = getattr(obj, '_instance_key', None) if key is not None: self.identity_map[key] = obj obj._sa_session_id = self.hash_key
def _close(self): if self._cursors is not None: # cursors should be closed before connection is returned to the pool. some dbapis like # mysql have real issues if they are not. if self.__pool.auto_close_cursors: self.close_open_cursors() elif self.__pool.disallow_open_cursors: if len(self._cursors): raise exceptions.InvalidRequestError("This connection still has %d open cursors" % len(self._cursors)) if self.connection is not None: try: self.connection.rollback() except: if self._connection_record is not None: self._connection_record.invalidate() if self._connection_record is not None: if self.__pool.echo: self.__pool.log("Connection %s being returned to pool" % repr(self.connection)) self.__pool.return_conn(self) self.connection = None self._connection_record = None self._threadfairy = None self._cursors = None
def _executioncontext(self): try: return self.__executioncontext except AttributeError: raise exceptions.InvalidRequestError("This ResultProxy does not have an execution context with which to complete this operation. Execution contexts are not generated for literal SQL execution.")
def lazyload(): self.logger.debug("lazy load attribute %s on instance %s" % (self.key, mapperutil.instance_str(instance))) params = {} allparams = True # if the instance wasnt loaded from the database, then it cannot lazy load # child items. one reason for this is that a bi-directional relationship # will not update properly, since bi-directional uses lazy loading functions # in both directions, and this instance will not be present in the lazily-loaded # results of the other objects since its not in the database if not mapper.has_identity(instance): return None #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds for col, bind in self.lazybinds.iteritems(): params[bind.key] = self.parent.get_attr_by_column( instance, col) if params[bind.key] is None: allparams = False break if not allparams: return None session = sessionlib.object_session(instance) if session is None: try: session = mapper.object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError( "Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) # if we have a simple straight-primary key load, use mapper.get() # to possibly save a DB round trip if self.use_get: ident = [] for primary_key in self.mapper.pks_by_table[ self.mapper.mapped_table]: bind = self.lazyreverse[primary_key] ident.append(params[bind.key]) return session.query(self.mapper).get(ident) elif self.order_by is not False: order_by = self.order_by elif self.secondary is not None and self.secondary.default_order_by( ) is not None: order_by = self.secondary.default_order_by() else: order_by = False result = session.query(self.mapper, with_options=options).select_whereclause( self.lazywhere, order_by=order_by, params=params) if self.uselist: return result else: if len(result): return result[0] else: return None
def checkout(self): if self.connection is None: raise exceptions.InvalidRequestError("This connection is closed") self.__counter +=1 return self
def setup_query(self, context, eagertable=None, parentclauses=None, parentmapper=None, **kwargs): """add a left outer join to the statement thats being constructed""" if parentmapper is None: localparent = context.mapper else: localparent = parentmapper if self.mapper in context.recursion_stack: return else: context.recursion_stack.add(self.parent) statement = context.statement if hasattr(statement, '_outerjoin'): towrap = statement._outerjoin elif isinstance(localparent.mapped_table, schema.Table): # if the mapper is against a plain Table, look in the from_obj of the select statement # to join against whats already there. for (fromclause, finder) in [(x, sql_util.TableFinder(x)) for x in statement.froms]: # dont join against an Alias'ed Select. we are really looking either for the # table itself or a Join that contains the table. this logic still might need # adjustments for scenarios not thought of yet. if not isinstance( fromclause, sql.Alias) and localparent.mapped_table in finder: towrap = fromclause break else: raise exceptions.InvalidRequestError( "EagerLoader cannot locate a clause with which to outer join to, in query '%s' %s" % (str(statement), self.localparent.mapped_table)) else: # if the mapper is against a select statement or something, we cant handle that at the # same time as a custom FROM clause right now. towrap = localparent.mapped_table try: clauses = self.clauses[parentclauses] except KeyError: clauses = EagerLoader.AliasedClauses(self, parentclauses) self.clauses[parentclauses] = clauses self.clauses_by_lead_mapper[context.mapper] = clauses if self.secondaryjoin is not None: statement._outerjoin = sql.outerjoin( towrap, clauses.eagersecondary, clauses.eagerprimary).outerjoin(clauses.eagertarget, clauses.eagersecondaryjoin) if self.order_by is False and self.secondary.default_order_by( ) is not None: statement.order_by(*clauses.eagersecondary.default_order_by()) else: statement._outerjoin = towrap.outerjoin(clauses.eagertarget, clauses.eagerprimary) if self.order_by is False and clauses.eagertarget.default_order_by( ) is not None: statement.order_by(*clauses.eagertarget.default_order_by()) if clauses.eager_order_by: statement.order_by(*util.to_list(clauses.eager_order_by)) elif getattr(statement, 'order_by_clause', None): clauses._aliasize_orderby(statement.order_by_clause, False) statement.append_from(statement._outerjoin) for value in self.select_mapper.props.values(): value.setup(context, eagertable=clauses.eagertarget, parentclauses=clauses, parentmapper=self.select_mapper)
def _validate_attached(self, obj): """validate that the given object is either pending or persistent within this Session.""" if not self._is_attached(obj): raise exceptions.InvalidRequestError( "Instance '%s' not attached to this Session" % repr(obj))
def _get_connection(self): try: return self.__connection except AttributeError: raise exceptions.InvalidRequestError("This Connection is closed")
def commit(self): if not self.__parent.__is_active: raise exceptions.InvalidRequestError("This transaction is inactive") if self.__parent is self: self.__connection._commit_impl() self.__is_active = False
def add(self, connectable): if self.connections.has_key(connectable.engine): raise exceptions.InvalidRequestError( "Session already has a Connection associated for the given Connection's Engine" ) return self.get_or_add(connectable)
def exp(): if self.query(obj.__class__)._get(obj._instance_key, reload=True) is None: raise exceptions.InvalidRequestError( "Could not refresh instance '%s'" % repr(obj))
def convert_result_value(self, arg, engine): raise exceptions.InvalidRequestError("Ambiguous column name '%s' in result set! try 'use_labels' option on select statement." % (self.key))