a
    h                     @   s   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	m
Z
 dgZdd	d
dZedZeddd	Zeed eeddd	 i Zdd Zi ZG dd dZdd ZejdreZdddZdS )a|  
Code to support various backends in a plugin dispatch architecture.

Create a Dispatcher
-------------------

To be a valid backend, a package must register an entry_point
of `networkx.backends` with a key pointing to the handler.

For example::

    entry_points={'networkx.backends': 'sparse = networkx_backend_sparse'}

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

Continuing the example above::

    class WrappedSparse:
        __networkx_backend__ = "sparse"
        ...

When a dispatchable NetworkX algorithm encounters a Graph-like object
with a ``__networkx_backend__`` attribute, it will look for the associated
dispatch object in the entry_points, load it, and dispatch the work to it.


Testing
-------
To assist in validating the backend algorithm implementations, if an
environment variable ``NETWORKX_TEST_BACKEND`` is set to a registered
backend key, the dispatch machinery will automatically convert regular
networkx Graphs and DiGraphs to the backend equivalent by calling
``<backend dispatcher>.convert_from_nx(G, edge_attrs=edge_attrs, name=name)``.
Set ``NETWORKX_FALLBACK_TO_NX`` environment variable to have tests
use networkx graphs for algorithms not implemented by the backend.

The arguments to ``convert_from_nx`` are:

- ``G`` : networkx Graph
- ``edge_attrs`` : dict, optional
    Dict that maps 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
    Dict that maps node attribute 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.

The converted object is then passed to the backend implementation of
the algorithm. The result is then passed to
``<backend dispatcher>.convert_to_nx(result, name=name)`` to convert back
to a form expected by the NetworkX tests.

By defining ``convert_from_nx`` and ``convert_to_nx`` methods and setting
the environment variable, NetworkX will automatically route tests on
dispatchable algorithms to the backend, allowing the full networkx test
suite to be run against the backend implementation.

Example pytest invocation::

    NETWORKX_TEST_BACKEND=sparse pytest --pyargs networkx

Dispatchable algorithms which are not implemented by the backend
will cause a ``pytest.xfail()``, giving some indication that not all
tests are working, 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.

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=...))`.
    N)partial)entry_points   )NetworkXNotImplemented	_dispatchF)load_and_callc                C   s   t jdk r&t }| |vri S ||  }n
t| d}i }|D ]}|j|v r`tjd|j tdd q8|rz|  ||j< W q ty } z*tjd|j d| tdd W Y d }~qd }~0 0 q8|||j< q8|	dd  |S )	N)   
   )groupz)networkx backend defined more than once: r   )
stacklevelz0Error encountered when loading info for backend z: znx-loopback)
sysversion_infor   namewarningswarnRuntimeWarningload	Exceptionpop)r
   r   Zepsitemsrvepexc r   E/var/www/auris/lib/python3.9/site-packages/networkx/utils/backends.py_get_backendsc   s4    




r   znetworkx.pluginsznetworkx.plugin_infoTznetworkx.backendsznetworkx.backend_infoc                 C   s(   | t v rt |  S t|    }t | < |S N)_loaded_backendsbackendsr   )backend_namer   r   r   r   _load_backend   s    r    c                
   @   s   e Zd ZdZdZejdd 	 dkZ
dd ejddd	D Z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ddZddddZd d! Zd"d# Zd
S )%r   a  Dispatches to a backend algorithm based on input graph types.

    Parameters
    ----------
    func : function

    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.

    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, ``@_dispatch(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.

    FZNETWORKX_FALLBACK_TO_NXtruec                 C   s   g | ]}|  r|  qS r   )strip).0xr   r   r   
<listcomp>   s   z_dispatch.<listcomp>ZNETWORKX_AUTOMATIC_BACKENDS ,NGr   graphs
edge_attrs
node_attrspreserve_edge_attrspreserve_node_attrspreserve_graph_attrspreserve_all_attrsc          
         s  |d u r"t t|||||||	d	S t|tr6tdd d u rD|jt| |j_|j_|j	rzi |j	dd i_	n
