def compile_binary(binary): """Assemble a SyncRule given a single binary condition.""" if binary.operator != operators.eq or not isinstance( binary.left, schema.Column) or not isinstance( binary.right, schema.Column): return source_column = None dest_column = None if foreign_keys is None: if binary.left.table == binary.right.table: raise exceptions.ArgumentError( "need foreign_keys argument for self-referential sync") if binary.left in util.Set( [f.column for f in binary.right.foreign_keys]): dest_column = binary.right source_column = binary.left elif binary.right in util.Set( [f.column for f in binary.left.foreign_keys]): dest_column = binary.left source_column = binary.right else: if binary.left in foreign_keys: source_column = binary.right dest_column = binary.left elif binary.right in foreign_keys: source_column = binary.left dest_column = binary.right if source_column and dest_column: if self.direction == ONETOMANY: self.syncrules.append( SyncRule(self.parent_mapper, source_column, dest_column, dest_mapper=self.child_mapper)) elif self.direction == MANYTOONE: self.syncrules.append( SyncRule(self.child_mapper, source_column, dest_column, dest_mapper=self.parent_mapper)) else: if not issecondary: self.syncrules.append( SyncRule(self.parent_mapper, source_column, dest_column, dest_mapper=self.child_mapper, issecondary=issecondary)) else: self.syncrules.append( SyncRule(self.child_mapper, source_column, dest_column, dest_mapper=self.parent_mapper, issecondary=issecondary))
def _sort(tuples, allitems, allow_cycles=False, ignore_self_cycles=False): nodes = {} edges = _EdgeCollection() for item in list(allitems) + [t[0] for t in tuples] + [t[1] for t in tuples]: if id(item) not in nodes: node = _Node(item) nodes[item] = node for t in tuples: if t[0] is t[1]: if allow_cycles: n = nodes[t[0]] n.cycles = util.Set([n]) elif not ignore_self_cycles: raise CircularDependencyError("Self-referential dependency detected " + repr(t)) continue childnode = nodes[t[1]] parentnode = nodes[t[0]] edges.add((parentnode, childnode)) queue = [] for n in nodes.values(): if not edges.has_parents(n): queue.append(n) output = [] while nodes: if not queue: # edges remain but no edgeless nodes to remove; this indicates # a cycle if allow_cycles: for cycle in _find_cycles(edges): lead = cycle[0][0] lead.cycles = util.Set() for edge in cycle: n = edges.remove(edge) lead.cycles.add(edge[0]) lead.cycles.add(edge[1]) if n is not None: queue.append(n) for n in lead.cycles: if n is not lead: n._cyclical = True for (n,k) in list(edges.edges_by_parent(n)): edges.add((lead, k)) edges.remove((n,k)) continue else: # long cycles not allowed raise CircularDependencyError("Circular dependency detected " + repr(edges) + repr(queue)) node = queue.pop() if not hasattr(node, '_cyclical'): output.append(node) del nodes[node.item] for childnode in edges.pop_node(node): queue.append(childnode) return output
def __init__(self, session): if session.weak_identity_map: self.identity_map = attributes.InstanceDict() else: self.identity_map = {} self.new = util.Set() #OrderedSet() self.deleted = util.Set() self.logger = logging.instance_logger(self, echoflag=session.echo_uow)
def _determine_remote_side(self): if not self.remote_side: if self.direction is sync.MANYTOONE: self.remote_side = util.Set(self._opposite_side) elif self.direction is sync.ONETOMANY or self.direction is sync.MANYTOMANY: self.remote_side = util.Set(self.foreign_keys) self.local_side = util.Set(self._opposite_side).union( util.Set(self.foreign_keys)).difference(self.remote_side)
def __init__(self, identity_map=None): if identity_map is not None: self.identity_map = identity_map else: self.identity_map = weakref.WeakValueDictionary() self.new = util.OrderedSet() self.dirty = util.Set() self.deleted = util.Set()
def flush(self, session, objects=None): # this context will track all the objects we want to save/update/delete, # and organize a hierarchical dependency structure. it also handles # communication with the mappers and relationships to fire off SQL # and synchronize attributes between related objects. echo = logging.is_info_enabled(self.logger) flush_context = UOWTransaction(self, session) # create the set of all objects we want to operate upon if objects is not None: # specific list passed in objset = util.Set(objects) else: # or just everything objset = util.Set(self.identity_map.values()).union(self.new) # detect persistent objects that have changes dirty = self.locate_dirty() # store objects whose fate has been decided processed = util.Set() # put all saves/updates into the flush context. detect orphans and throw them into deleted. for obj in self.new.union(dirty).intersection(objset).difference( self.deleted): if obj in processed: continue if object_mapper(obj)._is_orphan(obj): for c in [obj] + list( object_mapper(obj).cascade_iterator('delete', obj)): if c in processed: continue flush_context.register_object(c, isdelete=True) processed.add(c) else: flush_context.register_object(obj) processed.add(obj) # put all remaining deletes into the flush context. for obj in self.deleted: if (objset is not None and not obj in objset) or obj in processed: continue flush_context.register_object(obj, isdelete=True) trans = session.create_transaction(autoflush=False) flush_context.transaction = trans try: flush_context.execute() except: trans.rollback() raise trans.commit() flush_context.post_exec()
def add(self, edge): """Add an edge to this collection.""" (parentnode, childnode) = edge if parentnode not in self.parent_to_children: self.parent_to_children[parentnode] = util.Set() self.parent_to_children[parentnode].add(childnode) if childnode not in self.child_to_parents: self.child_to_parents[childnode] = util.Set() self.child_to_parents[childnode].add(parentnode) parentnode.dependencies.add(childnode)
def __init__(self, identity_map=None, weak_identity_map=False): if identity_map is not None: self.identity_map = identity_map else: if weak_identity_map: self.identity_map = weakref.WeakValueDictionary() else: self.identity_map = {} self.new = util.Set() #OrderedSet() self.deleted = util.Set() self.logger = logging.instance_logger(self)
def process_query_property(self, query, paths): if self.lazy: if paths[-1] in query._eager_loaders: query._eager_loaders = query._eager_loaders.difference(util.Set([paths[-1]])) else: if not self.chained: paths = [paths[-1]] res = util.Set() for path in paths: if len(path) - len(query._current_path) == 2: res.add(path) query._eager_loaders = query._eager_loaders.union(res) super(EagerLazyOption, self).process_query_property(query, paths)
def __init__(self, engine, proxy, connection, checkfirst=False, tables=None, **kwargs): super(ANSISchemaGenerator, self).__init__(engine, proxy, **kwargs) self.checkfirst = checkfirst self.tables = tables and util.Set(tables) or None self.connection = connection self.preparer = self.engine.dialect.preparer() self.dialect = self.engine.dialect
def visit_update(self, update_stmt): # scan the table's columns for onupdates that have to be pre-set for an UPDATE # add these columns to the parameter list via visit_update_XXX methods default_params = {} class OnUpdateVisitor(schema.SchemaVisitor): def visit_column_onupdate(s, cd): self.visit_update_column_default(c, cd, default_params) vis = OnUpdateVisitor() for c in update_stmt.table.c: if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): c.accept_schema_visitor(vis) self.isupdate = True colparams = self._get_colparams(update_stmt, default_params) self.inline_params = util.Set() def create_param(col, p): if isinstance(p, sql._BindParamClause): self.binds[p.key] = p self.binds[p.shortname] = p return self.bindparam_string(p.key) else: p.accept_visitor(self) self.inline_params.add(col) if isinstance(p, sql.ClauseElement) and not isinstance(p, sql.ColumnElement): return "(" + self.get_str(p) + ")" else: return self.get_str(p) text = "UPDATE " + self.preparer.format_table(update_stmt.table) + " SET " + string.join(["%s=%s" % (self.preparer.format_column(c[0]), create_param(*c)) for c in colparams], ', ') if update_stmt.whereclause: text += " WHERE " + self.get_str(update_stmt.whereclause) self.strings[update_stmt] = text
def polymorphic_union(table_map, typecolname, aliasname='p_union'): colnames = util.Set() colnamemaps = {} types = {} for key in table_map.keys(): table = table_map[key] # mysql doesnt like selecting from a select; make it an alias of the select if isinstance(table, sql.Select): table = table.alias() table_map[key] = table m = {} for c in table.c: colnames.add(c.name) m[c.name] = c types[c.name] = c.type colnamemaps[table] = m def col(name, table): try: return colnamemaps[table][name] except KeyError: return sql.cast(sql.null(), types[name]).label(name) result = [] for type, table in table_map.iteritems(): if typecolname is not None: result.append(sql.select([col(name, table) for name in colnames] + [sql.column("'%s'" % type).label(typecolname)], from_obj=[table])) else: result.append(sql.select([col(name, table) for name in colnames], from_obj=[table])) return sql.union_all(*result).alias(aliasname)
def __init__(self, arg=""): values = util.Set([c.strip() for c in arg.split(',')]) self.delete_orphan = "delete-orphan" in values self.delete = "delete" in values or self.delete_orphan or "all" in values self.save_update = "save-update" in values or "all" in values self.merge = "merge" in values or "all" in values self.expunge = "expunge" in values or "all" in values
def flush(self, session, objects=None, echo=False): flush_context = UOWTransaction(self, session) if objects is not None: objset = util.Set(objects) else: objset = None for obj in [n for n in self.new] + [d for d in self.dirty]: if objset is not None and not obj in objset: continue if obj in self.deleted: continue flush_context.register_object(obj) for obj in self.deleted: if objset is not None and not obj in objset: continue flush_context.register_object(obj, isdelete=True) trans = session.create_transaction(autoflush=False) flush_context.transaction = trans try: flush_context.execute(echo=echo) trans.commit() except: trans.rollback() raise flush_context.post_exec()
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, 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 assert_sort(self, tuples, node, collection=None): print str(node) def assert_tuple(tuple, node): if node.cycles: cycles = [i.item for i in node.cycles] else: cycles = [] if tuple[0] is node.item or tuple[0] in cycles: tuple.pop() if tuple[0] is node.item or tuple[0] in cycles: return elif len(tuple) > 1 and tuple[1] is node.item: assert False, "Tuple not in dependency tree: " + str(tuple) for c in node.children: assert_tuple(tuple, c) for tuple in tuples: assert_tuple(list(tuple), node) if collection is None: collection = [] items = util.Set() def assert_unique(node): for item in [n.item for n in node.cycles or [node,]]: assert item not in items items.add(item) if item in collection: collection.remove(item) for c in node.children: assert_unique(c) assert_unique(node) assert len(collection) == 0
def __init__(self, mapper, options): self.mapper = mapper self.options = options self.attributes = {} self.recursion_stack = util.Set() for opt in util.flatten_iterator(options): self.accept_option(opt)
def merge(self, object, entity_name=None, _recursive=None): """Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with ``cascade="merge"``. """ if _recursive is None: _recursive = util.Set() mapper = _object_mapper(object) key = getattr(object, '_instance_key', None) if key is None: merged = mapper._create_instance(self) else: if key in self.identity_map: merged = self.identity_map[key] else: merged = self.get(mapper.class_, key[1]) for prop in mapper.props.values(): prop.merge(self, object, merged, _recursive) if key is None: self.save(merged) return merged
def intersection_update(self, other): want, have = self.intersection(other), sautil.Set(self) remove, add = have - want, want - have for item in remove: self.remove(item) for item in add: self.add(item)
def symmetric_difference_update(self, other): want, have = self.symmetric_difference(other), sautil.Set(self) remove, add = have - want, want - have for item in remove: self.remove(item) for item in add: self.add(item)
def _get_noninheriting_mappers(self): """returns a list of UOWTasks whose mappers are not inheriting from the mapper of another UOWTask. i.e., this returns the root UOWTasks for all the inheritance hierarchies represented in this UOWTransaction.""" mappers = util.Set() for task in self.tasks.values(): base = task.mapper.base_mapper() mappers.add(base) return mappers
def find_columns(clause): cols = util.Set() def visit_column(col): cols.add(col) visitors.traverse(clause, visit_column=visit_column) return cols
def traverse(self, elem, clone=True): if not clone: raise exceptions.ArgumentError( "AbstractClauseProcessor 'clone' argument must be True") return self._traverse(elem, util.Set(self.stop_on or []), {}, _clone_toplevel=True)
def all_deps(self): """Return a set of dependencies for this node and all its cycles.""" deps = util.Set(self.dependencies) if self.cycles is not None: for c in self.cycles: deps.update(c.dependencies) return deps
def _organize_as_tree(nodes): """Given a list of nodes from a topological sort, organize the nodes into a tree structure, with as many non-dependent nodes set as siblings to each other as possible. returns nodes as 3-tuples (item, cycles, children). """ if not nodes: return None # a list of all currently independent subtrees as a tuple of # (root_node, set_of_all_tree_nodes, set_of_all_cycle_nodes_in_tree) # order of the list has no semantics for the algorithmic independents = [] # in reverse topological order for node in util.reversed(nodes): # nodes subtree and cycles contain the node itself subtree = util.Set([node]) if node.cycles is not None: cycles = util.Set(node.cycles) else: cycles = util.Set() # get a set of dependent nodes of node and its cycles nodealldeps = node.all_deps() if nodealldeps: # iterate over independent node indexes in reverse order so we can efficiently remove them for index in xrange(len(independents)-1,-1,-1): child, childsubtree, childcycles = independents[index] # if there is a dependency between this node and an independent node if (childsubtree.intersection(nodealldeps) or childcycles.intersection(node.dependencies)): # prepend child to nodes children # (append should be fine, but previous implemetation used prepend) node.children[0:0] = [(child.item, [n.item for n in child.cycles or []], child.children)] # merge childs subtree and cycles subtree.update(childsubtree) cycles.update(childcycles) # remove the child from list of independent subtrees independents[index:index+1] = [] # add node as a new independent subtree independents.append((node,subtree,cycles)) # choose an arbitrary node from list of all independent subtrees head = independents.pop()[0] # add all other independent subtrees as a child of the chosen root # used prepend [0:0] instead of extend to maintain exact behaviour of previous implementation head.children[0:0] = [(i[0].item, [n.item for n in i[0].cycles or []], i[0].children) for i in independents] return (head.item, [n.item for n in head.cycles or []], head.children)
def __init__(self, uowtransaction, mapper, base_task=None): # the transaction owning this UOWTask self.uowtransaction = uowtransaction # base_task is the UOWTask which represents the "base mapper" # in our mapper's inheritance chain. if the mapper does not # inherit from any other mapper, the base_task is self. # the _inheriting_tasks dictionary is a dictionary present only # on the "base_task"-holding UOWTask, which maps all mappers within # an inheritance hierarchy to their corresponding UOWTask instances. if base_task is None: self.base_task = self self._inheriting_tasks = {mapper: self} else: self.base_task = base_task base_task._inheriting_tasks[mapper] = self # the Mapper which this UOWTask corresponds to self.mapper = mapper # a dictionary mapping object instances to a corresponding UOWTaskElement. # Each UOWTaskElement represents one object instance which is to be saved or # deleted by this UOWTask's Mapper. # in the case of the row-based "cyclical sort", the UOWTaskElement may # also reference further UOWTasks which are dependent on that UOWTaskElement. self._objects = {} # a set of UOWDependencyProcessor instances, which are executed after saves and # before deletes, to synchronize data between dependent objects as well as to # ensure that relationship cascades populate the flush() process with all # appropriate objects. self._dependencies = util.Set() # a list of UOWTasks which are sub-nodes to this UOWTask. this list # is populated during the dependency sorting operation. self.childtasks = [] # a list of UOWDependencyProcessor instances # which derive from the UOWDependencyProcessor instances present in a # corresponding UOWTask's "_dependencies" set. This collection is populated # during a row-based cyclical sorting operation and only corresponds to # new UOWTask instances created during this operation, which are also local # to the dependency graph (i.e. they are not present in the get_task_by_mapper() # collection). self._cyclical_dependencies = util.Set()
def unmodified(self): """a set of keys which have no uncommitted changes""" return util.Set([ attr.impl.key for attr in _managed_attributes(self.class_) if attr.impl.key not in self.committed_state and ( not hasattr(attr.impl, 'commit_to_state') or not attr.impl.check_mutable_modified(self)) ])
def intersection_update(self, other): want, have = self.intersection(other), util.Set(self) remove, add = have - want, want - have for value in remove: self.remove(value) for value in add: self.add(value)
def symmetric_difference_update(self, other): want, have = self.symmetric_difference(other), util.Set(self) remove, add = have - want, want - have for value in remove: self.remove(value) for value in add: self.add(value)
def close(self): if self.__parent is not None: return for t in util.Set(self.__connections.values()): if t[2]: t[0].close() else: t[1].close() self.session.transaction = None