o
    h                    @   sh  d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	Z
ddlmZ dgZdd	 Zd
dddZedZedddZddlmZmZ dd ejdejdddD e_ed&i dd e D e_deej_ i Zdd Zdd Zi ZG dd dZd d! Z ejd"reZ!d'd#dZe!j"j e_ e#e!j"Z$e$j%d$d e$j& D d%e_'dS dS )(a&  
NetworkX utilizes a plugin-dispatch architecture, which means we can plug in and
out of backends with minimal code changes. A valid NetworkX backend specifies
`entry points <https://packaging.python.org/en/latest/specifications/entry-points>`_,
named ``networkx.backends`` and an optional ``networkx.backend_info`` when it is
installed (not imported). This allows NetworkX to dispatch (redirect) function calls
to the backend so the execution flows to the designated backend
implementation, similar to how plugging a charger into a socket redirects the
electricity to your phone. This design enhances flexibility and integration, making
NetworkX more adaptable and efficient. 

There are three main ways to use a backend after the package is installed.
You can set environment variables and run the exact same code you run for
NetworkX. You can use a keyword argument ``backend=...`` with the NetworkX
function. Or, you can convert the NetworkX Graph to a backend graph type and
call a NetworkX function supported by that backend. Environment variables
and backend keywords automatically convert your NetworkX Graph to the
backend type. Manually converting it yourself allows you to use that same
backend graph for more than one function call, reducing conversion time.

For example, you can set an environment variable before starting python to request
all dispatchable functions automatically dispatch to the given backend::

    bash> NETWORKX_AUTOMATIC_BACKENDS=cugraph python my_networkx_script.py

or you can specify the backend as a kwarg::

    nx.betweenness_centrality(G, k=10, backend="parallel")

or you can convert the NetworkX Graph object ``G`` into a Graph-like
object specific to the backend and then pass that in the NetworkX function::

    H = nx_parallel.ParallelGraph(G)
    nx.betweenness_centrality(H, k=10)

How it works: You might have seen the ``@nx._dispatchable`` decorator on
many of the NetworkX functions in the codebase. It decorates the function
with code that redirects execution to the function's backend implementation.
The code also manages any ``backend_kwargs`` you provide to the backend
version of the function. The code looks for the environment variable or
a ``backend`` keyword argument and if found, converts the input NetworkX
graph to the backend format before calling the backend's version of the
function. If no environment variable or backend keyword are found, the
dispatching code checks the input graph object for an attribute
called ``__networkx_backend__`` which tells it which backend provides this
graph type. That backend's version of the function is then called.
The backend system relies on Python ``entry_point`` system to signal
NetworkX that a backend is installed (even if not imported yet). Thus no
code needs to be changed between running with NetworkX and running with
a backend to NetworkX. The attribute ``__networkx_backend__`` holds a
string with the name of the ``entry_point``. If none of these options
are being used, the decorator code simply calls the NetworkX function
on the NetworkX graph as usual.

The NetworkX library does not need to know that a backend exists for it
to work. So long as the backend package creates the entry_point, and
provides the correct interface, it will be called when the user requests
it using one of the three approaches described above. Some backends have
been working with the NetworkX developers to ensure smooth operation.
They are the following::

- `graphblas <https://github.com/python-graphblas/graphblas-algorithms>`_
- `cugraph <https://github.com/rapidsai/cugraph/tree/branch-24.04/python/nx-cugraph>`_
- `parallel <https://github.com/networkx/nx-parallel>`_
- ``loopback`` is for testing purposes only and is not a real backend.

Note that the ``backend_name`` is e.g. ``parallel``, the package installed
is ``nx-parallel``, and we use ``nx_parallel`` while importing the package.

Creating a Custom backend
-------------------------

1.  To be a valid backend that is discoverable by NetworkX, your package must
    register an `entry-point <https://packaging.python.org/en/latest/specifications/entry-points/#entry-points>`_
    ``networkx.backends`` in the package's metadata, with a `key pointing to your
    dispatch object <https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-package-metadata>`_ .
    For example, if you are using ``setuptools`` to manage your backend package,
    you can `add the following to your pyproject.toml file <https://setuptools.pypa.io/en/latest/userguide/entry_point.html>`_::

        [project.entry-points."networkx.backends"]
        backend_name = "your_dispatcher_class"

    You can also add the ``backend_info`` entry-point. It points towards the ``get_info``
    function that returns all the backend information, which is then used to build the
    "Additional Backend Implementation" box at the end of algorithm's documentation
    page (e.g. `nx-cugraph's get_info function <https://github.com/rapidsai/cugraph/blob/branch-24.04/python/nx-cugraph/_nx_cugraph/__init__.py>`_)::

        [project.entry-points."networkx.backend_info"]
        backend_name = "your_get_info_function"

    Note that this would only work if your backend is a trusted backend of NetworkX,
    and is present in the `.circleci/config.yml` and
    `.github/workflows/deploy-docs.yml` files in the NetworkX repository.