dd i_	|j
_
|j_j|j |_|j_d _|__|_|_|p|	_|p|	_|p|	_|d urt|ttfstdt| dd |d urLt|ttfsLtdt| dd tjtttfsxtdtj dd tjtttfstd	tj dd tjttfstd
tj dd t|tr|di}nH|d u rn<t|tstdt| dd nt|dkr,tdd t _t _ |d u rNi _!n fdd|" D _!d _#fddt$" D _%t&v rtd d t&< S )Nr)   z-'name' and 'graphs' must be passed by keywordbackendz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.r   zBad type for graphs: z0'graphs' must contain at least one variable namec                    sl   i | ]d\}}|d     dkr<j |dd    pdn( dkrbj|d d    pdn||qS )   ?N])optional_graphsaddlist_graphs)r#   kv)lastselfvalr   r   
<dictcomp>M  s     z%_dispatch.__new__.<locals>.<dictcomp>c                    s(   h | ] \}}d |v r |d  v r|qS )	functionsr   )r#   r1   infor   r   r   	<setcomp>^  s   z$_dispatch.__new__.<locals>.<setcomp>z/Algorithm already exists in dispatch registry: )'r   r   
isinstancestr	TypeError__name__object__new____defaults____kwdefaults__
__module____qualname____dict__update__wrapped____doc__	_orig_doc_cached_doc	orig_funcr   r+   r,   r-   r.   r/   dicttypeboolsetlenKeyErrorr5   r7   r*   r   _sigbackend_infor   _registered_algorithms)
clsfuncr   r*   r+   r,   r-   r.   r/   r0   r   )r:   r   r;   r<   r   rG      s    












