def test_unconnected_stable(): nodes = list(range(1, 100)) random.shuffle(nodes) graph = Graph() for node in nodes: graph.add_node(node) assert topological_sort(graph) == nodes
def test_topological_sort_chain(): graph = Graph() graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_node(4) graph.add_dependency(2, 1) graph.add_dependency(3, 2) graph.add_dependency(4, 3) assert topological_sort(graph) == [1, 2, 3, 4]
def test_topological_sort_root(): graph = Graph() graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_node(4) graph.add_dependency(1, 4) graph.add_dependency(2, 4) graph.add_dependency(3, 4) assert topological_sort(graph) == [4, 1, 2, 3]
def test_topological_sort_tree(): graph = Graph() graph.add_node(1) graph.add_node(2) graph.add_node(3) graph.add_node(4) graph.add_node(5) graph.add_dependency(3, 2) graph.add_dependency(5, 4) graph.add_dependency(5, 3) assert topological_sort(graph) == [1, 2, 3, 4, 5]
def test_random_stable(): nodes = list(range(100)) random.shuffle(nodes) graph = Graph() for node in nodes: graph.add_node(node) for _ in range(200): src_index = random.randrange(1, 100) tgt_index = random.randrange(src_index) graph.add_dependency(nodes[src_index], nodes[tgt_index]) assert topological_sort(graph) == nodes
def ssort( text, *, filename="<unknown>", on_unknown_encoding_error="raise", on_decoding_error="raise", on_parse_error="raise", on_unresolved="raise", on_wildcard_import="raise", ): on_unknown_encoding_error = _interpret_on_unknown_encoding_action( on_unknown_encoding_error) on_decoding_error = _interpret_on_decoding_error_action(on_decoding_error) on_parse_error = _interpret_on_parse_error_action(on_parse_error) on_unresolved = _interpret_on_unresolved_action(on_unresolved) on_wildcard_import = _interpret_on_wildcard_import_action( on_wildcard_import) try: encoding = None if isinstance(text, bytes): encoding = detect_encoding(text) text = text.decode(encoding) except UnknownEncodingError as exc: on_unknown_encoding_error(str(exc), encoding=exc.encoding) return text except UnicodeDecodeError as exc: on_decoding_error(str(exc)) return text newline = detect_newline(text) text = normalize_newlines(text) try: statements = list(parse(text, filename=filename)) except ParseError as exc: on_parse_error(str(exc), lineno=exc.lineno, col_offset=exc.col_offset) return text if not statements: return text graph = module_statements_graph( statements, on_unresolved=on_unresolved, on_wildcard_import=on_wildcard_import, ) if graph is None: return text replace_cycles(graph, key=sort_key_from_iter(statements)) sorted_statements = topological_sort(statements, graph=graph) assert is_topologically_sorted(sorted_statements, graph=graph) output = "\n".join( statement_text_sorted(statement) for statement in sorted_statements) if output: output += "\n" if newline != "\n": output = re.sub("\n", newline, output) if encoding is not None: output = output.encode(encoding) return output
def _statement_text_sorted_class(statement): head_text, statements = split_class(statement) # Take a snapshot of any hard dependencies between statements so that we can # restore them later. initialisation_graph = class_statements_initialisation_graph(statements) # === Split up the statements into high level groups ======================= if _is_string(statements[0]): docstrings, statements = statements[:1], statements[1:] else: docstrings = [] special_properties, statements = _partition(statements, _is_special_property) lifecycle_operations, statements = _partition(statements, _is_lifecycle_operation) regular_operations, statements = _partition(statements, _is_regular_operation) inner_classes, statements = _partition(statements, _is_class) properties, statements = _partition(statements, _is_property) methods, statements = statements, [] sorted_statements = [] # === Join groups back together in the correct order ======================= sorted_statements += docstrings # Special properties (in hard-coded order). sorted_statements += sorted( special_properties, key=_statement_binding_sort_key( sort_key_from_iter(SPECIAL_PROPERTIES)), ) # Inner classes (in original order). sorted_statements += inner_classes # Regular properties (in original order). sorted_statements += properties # Special lifecycle methods (in hard-coded order). sorted_statements += sorted( lifecycle_operations, key=_statement_binding_sort_key( sort_key_from_iter(LIFECYCLE_OPERATIONS)), ) # Regular methods. sorted_statements += methods # Special operations (in hard-coded order). sorted_statements += sorted( regular_operations, key=_statement_binding_sort_key( sort_key_from_iter(REGULAR_OPERATIONS)), ) # === Re-sort based on dependencies between statements ===================== # Fix any hard dependencies. sorted_statements = topological_sort(sorted_statements, graph=initialisation_graph) # Attempt to resolve soft dependencies on private attributes, but with hard # dependencies taking priority, and always preserving the original order # where there are cycles. runtime_graph = class_statements_runtime_graph(sorted_statements, ignore_public=True) runtime_graph.update(initialisation_graph) replace_cycles(runtime_graph, key=sort_key_from_iter(sorted_statements)) sorted_statements = topological_sort(sorted_statements, graph=runtime_graph) return (head_text + "\n" + "\n".join( statement_text_sorted(body_statement) for body_statement in sorted_statements))