2.  The backend must create an ``nx.Graph``-like object which contains an attribute
    ``__networkx_backend__`` with a value of the entry point name::

        class BackendGraph:
            __networkx_backend__ = "backend_name"
            ...


Testing the Custom backend
--------------------------

To test your custom backend, you can run the NetworkX test suite with your backend.
This also ensures that the custom backend is compatible with NetworkX's API.

Testing Environment Setup
~~~~~~~~~~~~~~~~~~~~~~~~~

To enable automatic testing with your custom backend, follow these steps:

1. Set Backend Environment Variables: 
    - ``NETWORKX_TEST_BACKEND`` : Setting this to your registered backend key will let
      the NetworkX's dispatch machinery automatically convert a regular NetworkX
      ``Graph``, ``DiGraph``, ``MultiGraph``, etc. to their backend equivalents, using
      ``your_dispatcher_class.convert_from_nx(G, ...)`` function.
    - ``NETWORKX_FALLBACK_TO_NX`` (default=False) : Setting this variable to `True` will
      instruct tests to use a NetworkX ``Graph`` for algorithms not implemented by your
      custom backend. Setting this to `False` will only run the tests for algorithms
      implemented by your custom backend and tests for other algorithms will ``xfail``.

2. Defining ``convert_from_nx`` and ``convert_to_nx`` methods:
    The arguments to ``convert_from_nx`` are:

    - ``G`` : NetworkX Graph
    - ``edge_attrs`` : dict, optional
        Dictionary mapping edge attributes to default values if missing in ``G``.
        If None, then no edge attributes will be converted and default may be 1.
    - ``node_attrs``: dict, optional
        Dictionary mapping node attributes to default values if missing in ``G``.
        If None, then no node attributes will be converted.
    - ``preserve_edge_attrs`` : bool
        Whether to preserve all edge attributes.
    - ``preserve_node_attrs`` : bool
        Whether to preserve all node attributes.
    - ``preserve_graph_attrs`` : bool
        Whether to preserve all graph attributes.
    - ``preserve_all_attrs`` : bool
        Whether to preserve all graph, node, and edge attributes.
    - ``name`` : str
        The name of the algorithm.
    - ``graph_name`` : str
        The name of the graph argument being converted.

Running Tests
~~~~~~~~~~~~~

You can invoke NetworkX tests for your custom backend with the following commands::

    NETWORKX_TEST_BACKEND=<backend_name>
    NETWORKX_FALLBACK_TO_NX=True # or False
    pytest --pyargs networkx

Conversions while running tests :

- Convert NetworkX graphs using ``<your_dispatcher_class>.convert_from_nx(G, ...)`` into
  the backend graph.
- Pass the backend graph objects to the backend implementation of the algorithm.
- Convert the result back to a form expected by NetworkX tests using 
  ``<your_dispatcher_class>.convert_to_nx(result, ...)``.

Notes
~~~~~

-   Dispatchable algorithms that are not implemented by the backend
    will cause a ``pytest.xfail``, giving some indication that not all
    tests are running, while avoiding causing an explicit failure.

-   If a backend only partially implements some algorithms, it can define
    a ``can_run(name, args, kwargs)`` function that returns True or False
    indicating whether it can run the algorithm with the given arguments.
    It may also return a string indicating why the algorithm can't be run;
    this string may be used in the future to give helpful info to the user.

-   A backend may also define ``should_run(name, args, kwargs)`` that is similar
    to ``can_run``, but answers whether the backend *should* be run (converting
    if necessary). Like ``can_run``, it receives the original arguments so it
    can decide whether it should be run by inspecting the arguments. ``can_run``
    runs before ``should_run``, so ``should_run`` may assume ``can_run`` is True.
    If not implemented by the backend, ``can_run`` and ``should_run`` are
    assumed to always return True if the backend implements the algorithm.

-   A special ``on_start_tests(items)`` function may be defined by the backend.
    It will be called with the list of NetworkX tests discovered. Each item
    is a test object that can be marked as xfail if the backend does not support
    the test using ``item.add_marker(pytest.mark.xfail(reason=...))``.

