Psyduck - 可達鴨 之 鴨力山大2


Server : LiteSpeed
System : Linux premium217.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User : alloknri ( 880)
PHP Version : 8.1.34
Disable Function : NONE
Directory :  /opt/alt/python-internal/lib64/python3.11/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //opt/alt/python-internal/lib64/python3.11/graphlib.py
from types import GenericAlias

__all__ = ["TopologicalSorter", "CycleError"]

_NODE_OUT = -1
_NODE_DONE = -2


class _NodeInfo:
    __slots__ = "node", "npredecessors", "successors"

    def __init__(self, node):
        # The node this class is augmenting.
        self.node = node

        # Number of predecessors, generally >= 0. When this value falls to 0,
        # and is returned by get_ready(), this is set to _NODE_OUT and when the
        # node is marked done by a call to done(), set to _NODE_DONE.
        self.npredecessors = 0

        # List of successor nodes. The list can contain duplicated elements as
        # long as they're all reflected in the successor's npredecessors attribute.
        self.successors = []


class CycleError(ValueError):
    """Subclass of ValueError raised by TopologicalSorter.prepare if cycles
    exist in the working graph.

    If multiple cycles exist, only one undefined choice among them will be reported
    and included in the exception. The detected cycle can be accessed via the second
    element in the *args* attribute of the exception instance and consists in a list
    of nodes, such that each node is, in the graph, an immediate predecessor of the
    next node in the list. In the reported list, the first and the last node will be
    the same, to make it clear that it is cyclic.
    """

    pass


class TopologicalSorter:
    """Provides functionality to topologically sort a graph of hashable nodes"""

    def __init__(self, graph=None):
        self._node2info = {}
        self._ready_nodes = None
        self._npassedout = 0
        self._nfinished = 0

        if graph is not None:
            for node, predecessors in graph.items():
                self.add(node, *predecessors)

    def _get_nodeinfo(self, node):
        if (result := self._node2info.get(node)) is None:
            self._node2info[node] = result = _NodeInfo(node)
        return result

    def add(self, node, *predecessors):
        """Add a new node and its predecessors to the graph.

        Both the *node* and all elements in *predecessors* must be hashable.

        If called multiple times with the same node argument, the set of dependencies
        will be the union of all dependencies passed in.

        It is possible to add a node with no dependencies (*predecessors* is not provided)
        as well as provide a dependency twice. If a node that has not been provided before
        is included among *predecessors* it will be automatically added to the graph with
        no predecessors of its own.

        Raises ValueError if called after "prepare".
        """
        if self._ready_nodes is not None:
            raise ValueError("Nodes cannot be added after a call to prepare()")

        # Create the node -> predecessor edges
        nodeinfo = self._get_nodeinfo(node)
        nodeinfo.npredecessors += len(predecessors)

        # Create the predecessor -> node edges
        for pred in predecessors:
            pred_info = self._get_nodeinfo(pred)
            pred_info.successors.append(node)

    def prepare(self):
        """Mark the graph as finished and check for cycles in the graph.

        If any cycle is detected, "CycleError" will be raised, but "get_ready" can
        still be used to obtain as many nodes as possible until cycles block more
        progress. After a call to this function, the graph cannot be modified and
        therefore no more nodes can be added using "add".
        """
        if self._ready_nodes is not None:
            raise ValueError("cannot prepare() more than once")

        self._ready_nodes = [
            i.node for i in self._node2info.values() if i.npredecessors == 0
        ]
        # ready_nodes is set before we look for cycles on purpose:
        # if the user wants to catch the CycleError, that's fine,
        # they can continue using the instance to grab as many
        # nodes as possible before cycles block more progress
        cycle = self._find_cycle()
        if cycle:
            raise CycleError(f"nodes are in a cycle", cycle)

    def get_ready(self):
        """Return a tuple of all the nodes that are ready.

        Initially it returns all nodes with no predecessors; once those are marked
        as processed by calling "done", further calls will return all new nodes that
        have all their predecessors already processed. Once no more progress can be made,
        empty tuples are returned.

        Raises ValueError if called without calling "prepare" previously.
        """
        if self._ready_nodes is None:
            raise ValueError("prepare() must be called first")

        # Get the nodes that are ready and mark them
        result = tuple(self._ready_nodes)
        n2i = self._node2info
        for node in result:
            n2i[node].npredecessors = _NODE_OUT

        # Clean the list of nodes that are ready and update
        # the counter of nodes that we have returned.
        self._ready_nodes.clear()
        self._npassedout += len(result)

        return result

    def is_active(self):
        """Return ``True`` if more progress can be made and ``False`` otherwise.

        Progress can be made if cycles do not block the resolution and either there
        are still nodes ready that haven't yet been returned by "get_ready" or the
        number of nodes marked "done" is less than the number that have been returned
        by "get_ready".

        Raises ValueError if called without calling "prepare" previously.
        """
        if self._ready_nodes is None:
            raise ValueError("prepare() must be called first")
        return self._nfinished < self._npassedout or bool(self._ready_nodes)

    def __bool__(self):
        return self.is_active()

    def done(self, *nodes):
        """Marks a set of nodes returned by "get_ready" as processed.

        This method unblocks any successor of each node in *nodes* for being returned
        in the future by a call to "get_ready".

        Raises :exec:`ValueError` if any node in *nodes* has already been marked as
        processed by a previous call to this method, if a node was not added to the
        graph by using "add" or if called without calling "prepare" previously or if
        node has not yet been returned by "get_ready".
        """

        if self._ready_nodes is None:
            raise ValueError("prepare() must be called first")

        n2i = self._node2info

        for node in nodes:

            # Check if we know about this node (it was added previously using add()
            if (nodeinfo := n2i.get(node)) is None:
                raise ValueError(f"node {node!r} was not added using add()")

            # If the node has not being returned (marked as ready) previously, inform the user.
            stat = nodeinfo.npredecessors
            if stat != _NODE_OUT:
                if stat >= 0:
                    raise ValueError(
                        f"node {node!r} was not passed out (still not ready)"
                    )
                elif stat == _NODE_DONE:
                    raise ValueError(f"node {node!r} was already marked done")
                else:
                    assert False, f"node {node!r}: unknown status {stat}"

            # Mark the node as processed
            nodeinfo.npredecessors = _NODE_DONE

            # Go to all the successors and reduce the number of predecessors, collecting all the ones
            # that are ready to be returned in the next get_ready() call.
            for successor in nodeinfo.successors:
                successor_info = n2i[successor]
                successor_info.npredecessors -= 1
                if successor_info.npredecessors == 0:
                    self._ready_nodes.append(successor)
            self._nfinished += 1

    def _find_cycle(self):
        n2i = self._node2info
        stack = []
        itstack = []
        seen = set()
        node2stacki = {}

        for node in n2i:
            if node in seen:
                continue

            while True:
                if node in seen:
                    # If we have seen already the node and is in the
                    # current stack we have found a cycle.
                    if node in node2stacki:
                        return stack[node2stacki[node] :] + [node]
                    # else go on to get next successor
                else:
                    seen.add(node)
                    itstack.append(iter(n2i[node].successors).__next__)
                    node2stacki[node] = len(stack)
                    stack.append(node)

                # Backtrack to the topmost stack entry with
                # at least another successor.
                while stack:
                    try:
                        node = itstack[-1]()
                        break
                    except StopIteration:
                        del node2stacki[stack.pop()]
                        itstack.pop()
                else:
                    break
        return None

    def static_order(self):
        """Returns an iterable of nodes in a topological order.

        The particular order that is returned may depend on the specific
        order in which the items were inserted in the graph.

        Using this method does not require to call "prepare" or "done". If any
        cycle is detected, :exc:`CycleError` will be raised.
        """
        self.prepare()
        while self.is_active():
            node_group = self.get_ready()
            yield from node_group
            self.done(*node_group)

    __class_getitem__ = classmethod(GenericAlias)
