@@ -522,54 +522,46 @@ The :mod:`functools` module defines the following functions:
522
522
523
523
Provides functionality to topologically sort a graph of hashable nodes.
524
524
525
- A topological order is a linear ordering of the vertices in a graph such that for
526
- every directed edge u -> v from vertex u to vertex v, vertex u comes before vertex
527
- v in the ordering. For instance, the vertices of the graph may represent tasks to
528
- be performed, and the edges may represent constraints that one task must be
529
- performed before another; in this example, a topological ordering is just a valid
530
- sequence for the tasks. A complete topological ordering is possible if and only if
531
- the graph has no directed cycles, that is, if it is a directed acyclic graph.
532
-
533
- If the optional *graph * argument is provided it must be a dictionary representing
534
- a directed acyclic graph where the keys are nodes and the values are iterables of
535
- all predecessors of that node in the graph (the nodes that have edges that point
536
- to the value in the key). Additional nodes can be added to the graph using the
537
- :meth: `~TopologicalSorter.add ` method.
538
-
539
- In the general case, the steps required to perform the sorting of a given graph
540
- are as follows:
541
-
542
- * Create an instance of the :class: `TopologicalSorter ` with an optional initial graph.
525
+ A topological order is a linear ordering of the vertices in a graph such that
526
+ for every directed edge u -> v from vertex u to vertex v, vertex u comes
527
+ before vertex v in the ordering. For instance, the vertices of the graph may
528
+ represent tasks to be performed, and the edges may represent constraints that
529
+ one task must be performed before another; in this example, a topological
530
+ ordering is just a valid sequence for the tasks. A complete topological
531
+ ordering is possible if and only if the graph has no directed cycles, that
532
+ is, if it is a directed acyclic graph.
533
+
534
+ If the optional *graph * argument is provided it must be a dictionary
535
+ representing a directed acyclic graph where the keys are nodes and the values
536
+ are iterables of all predecessors of that node in the graph (the nodes that
537
+ have edges that point to the value in the key). Additional nodes can be added
538
+ to the graph using the :meth: `~TopologicalSorter.add ` method.
539
+
540
+ In the general case, the steps required to perform the sorting of a given
541
+ graph are as follows:
542
+
543
+ * Create an instance of the :class: `TopologicalSorter ` with an optional
544
+ initial graph.
543
545
* Add additional nodes to the graph.
544
546
* Call :meth: `~TopologicalSorter.prepare ` on the graph.
545
- * While :meth: `~TopologicalSorter.is_active ` is ``True ``, iterate over the
546
- nodes returned by :meth: `~TopologicalSorter.get_ready ` and process them.
547
- Call :meth: `~TopologicalSorter.done ` on each node as it finishes processing.
547
+ * While :meth: `~TopologicalSorter.is_active ` is ``True ``, iterate over
548
+ the nodes returned by :meth: `~TopologicalSorter.get_ready ` and
549
+ process them. Call :meth: `~TopologicalSorter.done ` on each node as it
550
+ finishes processing.
548
551
549
552
In case just an immediate sorting of the nodes in the graph is required and
550
- no parallelism is involved, the convenience method :meth: `TopologicalSorter.static_order `
551
- can be used directly. For example, this method can be used to implement a simple
552
- version of the C3 linearization algorithm used by Python to calculate the Method
553
- Resolution Order (MRO) of a derived class:
553
+ no parallelism is involved, the convenience method
554
+ :meth: `TopologicalSorter.static_order ` can be used directly:
554
555
555
556
.. doctest ::
556
557
557
- >>> class A : pass
558
- >>> class B (A ): pass
559
- >>> class C (A ): pass
560
- >>> class D (B , C ): pass
561
-
562
- >>> D.__mro__
563
- (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
564
-
565
- >>> graph = {D: {B, C}, C: {A}, B: {A}, A:{object }}
558
+ >>> graph = {" D" : {" B" , " C" }, " C" : {" A" }, " B" : {" A" }}
566
559
>>> ts = TopologicalSorter(graph)
567
- >>> topological_order = tuple (ts.static_order())
568
- >>> tuple (reversed (topological_order))
569
- (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
560
+ >>> tuple (ts.static_order())
561
+ ('A', 'C', 'B', 'D')
570
562
571
- The class is designed to easily support parallel processing of the nodes as they
572
- become ready. For instance::
563
+ The class is designed to easily support parallel processing of the nodes as
564
+ they become ready. For instance::
573
565
574
566
topological_sorter = TopologicalSorter()
575
567
@@ -595,39 +587,39 @@ The :mod:`functools` module defines the following functions:
595
587
596
588
.. method :: add(node, *predecessors)
597
589
598
- Add a new node and its predecessors to the graph. Both the *node * and
599
- all elements in *predecessors * must be hashable.
590
+ Add a new node and its predecessors to the graph. Both the *node * and all
591
+ elements in *predecessors * must be hashable.
600
592
601
- If called multiple times with the same node argument, the set of dependencies
602
- will be the union of all dependencies passed in.
593
+ If called multiple times with the same node argument, the set of
594
+ dependencies will be the union of all dependencies passed in.
603
595
604
596
It is possible to add a node with no dependencies (*predecessors * is not
605
597
provided) or to provide a dependency twice. If a node that has not been
606
- provided before is included among *predecessors * it will be automatically added
607
- to the graph with no predecessors of its own.
598
+ provided before is included among *predecessors * it will be automatically
599
+ added to the graph with no predecessors of its own.
608
600
609
601
Raises :exc: `ValueError ` if called after :meth: `~TopologicalSorter.prepare `.
610
602
611
603
.. method :: prepare()
612
604
613
- Mark the graph as finished and check for cycles in the graph. If any cycle is
614
- detected, :exc: `CycleError ` will be raised, but
615
- :meth: `~TopologicalSorter.get_ready ` can still be used to obtain as many nodes
616
- as possible until cycles block more progress. After a call to this function,
617
- the graph cannot be modified, and therefore no more nodes can be added using
618
- :meth: `~TopologicalSorter.add `.
605
+ Mark the graph as finished and check for cycles in the graph. If any cycle
606
+ is detected, :exc: `CycleError ` will be raised, but
607
+ :meth: `~TopologicalSorter.get_ready ` can still be used to obtain as many
608
+ nodes as possible until cycles block more progress. After a call to this
609
+ function, the graph cannot be modified, and therefore no more nodes can be
610
+ added using :meth: `~TopologicalSorter.add `.
619
611
620
612
.. method :: is_active()
621
613
622
- Returns ``True `` if more progress can be made and ``False `` otherwise. Progress
623
- can be made if cycles do not block the resolution and either there are still
624
- nodes ready that haven't yet been returned by
614
+ Returns ``True `` if more progress can be made and ``False `` otherwise.
615
+ Progress can be made if cycles do not block the resolution and either
616
+ there are still nodes ready that haven't yet been returned by
625
617
:meth: `TopologicalSorter.get_ready ` or the number of nodes marked
626
- :meth: `TopologicalSorter.done ` is less than the number that have been returned
627
- by :meth: `TopologicalSorter.get_ready `.
618
+ :meth: `TopologicalSorter.done ` is less than the number that have been
619
+ returned by :meth: `TopologicalSorter.get_ready `.
628
620
629
- The :meth: `~TopologicalSorter.__bool__ ` method of this class defers to this
630
- function, so instead of::
621
+ The :meth: `~TopologicalSorter.__bool__ ` method of this class defers to
622
+ this function, so instead of::
631
623
632
624
if ts.is_active():
633
625
...
@@ -637,29 +629,28 @@ The :mod:`functools` module defines the following functions:
637
629
if ts:
638
630
...
639
631
640
- Raises :exc: `ValueError ` if called without calling :meth: ` ~TopologicalSorter.prepare `
641
- previously.
632
+ Raises :exc: `ValueError ` if called without calling
633
+ :meth: ` ~TopologicalSorter.prepare ` previously.
642
634
643
635
.. method :: done(*nodes)
644
636
645
637
Marks a set of nodes returned by :meth: `TopologicalSorter.get_ready ` as
646
- processed, unblocking any successor of each node in *nodes * for being returned
647
- in the future by a call to :meth: `TopologicalSorter.get_ready `.
638
+ processed, unblocking any successor of each node in *nodes * for being
639
+ returned in the future by a call to :meth: `TopologicalSorter.get_ready `.
648
640
649
641
Raises :exc: `ValueError ` if any node in *nodes * has already been marked as
650
- processed by a previous call to this method or if a node was not added to the
651
- graph by using :meth: `TopologicalSorter.add `, if called without calling
652
- :meth: `~TopologicalSorter.prepare ` or if node has not yet been returned by
653
- :meth: `~TopologicalSorter.get_ready `.
642
+ processed by a previous call to this method or if a node was not added to
643
+ the graph by using :meth: `TopologicalSorter.add `, if called without
644
+ calling :meth: `~TopologicalSorter.prepare ` or if node has not yet been
645
+ returned by :meth: `~TopologicalSorter.get_ready `.
654
646
655
647
.. method :: get_ready()
656
648
657
- Returns a ``tuple `` with all the nodes that are ready. Initially it returns all
658
- nodes with no predecessors, and once those are marked as processed by calling
659
- :meth: `TopologicalSorter.done `, further calls will return all new nodes that
660
- have all their predecessors already processed. Once no more progress can be
661
- made, empty tuples are returned.
662
- made.
649
+ Returns a ``tuple `` with all the nodes that are ready. Initially it
650
+ returns all nodes with no predecessors, and once those are marked as
651
+ processed by calling :meth: `TopologicalSorter.done `, further calls will
652
+ return all new nodes that have all their predecessors already processed.
653
+ Once no more progress can be made, empty tuples are returned.
663
654
664
655
Raises :exc: `ValueError ` if called without calling
665
656
:meth: `~TopologicalSorter.prepare ` previously.
@@ -694,9 +685,10 @@ The :mod:`functools` module defines the following functions:
694
685
>>> print ([* ts2.static_order()])
695
686
[0, 2, 1, 3]
696
687
697
- This is due to the fact that "0" and "2" are in the same level in the graph (they
698
- would have been returned in the same call to :meth: `~TopologicalSorter.get_ready `)
699
- and the order between them is determined by the order of insertion.
688
+ This is due to the fact that "0" and "2" are in the same level in the
689
+ graph (they would have been returned in the same call to
690
+ :meth: `~TopologicalSorter.get_ready `) and the order between them is
691
+ determined by the order of insertion.
700
692
701
693
702
694
If any cycle is detected, :exc: `CycleError ` will be raised.
0 commit comments