-   A backend graph instance may have a ``G.__networkx_cache__`` dict to enable
    caching, and care should be taken to clear the cache when appropriate.
    N)partial)entry_points   )argmap_dispatchablec                   C      dS )zKThis does nothing at all, yet it helps turn `_dispatchable` into functions.N r   r   r   R/var/www/html/env_mimamsha/lib/python3.10/site-packages/networkx/utils/backends.py_do_nothing   s    r
   F)load_and_callc                C   s   t | d}i }|D ]G}|j|v rtjd|j tdd q	|rKz
|  ||j< W q	 tyJ } ztjd|j d| tdd W Y d}~q	d}~ww |||j< q	|dd |S )	a  
    Retrieve NetworkX ``backends`` and ``backend_info`` from the entry points.

    Parameters
    -----------
    group : str
        The entry_point to be retrieved.
    load_and_call : bool, optional
        If True, load and call the backend. Defaults to False.

    Returns
    --------
    dict
        A dictionary mapping backend names to their respective backend objects.

    Notes
    ------
    If a backend is defined more than once, a warning is issued.
    The `nx-loopback` backend is removed if it exists, as it is only available during testing.
    A warning is displayed if an error occurs while loading a backend.
    )groupz)networkx backend defined more than once:    )
stacklevelz0Error encountered when loading info for backend z: Nznx-loopback)r   namewarningswarnRuntimeWarningload	Exceptionpop)r   r   itemsrvepexcr   r   r	   _get_backends   s.   


r   znetworkx.backendsznetworkx.backend_infoT)Configconfigc                 C   s   g | ]
}|  r|  qS r   )strip.0xr   r   r	   
<listcomp>	  s    r!   NETWORKX_BACKEND_PRIORITYNETWORKX_AUTOMATIC_BACKENDS ,c                 C   sD   i | ]\}}|d |v rt |d   atrtn	tdi tnt qS )default_configr   )
isinstancecfgr   r   backendinfor   r   r	   
<dictcomp>  s    $r,   z2All installed NetworkX backends and their configs.c                 C   r   )NTr   )r   argskwargsr   r   r	   _always_run"  s   r/   c                 C   sH   | t v rt |  S t|    }t | < t|dst|_t|ds"t|_|S )Ncan_run
should_run)_loaded_backendsbackendsr   hasattrr/   r0   r1   )backend_namer   r   r   r	   _load_backend&  s   

r6   c                   @   s   e Zd ZdZdZejdd 	 dkZ
	d#ddddddddddd
dd	Zed
d Zejdd Zedd ZddddZdd Zdd Zdd Zdd ZddddZddddZdd  Zd!d" ZdS )$r   a  Allow any of the following decorator forms:
    - @_dispatchable
    - @_dispatchable()
    - @_dispatchable(name="override_name")
    - @_dispatchable(graphs="graph")
    - @_dispatchable(edge_attrs="weight")
    - @_dispatchable(graphs={"G": 0, "H": 1}, edge_attrs={"weight": "default"})

    These class attributes are currently used to allow backends to run networkx tests.
    For example: `PYTHONPATH=. pytest --backend graphblas --fallback-to-nx`
    Future work: add configuration to control these.
    FNETWORKX_FALLBACK_TO_NXtrueNG
r   graphs
edge_attrs
node_attrspreserve_edge_attrspreserve_node_attrspreserve_graph_attrspreserve_all_attrsmutates_inputreturns_graphc       
            s  |du rt t|||||||	|