z_dispatch.__new__c                 C   s$   | j  }d ur|S |   }| _ |S r   )rQ   	_make_doc)r;   r   r   r   r   rO   k  s    z_dispatch.__doc__c                 C   s   || _ d | _d S r   )rP   rQ   )r;   r<   r   r   r   rO   r  s    c                 C   s   | j d u rt| j}tdd |j D sj|jg |j tjdtjj	d dtdtjj
d}n8|j ^ }}|jg |tjdtjj	d d|d}|| _ | j S )Nc                 s   s   | ]}|j tjjkV  qd S r   )kindinspect	ParameterVAR_KEYWORD)r#   pr   r   r   	<genexpr>}  s   z*_dispatch.__signature__.<locals>.<genexpr>r1   )defaultZbackend_kwargs)
parameters)rY   r`   	signaturerR   anyrf   valuesreplacera   KEYWORD_ONLYrb   )r;   sigrf   Zvar_keywordr   r   r   __signature__w  s@    


	z_dispatch.__signature__)r1   c            
      s  t s j|i |S |}|d ur6|t vr6td| i } j D ]\}}|t|k r~||v rtt j d||| }n4||v r|| }n"| jvrDt j d| nqD|d u r| jvrt j d|dqD|||< qD j	r j
r|d u r j j
d || jdS  jrt|} j| @ D ]<}t|| }|||< ||v rd|||< n|| j| < q8t fdd	| D }	|	r
 fd
d| D }
 j| @ D ]}|
dd	 || D  qn.tdd	 | D }	|	r
dd | D }
|	r&|
dh }t|dkr<t j d| |\}|d urr||krrt j d|d|d|t vrtd| d|
v r| j
vrtd j d j d| d| d	t|}t| jrd|
v r j||| jdS t| j|i |S td j d| |d urB j|||ddS  jr j
D ]8} j|g|R i |rP j||| jd  S qP j|i |S )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 graphr   fallback_to_nxc                 3   sB   | ]:\}}| j vr(t|d p8t|dntdd |D V  qdS )__networkx_backend____networkx_plugin__c                 s   s"   | ]}t |d pt |dV  qdS rp   rq   Nhasattr)r#   Zg2r   r   r   rd     s   
z/_dispatch.__call__.<locals>.<genexpr>.<genexpr>N)r7   rt   rh   r#   gnamegr;   r   r   rd     s   z%_dispatch.__call__.<locals>.<genexpr>c              	      s.   h | ]&\}}| j vrt|d t|ddqS rp   rq   networkx)r7   getattrru   rx   r   r   rA     s   

z%_dispatch.__call__.<locals>.<setcomp>c                 s   s"   | ]}t |d t |ddV  qdS )rp   rq   rz   Nr{   r#   rw   r   r   r   rd     s   
c                 s   s"   | ]}t |d pt |dV  qdS rr   rs   r}   r   r   r   rd     s   c              	   S   s    h | ]}t |d t |ddqS ry   r|   r}   r   r   r   rA     s   
rz   r2   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 F)r   rR   ImportErrorr*   r   rW   rD   r   r5   _is_testing_automatic_backends_convert_and_call_for_tests_fallback_to_nxr7   listkeysrh   rM   ri   r    rt   _convert_and_callr{   r   _can_backend_run)r;   r1   argskwargsr   Zgraphs_resolvedrv   posr<   Zhas_backendsZgraph_backend_namesZbackend_namesZgraph_backend_namer   rx   r   __call__  s    




	



	
	





z_dispatch.__call__c                O   s0   t |}t|| jo.t|d p.|| j||S )zCCan the specified backend run this algorithms with these arguments?can_run)r    rt   r   r   )r;   r   r   r   r1   r   r   r   r   B  s    z_dispatch._can_backend_runc                    s*  
j j|i |  
js6j}|d= j|fS 
j
jdu rLn~du rZdnptt	rʈj
 du stj
 rddn@j
 du rtt	rksttrƈv rddnddu rntt	rd dkrdd j
d	d
  D nttj
 r&ddnZj
 durFj
 d	in:
jdkr|tj
d dr|dd j
d jD ndnfdd D 
j	
j	du rn	du rdnt	t	rBj
	 du stj
	 rd	dnJj
	 du r>tt	r	ks4ttr>	v r>d	dnd	du rNntt	rƈd dkrdd j
d	d
  D n>tj
 rd	dn$j
 durj
 dindnfdd D 
jt| 
jD ]
jv r2 	
fddj
 D j
< nވj
 }|du rn
jv rVqtd d
j dttrd}}n}}t	trd}	}	n	}}	ttrЈv }
n}
t|dt|dddkr j|||	|||

jdj
< qj}|d= j|fS )z~Convert graph arguments to the specified backend.

        Returns
        -------
        args tuple and kwargs dict
        r1   FTNr   [c                 S   s   i | ]
}|d qS r2   r   r#   	edge_attrr   r   r   r=     s   z0_dispatch._convert_arguments.<locals>.<dictcomp>r2   Zto_numpy_arrayZdtypenamesc                 S   s   i | ]
}|d qS r   r   r   r   r   r   r=     s   c                    s@   i | ]8\}} j |  d urt|tr8 j |dn|qS )Nr2   	argumentsrB   rC   getr#   keyr<   )boundr   r   r   r=     s   c                 S   s   i | ]
}|d qS r   r   )r#   	node_attrr   r   r   r=     s   c                    s>   i | ]6\}} j |  d urt|tr6 j |n|qS r   r   r   )r   r   r   r   r=     s   c                    sD   g | ]<}t |d t |dddkr< j|jdn|qS )rp   rq   rz   r+   r,   r-   r.   r/   r   Z
graph_name)r{   convert_from_nxr   r}   )r1   r+   rv   r,   r-   r/   r.   r;   r   r   r%     s&   
z0_dispatch._convert_arguments.<locals>.<listcomp>z!Missing required graph argument `z` in z	 functionrp   rq   rz   r   )rm   bindapply_defaultsr*   r   r   r-   r+   rB   rC   r   callablerS   r   rt   r   r   r.   r,   r/   r    r7   r5   rD   r   rV   r{   r   )r;   r   r   r   Zbound_kwargsgraphZpreserve_edgesedgesZpreserve_nodesnodesZpreserve_graphr   )r1   r   r   r+   rv   r   r,   r-   r/   r.   r;   r   _convert_argumentsI  s   

	



	





z_dispatch._convert_argumentsrn   c             
   C   s   t |}| j|g|R i |sb|r4| j|i |S d| j d| }t|| jrZ|d7 }t|z,| |||\}}t|| j|i |}	W nJ tt	fy }
 z.|r| j|i |W  Y d}
~
S  W Y d}
~
n
d}
~
0 0 |	S )zOCall this dispatchable function with a backend, converting graphs if necessary.r   r    with the given argumentsN)
r    r   rR   r   rt   RuntimeErrorr   r{   NotImplementedErrorr   )r;   r   r   r   ro   r1   msgconverted_argsconverted_kwargsresultr   r   r   r   r   "  s$    z_dispatch._convert_and_callc             
   C   s  t |}| j|g|R i |sr|s*| js:| j|i |S ddl}d| j d| }t|| jrh|d7 }|| z,| |||\}}	t	|| j|i |	}
W n~ t
tfy } z`|r| j|i |W  Y d}~S ddl}||jr|jd n| j dt|j  W Y d}~n
d}~0 0 | jdv r| jj|i |	}|  | jj|i |}|  | jdkr||jd	 }|jd	 }|j D ]\}}|d
 |j| d