Name
Size
Permissions
Options
__pycache__
--
drwxr-xr-x
asyncio
--
drwxr-xr-x
collections
--
drwxr-xr-x
concurrent
--
drwxr-xr-x
config-3.11-x86_64-linux-gnu
--
drwxr-xr-x
ctypes
--
drwxr-xr-x
curses
--
drwxr-xr-x
dbm
--
drwxr-xr-x
distutils
--
drwxr-xr-x
email
--
drwxr-xr-x
encodings
--
drwxr-xr-x
ensurepip
--
drwxr-xr-x
html
--
drwxr-xr-x
http
--
drwxr-xr-x
importlib
--
drwxr-xr-x
json
--
drwxr-xr-x
lib-dynload
--
drwxr-xr-x
lib2to3
--
drwxr-xr-x
logging
--
drwxr-xr-x
multiprocessing
--
drwxr-xr-x
pydoc_data
--
drwxr-xr-x
re
--
drwxr-xr-x
site-packages
--
drwxr-xr-x
sqlite3
--
drwxr-xr-x
tomllib
--
drwxr-xr-x
unittest
--
drwxr-xr-x
urllib
--
drwxr-xr-x
venv
--
drwxr-xr-x
wsgiref
--
drwxr-xr-x
xml
--
drwxr-xr-x
xmlrpc
--
drwxr-xr-x
zoneinfo
--
drwxr-xr-x
LICENSE.txt
13.609 KB
-rw-r--r--
__future__.py
5.096 KB
-rw-r--r--
__hello__.py
0.222 KB
-rw-r--r--
_aix_support.py
3.31 KB
-rw-r--r--
_bootsubprocess.py
2.612 KB
-rw-r--r--
_collections_abc.py
29.485 KB
-rw-r--r--
_compat_pickle.py
8.556 KB
-rw-r--r--
_compression.py
5.548 KB
-rw-r--r--
_markupbase.py
14.31 KB
-rw-r--r--
_osx_support.py
21.507 KB
-rw-r--r--
_py_abc.py
6.044 KB
-rw-r--r--
_pydecimal.py
223.83 KB
-rw-r--r--
_pyio.py
91.985 KB
-rw-r--r--
_sitebuiltins.py
3.055 KB
-rw-r--r--
_strptime.py
24.585 KB
-rw-r--r--
_sysconfigdata__linux_x86_64-linux-gnu.py
57.954 KB
-rw-r--r--
_sysconfigdata_d_linux_x86_64-linux-gnu.py
57.196 KB
-rw-r--r--
_threading_local.py
7.051 KB
-rw-r--r--
_weakrefset.py
5.755 KB
-rw-r--r--
abc.py
6.385 KB
-rw-r--r--
aifc.py
33.409 KB
-rw-r--r--
antigravity.py
0.488 KB
-rw-r--r--
argparse.py
97.933 KB
-rw-r--r--
ast.py
60.004 KB
-rw-r--r--
asynchat.py
11.299 KB
-rw-r--r--
asyncore.py
19.834 KB
-rw-r--r--
base64.py
20.554 KB
-rwxr-xr-x
bdb.py
31.702 KB
-rw-r--r--
bisect.py
3.062 KB
-rw-r--r--
bz2.py
11.569 KB
-rw-r--r--
cProfile.py
6.216 KB
-rwxr-xr-x
calendar.py
24.151 KB
-rw-r--r--
cgi.py
33.631 KB
-rwxr-xr-x
cgitb.py
12.13 KB
-rw-r--r--
chunk.py
5.371 KB
-rw-r--r--
cmd.py
14.524 KB
-rw-r--r--
code.py
10.373 KB
-rw-r--r--
codecs.py
36.279 KB
-rw-r--r--
codeop.py
5.769 KB
-rw-r--r--
colorsys.py
3.967 KB
-rw-r--r--
compileall.py
19.777 KB
-rw-r--r--
configparser.py
54.355 KB
-rw-r--r--
contextlib.py
26.771 KB
-rw-r--r--
contextvars.py
0.126 KB
-rw-r--r--
copy.py
8.478 KB
-rw-r--r--
copyreg.py
7.497 KB
-rw-r--r--
crypt.py
3.821 KB
-rw-r--r--
csv.py
15.654 KB
-rw-r--r--
dataclasses.py
57.102 KB
-rw-r--r--
datetime.py
89.68 KB
-rw-r--r--
decimal.py
0.313 KB
-rw-r--r--
difflib.py
81.355 KB
-rw-r--r--
dis.py
28.229 KB
-rw-r--r--
doctest.py
103.806 KB
-rw-r--r--
enum.py
77.718 KB
-rw-r--r--
filecmp.py
9.939 KB
-rw-r--r--
fileinput.py
15.346 KB
-rw-r--r--
fnmatch.py
5.858 KB
-rw-r--r--
fractions.py
28.005 KB
-rw-r--r--
ftplib.py
34.976 KB
-rw-r--r--
functools.py
37.513 KB
-rw-r--r--
genericpath.py
5.123 KB
-rw-r--r--
getopt.py
7.313 KB
-rw-r--r--
getpass.py
5.85 KB
-rw-r--r--
gettext.py
20.82 KB
-rw-r--r--
glob.py
8.527 KB
-rw-r--r--
graphlib.py
9.43 KB
-rw-r--r--
gzip.py
23.51 KB
-rw-r--r--
hashlib.py
11.489 KB
-rw-r--r--
heapq.py
22.484 KB
-rw-r--r--
hmac.py
7.535 KB
-rw-r--r--
imaplib.py
53.923 KB
-rw-r--r--
imghdr.py
3.859 KB
-rw-r--r--
imp.py
10.357 KB
-rw-r--r--
inspect.py
120.526 KB
-rw-r--r--
io.py
4.219 KB
-rw-r--r--
ipaddress.py
79.506 KB
-rw-r--r--
keyword.py
1.036 KB
-rw-r--r--
linecache.py
5.517 KB
-rw-r--r--
locale.py
77.241 KB
-rw-r--r--
lzma.py
12.966 KB
-rw-r--r--
mailbox.py
76.982 KB
-rw-r--r--
mailcap.py
9.149 KB
-rw-r--r--
mimetypes.py
22.424 KB
-rw-r--r--
modulefinder.py
23.144 KB
-rw-r--r--
netrc.py
6.767 KB
-rw-r--r--
nntplib.py
40.124 KB
-rw-r--r--
ntpath.py
29.967 KB
-rw-r--r--
nturl2path.py
2.819 KB
-rw-r--r--
numbers.py
10.105 KB
-rw-r--r--
opcode.py
10.202 KB
-rw-r--r--
operator.py
10.708 KB
-rw-r--r--
optparse.py
58.954 KB
-rw-r--r--
os.py
38.604 KB
-rw-r--r--
pathlib.py
47.428 KB
-rw-r--r--
pdb.py
62.688 KB
-rwxr-xr-x
pickle.py
63.605 KB
-rw-r--r--
pickletools.py
91.661 KB
-rw-r--r--
pipes.py
8.768 KB
-rw-r--r--
pkgutil.py
24.061 KB
-rw-r--r--
platform.py
41.302 KB
-rwxr-xr-x
plistlib.py
27.689 KB
-rw-r--r--
poplib.py
14.842 KB
-rw-r--r--
posixpath.py
16.796 KB
-rw-r--r--
pprint.py
24.007 KB
-rw-r--r--
profile.py
22.365 KB
-rwxr-xr-x
pstats.py
28.668 KB
-rw-r--r--
pty.py
6.169 KB
-rw-r--r--
py_compile.py
7.653 KB
-rw-r--r--
pyclbr.py
11.129 KB
-rw-r--r--
pydoc.py
110.029 KB
-rwxr-xr-x
queue.py
11.227 KB
-rw-r--r--
quopri.py
7.116 KB
-rwxr-xr-x
random.py
31.408 KB
-rw-r--r--
reprlib.py
5.31 KB
-rw-r--r--
rlcompleter.py
7.644 KB
-rw-r--r--
runpy.py
12.851 KB
-rw-r--r--
sched.py
6.202 KB
-rw-r--r--
secrets.py
1.98 KB
-rw-r--r--
selectors.py
19.21 KB
-rw-r--r--
shelve.py
8.359 KB
-rw-r--r--
shlex.py
13.185 KB
-rw-r--r--
shutil.py
55.192 KB
-rw-r--r--
signal.py
2.437 KB
-rw-r--r--
site.py
22.448 KB
-rw-r--r--
smtpd.py
30.45 KB
-rwxr-xr-x
smtplib.py
44.372 KB
-rwxr-xr-x
sndhdr.py
7.273 KB
-rw-r--r--
socket.py
36.677 KB
-rw-r--r--
socketserver.py
26.939 KB
-rw-r--r--
sre_compile.py
0.226 KB
-rw-r--r--
sre_constants.py
0.227 KB
-rw-r--r--
sre_parse.py
0.224 KB
-rw-r--r--
ssl.py
53.032 KB
-rw-r--r--
stat.py
5.356 KB
-rw-r--r--
statistics.py
46.587 KB
-rw-r--r--
string.py
11.51 KB
-rw-r--r--
stringprep.py
12.614 KB
-rw-r--r--
struct.py
0.251 KB
-rw-r--r--
subprocess.py
86.646 KB
-rw-r--r--
sunau.py
18.047 KB
-rw-r--r--
symtable.py
10.125 KB
-rw-r--r--
sysconfig.py
29.604 KB
-rw-r--r--
tabnanny.py
11.053 KB
-rwxr-xr-x
tarfile.py
109.217 KB
-rwxr-xr-x
telnetlib.py
22.755 KB
-rw-r--r--
tempfile.py
31.126 KB
-rw-r--r--
textwrap.py
19.256 KB
-rw-r--r--
this.py
0.979 KB
-rw-r--r--
threading.py
56.866 KB
-rw-r--r--
timeit.py
13.221 KB
-rwxr-xr-x
token.py
2.33 KB
-rw-r--r--
tokenize.py
25.719 KB
-rw-r--r--
trace.py
28.518 KB
-rwxr-xr-x
traceback.py
39.597 KB
-rw-r--r--
tracemalloc.py
17.624 KB
-rw-r--r--
tty.py
0.858 KB
-rw-r--r--
types.py
9.831 KB
-rw-r--r--
typing.py
118.116 KB
-rw-r--r--
uu.py
7.169 KB
-rw-r--r--
uuid.py
26.95 KB
-rw-r--r--
warnings.py
20.615 KB
-rw-r--r--
wave.py
21.307 KB
-rw-r--r--
weakref.py
21.009 KB
-rw-r--r--
webbrowser.py
24.565 KB
-rwxr-xr-x
xdrlib.py
5.837 KB
-rw-r--r--
zipapp.py
7.358 KB
-rw-r--r--
zipfile.py
91.59 KB
-rw-r--r--
zipimport.py
30.173 KB
-rw-r--r--