|dS t|trtdddu r$|jt| |j_|j_|j	r?i |j	ddi_	nddi_	|j
_
|j_j|j |_|j_d_|__|_|_|pl|	_|pq|	_|pv|	_|
_|_|durt|ttB stdt| dd|durt|ttB stdt| ddtjttB tB stdtj d	dtjttB tB std
tj d	dtjttB stdtj ddtjttB stdtj ddtjtstdtj ddt|tr|di}n#|du r"nt|ts3tdt| ddt|dkr?t ddt _!t _"|du rPi _#n fdd|$ D _#d_%fddt&$ D _'t(v rzt d dt)t*t(< S )a  A decorator that makes certain input graph types dispatch to ``func``'s
        backend implementation.

        Usage can be any of the following decorator forms:
        - @_dispatchable
        - @_dispatchable()
        - @_dispatchable(name="override_name")
        - @_dispatchable(graphs="graph_var_name")
        - @_dispatchable(edge_attrs="weight")
        - @_dispatchable(graphs={"G": 0, "H": 1}, edge_attrs={"weight": "default"})
        with 0 and 1 giving the position in the signature function for graph objects.
        When edge_attrs is a dict, keys are keyword names and values are defaults.

        The class attributes are used to allow backends to run networkx tests.
        For example: `PYTHONPATH=. pytest --backend graphblas --fallback-to-nx`
        Future work: add configuration to control these.

        Parameters
        ----------
        func : callable, optional
            The function to be decorated. If ``func`` is not provided, returns a
            partial object that can be used to decorate a function later. If ``func``
            is provided, returns a new callable object that dispatches to a backend
            algorithm based on input graph types.

        name : str, optional
            The name of the algorithm to use for dispatching. If not provided,
            the name of ``func`` will be used. ``name`` is useful to avoid name
            conflicts, as all dispatched algorithms live in a single namespace.
            For example, ``tournament.is_strongly_connected`` had a name conflict
            with the standard ``nx.is_strongly_connected``, so we used
            ``@_dispatchable(name="tournament_is_strongly_connected")``.

        graphs : str or dict or None, default "G"
            If a string, the parameter name of the graph, which must be the first
            argument of the wrapped function. If more than one graph is required
            for the algorithm (or if the graph is not the first argument), provide
            a dict of parameter name to argument position for each graph argument.
            For example, ``@_dispatchable(graphs={"G": 0, "auxiliary?": 4})``
            indicates the 0th parameter ``G`` of the function is a required graph,
            and the 4th parameter ``auxiliary`` is an optional graph.
            To indicate an argument is a list of graphs, do e.g. ``"[graphs]"``.
            Use ``graphs=None`` if *no* arguments are NetworkX graphs such as for
            graph generators, readers, and conversion functions.

        edge_attrs : str or dict, optional
            ``edge_attrs`` holds information about edge attribute arguments
            and default values for those edge attributes.
            If a string, ``edge_attrs`` holds the function argument name that
            indicates a single edge attribute to include in the converted graph.
            The default value for this attribute is 1. To indicate that an argument
            is a list of attributes (all with default value 1), use e.g. ``"[attrs]"``.
            If a dict, ``edge_attrs`` holds a dict keyed by argument names, with
            values that are either the default value or, if a string, the argument
            name that indicates the default value.

        node_attrs : str or dict, optional
            Like ``edge_attrs``, but for node attributes.

        preserve_edge_attrs : bool or str or dict, optional
            For bool, whether to preserve all edge attributes.
            For str, the parameter name that may indicate (with ``True`` or a
            callable argument) whether all edge attributes should be preserved
            when converting.
            For dict of ``{graph_name: {attr: default}}``, indicate pre-determined
            edge attributes (and defaults) to preserve for input graphs.

        preserve_node_attrs : bool or str or dict, optional
            Like ``preserve_edge_attrs``, but for node attributes.

        preserve_graph_attrs : bool or set
            For bool, whether to preserve all graph attributes.
            For set, which input graph arguments to preserve graph attributes.

        preserve_all_attrs : bool
            Whether to preserve all edge, node and graph attributes.
            This overrides all the other preserve_*_attrs.

        mutates_input : bool or dict, default False
            For bool, whether the functions mutates an input graph argument.
            For dict of ``{arg_name: arg_pos}``, arguments that indicates whether an
            input graph will be mutated, and ``arg_name`` may begin with ``"not "``
            to negate the logic (for example, this is used by ``copy=`` arguments).
            By default, dispatching doesn't convert input graphs to a different
            backend for functions that mutate input graphs.

        returns_graph : bool, default False
            Whether the function can return or yield a graph object. By default,
            dispatching doesn't convert input graphs to a different backend for
            functions that return graphs.
        Nr:   z-'name' and 'graphs' must be passed by keywordr*   zBad type for edge_attrs: z. Expected str or dict.zBad type for node_attrs: z"Bad type for preserve_edge_attrs: z. Expected bool, str, or dict.z"Bad type for preserve_node_attrs: z#Bad type for preserve_graph_attrs: z. Expected bool or set.zBad type for mutates_input: z. Expected bool or dict.zBad type for returns_graph: z. Expected bool.r   zBad type for graphs: z0'graphs' must contain at least one variable namec                    sf   i | ]/\}}|d    dkrj |dd   pn dkr.j|dd   p-n||qS )?N]r   )optional_graphsaddlist_graphsr   kv)lastselfvalr   r	   r,     s    z)_dispatchable.__new__.<locals>.<dictcomp>c                    s(   h | ]\}}d |v r |d  v r|qS )	functionsr   r)   r   r   r	   	<setcomp>)  s
    z(_dispatchable.__new__.<locals>.<setcomp>z/Algorithm already exists in dispatch registry: )+r   r   r'   str	TypeError__name__object__new____defaults____kwdefaults__
__module____qualname____dict__update__wrapped____doc__	_orig_doc_cached_doc	orig_funcr   r<   r=   r>   r?   r@   rB   _returns_graphdicttypeboolsetlenKeyErrorrG   rI   r;   r   _sigbackend_infor3   _registered_algorithmsr   r
   )clsfuncr   r;   r<   r=   r>   r?   r@   rA   rB   rC   r   )rM   r   rN   rO   r	   rW   G  s   j