< qn| jdkr|jd dur||jd }|jd }|jd }|j D ]\}}|| |j| |< qnt| jdkr`|jd s`||jd }|jd }|j|j n0| jdkr|jd s||jd }|jd }|j D ]\}}|d |j| d< qn| jdkr|jd s||jd }|jd }||u r|S |j  |j|j |j  |j|j t|dr\t|dr\|j  |j|j t|drt|dr|j  |j|j |S |j|
| jdS )zECall this dispatchable function with a backend; for use with testing.r   Nr   r   r   z raised >   edmonds_karp_corecontracted_nodes
barycenterrelabel_nodesstochastic_graphr   RZflowr   attrr(   r   copyr   Zweightr   _pred_succr@   )r    r   r*   rR   pytestr   rt   Zxfailr   r{   r   r   r   rT   rE   rm   r   r   Zconvert_to_nxr   r   r   r   rL   rM   _nodeclearZ_adjr   r   )r;   r   r   r   ro   r1   r   r   r   r   r   r   r   Zbound2ZR1ZR2r8   r9   ZG1ZG2r   r   r   r   r   9  s~    

$










z%_dispatch._convert_and_call_for_testsc           
      C   s\  | j s| jS ddg}t| j D ]}t| }d|v rN|| d|d   n
|| d|vsn| j|d vrz|d q|d | j }d|v r|dd	 |d d
D  d}nd}d|v r*|r|d |d |d }t|D ]<}|d|  ||  }r|d|  |d qq|d q|  d	|}	| j
  d|	 S )NZBackendsz--------Zshort_summaryz : r>   r&   Zextra_docstringc                 s   s    | ]}|rd | n|V  qdS )z  Nr   )r#   liner   r   r   rd     s   z&_dispatch._make_doc.<locals>.<genexpr>
TFextra_parametersz  Extra parameters:z    z      z
    z

    )r   rP   sortedrZ   appendr   extendsplitr   joinrstrip)
r;   linesr1   r?   Z	func_infoZadd_gapr   paramdescZto_addr   r   r   r^     sD    






z_dispatch._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_dispatchr   rx   r   r   r   
__reduce__  s    z_dispatch.__reduce__)N)rE   rJ   rK   rO   r   osenvironr   r"   lowerr   r   r   rG   propertysetterrm   r   r   r   r   r   r^   r   r   r   r   r   r      sF   E  


! * ZR+c                 C   s   t |  S r   )r[   r@   r   r   r   r     s    r   Z_NETWORKX_BUILDING_DOCS_c                 K   s4   | d u rt tfi |S t| fi |}|j| _| S r   )r   r   _orig_dispatchrO   )r]   r   Zdispatched_funcr   r   r   r     s
    )N)rO   r`   r   r   r   	functoolsr   importlib.metadatar   	exceptionr   __all__r   r   rZ   rM   r   r    r[   r   r   r   r   r   r   r   r   r   <module>   s6   V!      ,