def merge(*lists): """ Merge lists while trying to keep the relative order of the elements. Warn if the lists have the same elements in a different relative order. For static assets it can be important to have them included in the DOM in a certain order. In JavaScript you may not be able to reference a global or in CSS you might want to override a style. """ dependency_graph = defaultdict(set) all_items = OrderedSet() for list_ in filter(None, lists): head = list_[0] # The first items depend on nothing but have to be part of the # dependency graph to be included in the result. dependency_graph.setdefault(head, set()) for item in list_: all_items.add(item) # No self dependencies if head != item: dependency_graph[item].add(head) head = item try: return stable_topological_sort(all_items, dependency_graph) except CyclicDependencyError: warnings.warn( "Detected duplicate Media files in an opposite order: {}".format( ", ".join(repr(list_) for list_ in lists) ), MediaOrderConflictWarning, ) return list(all_items)
def merge(*lists): """ Merge lists while trying to keep the relative order of the elements. Warn if the lists have the same elements in a different relative order. For static assets it can be important to have them included in the DOM in a certain order. In JavaScript you may not be able to reference a global or in CSS you might want to override a style. """ dependency_graph = defaultdict(set) all_items = OrderedSet() for list_ in filter(None, lists): head = list_[0] # The first items depend on nothing but have to be part of the # dependency graph to be included in the result. dependency_graph.setdefault(head, set()) for item in list_: all_items.add(item) # No self dependencies if head != item: dependency_graph[item].add(head) head = item try: return stable_topological_sort(all_items, dependency_graph) except CyclicDependencyError: warnings.warn( 'Detected duplicate Media files in an opposite order: {}'.format( ', '.join(repr(l) for l in lists) ), MediaOrderConflictWarning, ) return list(all_items)
def test_basic(self): dependency_graph = { 1: {2, 3}, 2: set(), 3: set(), 4: {5, 6}, 5: set(), 6: {5}, } self.assertEqual(list(topological_sort_as_sets(dependency_graph)), [{2, 3, 5}, {1, 6}, {4}]) self.assertEqual(stable_topological_sort([1, 2, 3, 4, 5, 6], dependency_graph), [2, 3, 5, 1, 6, 4])
def get_sorted_dependencies(service_model): """ Returns list of application models in topological order. It is used in order to correctly delete dependent resources. """ app_models = list(service_model._meta.app_config.get_models()) dependencies = {model: set() for model in app_models} relations = (relation for model in app_models for relation in model._meta.related_objects if relation.on_delete in (models.PROTECT, models.CASCADE)) for rel in relations: dependencies[rel.model].add(rel.related_model) return stable_topological_sort(app_models, dependencies)
def test_basic(self): dependency_graph = { 1: {2, 3}, 2: set(), 3: set(), 4: {5, 6}, 5: set(), 6: {5}, } self.assertEqual(list(topological_sort_as_sets(dependency_graph)), [{2, 3, 5}, {1, 6}, {4}]) self.assertEqual( stable_topological_sort([1, 2, 3, 4, 5, 6], dependency_graph), [2, 3, 5, 1, 6, 4])
def get_executors(cls): # Get cleanup executors from extensions executors = [ extension.get_cleanup_executor() for extension in WaldurExtension.get_extensions() ] # Filter empty items from list because cleanup executor is optional executors = [executor for executor in executors if executor] # Apply topological sort with respect to dependencies between executors dependencies = {} for executor in executors: dependencies[executor] = set() if executor.related_executor: dependencies.setdefault(executor.related_executor, set()) dependencies[executor.related_executor].add(executor) return stable_topological_sort(executors, dependencies)