z_dispatchable.__new__c                 C   s$   | j  }dur	|S |   }| _ |S )zIf the cached documentation exists, it is returned.
        Otherwise, the documentation is generated using _make_doc() method,
        cached, and then returned.N)ra   	_make_doc)rN   r   r   r   r	   r_   ;  s   z_dispatchable.__doc__c                 C   s   || _ d| _dS )z_Sets the original documentation to the given value and resets the
        cached documentation.N)r`   ra   )rN   rO   r   r   r	   r_   F  s   
c                 C   s   | j du rTt| j}tdd |j D s5|jg |j tjdtjj	ddtdtjj
d}n|j ^ }}|jg |tjdtjj	dd|d}|| _ | j S )zzReturn the signature of the original function, with the addition of
        the `backend` and `backend_kwargs` parameters.Nc                 s   s    | ]
}|j tjjkV  qd S N)kindinspect	ParameterVAR_KEYWORD)r   pr   r   r	   	<genexpr>W  s    
z._dispatchable.__signature__.<locals>.<genexpr>r*   )defaultbackend_kwargs
parameters)rj   rr   	signaturerb   anyrz   valuesreplacers   KEYWORD_ONLYrt   )rN   sigrz   var_keywordr   r   r	   __signature__N  s@   


	z_dispatchable.__signature__)r*   c            
      s  t s
j i S |}|dur|t vrtd| i }j D ]O\}}|t k r?|v r:tj d| | }n|v rH| }n|jvrWtj d| q"|du rm|jvrltj d|dq"|||< q"j	rt
  j	| @ D ]}t
|| }|||< |v r||< q| j| < qtfdd| D }	|	r͇fd	d
| D }
j	| @ D ]}|
dd || D  qntdd | D }	|	rdd
 | D }
tj}jr|r|du rj|d  jdS |	r|
dh }t|dkrtj d| |\}|dur0||kr0tj d|d|d|t vr<td| d|
v rY||vrYtdj dj d| d| d	t|}t|jr~d|
v rsj| jdS t|j i S tdj d| |durj| ddS jsֈjrtjtrt fddj D r|D ]}j|g R i rԈj| jd  S qj i S )zReturns the result of the original function, or the backend function if
        the backend is specified and that backend implements `func`.NzUnable to load backend: z() got multiple values for z$() missing required graph argument: z() required graph argument z is None; must be a graphc                 3   s:    | ]\}}| j vrt|d ntdd |D V  qdS )__networkx_backend__c                 s       | ]}t |d V  qdS r   Nr4   )r   g2r   r   r	   rv         z3_dispatchable.__call__.<locals>.<genexpr>.<genexpr>N)rI   r4   r|   r   gnamegrN   r   r	   rv     s    


z)_dispatchable.__call__.<locals>.<genexpr>c                    s&   h | ]\}}| j vrt|d dqS r   networkx)rI   getattrr   r   r   r	   rR     s
    

z)_dispatchable.__call__.<locals>.<setcomp>c                 s   s    | ]	}t |d dV  qdS )r   r   Nr   r   r   r   r   r	   rv     s
    

c                 s   r   r   r   r   r   r   r	   rv     s    

c                 S   s   h | ]}t |d dqS r   r   r   r   r   r	   rR     s    
r   fallback_to_nxr   r   z3() graphs must all be from the same backend, found z+() is unable to convert graph from backend z to the specified backend .z!Unable to convert inputs and run z. z() has networkx and zY graphs, but NetworkX is not configured to automatically convert graphs from networkx to '' not implemented by Fc                 3   sj    | ]0\}}| d r t |kr | n	|dd d nt |kr* | n|duV  qdS )znot    NT)
startswithrh   get)r   arg_namearg_pos)r-   r.   r   r	   rv     s    
)r3   rb   ImportErrorr;   r   rh   rT   r   rG   rI   listkeysr|   r]   r}   r   backend_priority_is_testing_convert_and_call_for_tests_fallback_to_nxr6   r4   _convert_and_callr   nxNetworkXNotImplementedrc   rB   r'   rd   _should_backend_run)rN   r*   r-   r.   r5   graphs_resolvedr   posrO   has_backendsgraph_backend_namesr   backend_namesgraph_backend_namer   )r-   r.   rN   r	   __call__s  s   
















	

z_dispatchable.__call__c                O   s4   t |}t|| jo|| j|| }ot|t S )zBCan the specified backend run this algorithm with these arguments?)r6   r4   r   r0   r'   rS   )rN   r5   r-   r.   r*   r0   r   r   r	   _can_backend_run*  s   
z_dispatchable._can_backend_runc                O   sT   t |}t|| jo)|| j|| }o)t|t o)|| j|| }o)t|t S )zICan/should the specified backend run this algorithm with these arguments?)r6   r4   r   r0   r'   rS   r1   )rN   r5   r-   r.   r*   r0   r1   r   r   r	   r   5  s   

z!_dispatchable._should_backend_runc                   s  
j j|i |  
jsj}|d= j|fS 
j
jdu r&n?du r-dn8tt	rej
 du s@tj
 rEddn j
 du rctt	rUks^ttrcv rcddnddu rjn]tt	rd dkrdd j
d	d
  D nCtj
 rddn7j
 durj
 d	in(
jdkrtj
d drdd j
d jD ndnfdd D 
j	
j	du rnE	du rdn>t	t	rj
	 du stj
	 rd	dn%j
	 du rtt	r	ksttr	v rd	dnd	du rnHtt	rYd dkr9dd j
d	d
  D n,tj
 rFd	dnj
 durVj
 dindnfdd D 
j
jD ]
jv r 	
f	ddj
 D j
< qkj
 }|du r
jv rqktd d
j dttrd}}n}}t	trd}		}
n	}	}
ttrۈv }n}t|dddkr
j |||
||	|d	j
< qkj}|d= j|fS )z~Convert graph arguments to the specified backend.

        Returns
        -------
        args tuple and kwargs dict
        r*   FTNr   [c                 S      i | ]}|d qS r   r   r   	edge_attrr   r   r	   r,   x      z4_dispatchable._convert_arguments.<locals>.<dictcomp>r   rD   to_numpy_arraydtypenamesc                 S   r   r   r   r   r   r   r	   r,     r   c                    s@   i | ]\}} j |  d urt|tr j |dn|qS )Nr   	argumentsr'   rS   r   r   keyrO   )boundr   r   r	   r,     s
    c                 S   r   rp   r   )r   	node_attrr   r   r	   r,     r   c                    s>   i | ]\}} j |  d urt|tr j |n|qS rp   r   r   )r   r   r   r	   r,     s
    c                    s<   g | ]}t |d ddkrj |d	n|qS )r   r   r<   r=   r>   r?   r@   
graph_name	use_cache)r   _convert_graphr   )	r5   r<   r   r=   r>   r@   r?   rN   r   r   r	   r!     s     z4_dispatchable._convert_arguments.<locals>.<listcomp>z!Missing required graph argument `z` in z	 functionr   r   r   )r   bindapply_defaultsr;   r.   r-   r>   r<   r'   rS   r   callablerd   r   r4   r   r   r?   r=   r@   rI   rG   rT   r   rg   r   r   )rN   r5   r-   r.   r   bound_kwargsgraphpreserve_edgesedgespreserve_nodesnodespreserve_graphr   )r5   r   r   r<   r   r   r=   r>   r@   r?   rN   r   r	   _convert_argumentsB  s  












z _dispatchable._convert_argumentsc             
   C   sr  |	rt |dd  }
d ur|
di |i }|d ur t| n||d ur+t| n||f }\}}}|rd|d| j d}t|durJ|dfnd|durS|dfnd|dur\|dfndD ]}|| }d urst	| |  S q_|dur|durt
| D ]B\\}}}}|du s|du rn|du s|du s||sq|du s|du rn|du s|du s||sq|r|sqt	| |  S t|}|j||||||| j|d	}|	r7|
d ur7|||< t
|D ]O}||krq|\}}}|du s|du rn|du s|du s||sq|du s|du rn|du s(|du s(||s)q|r0|s0q||d  q|S )
N__networkx_cache__r3   zUsing cached graph for z backend in call to a  .

For the cache to be consistent (i.e., correct), the input graph must not have been manually mutated since the cached graph was created. Examples of manually mutating the graph data structures resulting in an inconsistent cache include:

    >>> G[u][v][key] = val

and

    >>> for u, v, d in G.edges(data=True):
    ...     d[key] = val

Using methods such as `G.add_edge(u, v, weight=val)` will correctly clear the cache to keep it consistent. You may also use `G.__networkx_cache__.clear()` to manually clear the cache, or set `G.__networkx_cache__` to None to disable caching for G. Enable or disable caching via `nx.config.cache_converted_graphs` config.T)TF)r<   r=   r>   r?   r@   r   r   )r   
setdefault	frozensetr   r   	itertoolsproductr   r   r   r   issubsetr6   convert_from_nxr   )rN   r5   r   r<   r=   r>   r?   r@   r   r   nx_cachecacher   edge_keynode_key	graph_keywarning_message
compat_keyr   ekeynkeygkeyrO   r*   cur_keyr   r   r	   r     s   	



  z_dispatchable._convert_graphr   c             
   C   s   t |}| j|g|R i |s1|r| j|i |S d| j d| }t|| jr-|d7 }t|z| j|||tjd\}}t	|| j|i |}	W |	S  t
tjfyk }
 z|rf| j|i |W  Y d}
~
S  d}
~
ww )zOCall this dispatchable function with a backend, converting graphs if necessary.r   r    with the given argumentsr   N)r6   r   rb   r   r4   RuntimeErrorr   r   cache_converted_graphsr   NotImplementedErrorr   r   )rN   r5   r-   r.   r   r*   msgconverted_argsconverted_kwargsresultr   r   r   r	   r     s(   

z_dispatchable._convert_and_callc                   sL  t |}j|g|R i |s9|sjsj|i |S ddl}dj d| }t|jr4|d7 }|| ddlm	m
m ddlm ddlm mmm	 dd	lm dd
lm ddlddlmm ddlm |sz| }}	nt 	f
dd|D  \}}	|s| }
}n!t 	fdd| D  \}
}t|
}
t|}zj|||
dd\}}t |j|i |}W n@ t!t"j#fy } z0|rj|	i |W  Y d}~S ddl}||j$r|j$d n
j dt%|j&  W Y d}~nd}~ww j't(|t"j)p0t|dp0t(|t*t+B o0t,dd |D krajdv rCt,dd |D sajdv rSt,dd |D sajdvrat-dj d5
fdd	

fdd}jdv r|n4t(|r||}n)z
| W n t-y } zt-j d | d!t%| d"|d}~ww 
| jd#v r@j.j/|i |}|0  j.j/|	i |}|0  jd$v r|1|j2d% }|j2d% }|j3|_3t"4| nMjd&kr-|1|j2d' }|j2d' }|dur+|dur+|j5 D ]\}}|d( |j5| d(< q|j67|j6 t"4| njd)krg|j2d* durg|1|j2d% }|j2d% }|j2d* }|j8 D ]\}}|| |j8| |< qRt"4| nԈjd+v r|j2d, s|1|j2d% }|j2d% }|j97|j9 t"4| njd-kr|j2d, s|1|j2d% }|j2d% }|j5 D ]\}}|d. |j5| d.< qt"4| n{jd/kr|j2d, r҈jd0v r;|1|j2d% }|j2d% }||u r|S |j:;  |j:7|j: |j3;  |j37|j3 t|d1rt|d1r|j<;  |j<7|j< t|d2r.t|d2r.|j=;  |j=7|j= t"4| jd/kr;|S |1|S |1|}t(|t"j)rjd3vrj|	i |}t"j>?||s|@ |@ ksmJ |A |A ksxJ |j6|j6ksJ |j8|j8ksJ |jB|jBksJ t%|t%|u sJ tCd4|S |S )6zECall this dispatchable function with a backend; for use with testing.r   Nr   r   r   )IterableIteratorMapping)copy)BufferedReaderBytesIOStringIOTextIOWrapper)tee)Random)	GeneratorRandomState)sparrayc                 3   s^    | ]*}t |B B B B r||fnt |r't | B s'	|n||fV  qd S rp   r'   )r   arg)
r   r   r   r   r   r   r   r   r   r   r   r	   rv     s    	

z<_dispatchable._convert_and_call_for_tests.<locals>.<genexpr>c                 3   s    | ]@\}}t |B B B B r||f||ffn#t |r9t | B s9|	| 
d  f|
d ffn||f||ffV  qdS )r   r   Nr   rJ   )r   r   r   r   r   r   r   r   r   r   teedr   r	   rv     s    	"
Fr   z raised r   c                 s   s&    | ]}t |tjpt|d V  qdS r   )r'   r   Graphr4   r   r   r   r	   rv     s
    
>   check_planaritycheck_planarity_recursivec                 s   s    | ]}|d u V  qd S rp   r   r   r   r   r	   rv     s    >   held_karp_ascentc                 s   s    | ]}t |tV  qd S rp   )r'   rd   r   r   r   r	   rv     r   >   
all_triadsnonisomorphic_treesgeneral_k_edge_subgraphsz!`returns_graph` is incorrect for c              	      s   t | jrtj d|  dt|  d| dt | jB r#d S t | tjr=| j|d d | j	|d d d S t | rDt
t |  r[t | ts[| D ]
}||d d qPt | ro|  D ]}||d d qdd S d S )N returned a numpy scalar  (z, depth=)r   )depth)r'   numberr   r   re   ndarrayr   r   _node_adjr   rS   r}   )rO   r  r    )r   r   r   check_resultnprN   r   r   r	   r    s(    

z?_dispatchable._convert_and_call_for_tests.<locals>.check_resultc                 3   s^    | D ])}z | W n t y( } zt j d| dt| d|d }~ww |V  qd S )Nr   r   r  )r   r   re   )itrO   r   )r  rN   r   r	   check_iterator'  s   zA_dispatchable._convert_and_call_for_tests.<locals>.check_iterator>   from_edgelistr   r   r  >   
barycenteredmonds_karprelabel_nodescontracted_edgecontracted_nodesstochastic_graphmaximum_branchingminimal_branchingrecursive_simple_cyclesconnected_double_edge_swapminimum_spanning_arborescence incremental_closeness_centrality>   r  r  r  r  r9   r  residualflowr  attr>   r  r  r   r  weightr  >   r  _pred_succ>   read_gml	read_gexf
from_pydot
read_pajekread_graph6preflow_pushread_adjlistread_graphmlread_sparse6read_edgelistpydot_read_dotquotient_graphagraph_read_dotboykov_kolmogorovspectral_graph_forgeread_multiline_adjlistbipartite_read_edgelistshortest_augmenting_pathzGraphs are not equal)r   )Dr6   r   r;   rb   pytestr   r4   xfailcollections.abcr   r   r   r   ior   r   r   r   r   r   randomr   numpynumpy.randomr   r   scipy.sparser   zipr   rd   r   r   r   r   r   r-   re   rU   rc   r'   r   tupler   r|   r   r   r   r   convert_to_nxr   r  _clear_cacher   r   r]   r   r\   r  clearr  r  utilsgraphs_equalnumber_of_nodesnumber_of_edgesadjAssertionError)rN   r5   r-   r.   r   r*   r0  r   args1args2kwargs1kwargs2r   r   r   r   r
  r   bound2G1G2R1R2rK   rL   r  converted_resultr9   r   )r   r   r   r   r   r   r   r   r   r   r  r   r  rN   r   r   r   r	   r     s:  


	
	
$	

















z)_dispatchable._convert_and_call_for_testsc                 C   s  | j s| jS ddg}t| j D ]}t| }d|v r&|| d|d   n|| d|vs6| j|d vr<|d q|d | j }|dpL|d }r_|d	d
 |dD  d}nd}|dpj|d }r|rt|d |d t|D ]}|d|  ||  }	r|d|	  |d q}n|d |d }
r|d|
 d |d q|	  d
|}| j  d| S )zGenerate the backends section at the end for functions having an alternate
        backend implementation(s) using the `backend_info` entry-point.Backendsz--------short_summaryz : rP   r$   additional_docsextra_docstringc                 s   s"    | ]}|rd | n|V  qdS )z  Nr   )r   liner   r   r	   rv     s    
z*_dispatchable._make_doc.<locals>.<genexpr>
TFextra_parametersadditional_parametersz  Additional parameters:z    z      urlz
[`Source <z>`_]z
    z

    )r3   r`   sortedrk   appendr   r   extendsplitr   joinrstrip)rN   linesr*   r+   	func_info	func_docsadd_gaprS  paramdescfunc_urlto_addr   r   r	   ro     sR   








z_dispatchable._make_docc                 C   s   t | jffS )zAllow this object to be serialized with pickle.

        This uses the global registry `_registered_algorithms` to deserialize.
        )_restore_dispatchabler   r   r   r   r	   
__reduce__  s   z_dispatchable.__reduce__rp   )rU   rZ   r[   r_   r   osenvironr   r   lowerr   rW   propertysetterr   r   r   r   r   r   r   r   ro   re  r   r   r   r	   r   4  sN     u



$ 8 O}  9c                 C   s   t |  S rp   )rl   rQ   r   r   r	   rd    s   rd  _NETWORKX_BUILDING_DOCS_c                 K   s4   | d u rt tfi |S t| fi |}|j| _| S rp   )r   r   _orig_dispatchabler_   )rn   r.   dispatched_funcr   r   r	   r     s
   c                 C   s   g | ]
\}}|d kr|qS )rm   r   rJ   r   r   r	   r!     s    ry   r   rp   )(r_   rr   r   rf  r   	functoolsr   importlib.metadatar   r   r   
decoratorsr   __all__r
   r   r3   rk   configsr   r   rg  r   rY  r   r   re   r2   r/   r6   rl   r   rd  rl  rW   r{   rj   r~   rz   r   r   r   r   r	   <module>   sj     B.	
         O

