
    Pip0                        d Z ddlmZ ddlZddlmZmZmZmZ erddl	m
Z
  ej        e          Zd ZeefddZd fddZdd fddZdd fddZdgdgd d d fddZdS )a  Convert (to and) from rdflib graphs to other well known graph libraries.

Currently the following libraries are supported:

- networkx: MultiDiGraph, DiGraph, Graph
- graph_tool: Graph

Doctests in this file are all skipped, as we can't run them conditionally if
networkx or graph_tool are available and they would err otherwise.
see `../../test/test_extras_external_graph_libs.py` for conditional tests
    )annotationsN)TYPE_CHECKINGAnyDictList)Graphc                    | S )N )xs    u/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/rdflib/extras/external_graph_libs.py	_identityr      s    H    graphr   calc_weightsboolc                   t          |          sJ t          |          sJ t          |          sJ ddl}| D ]\  }}}	 ||           ||	          }}
|                    |
|          }|t          ||j                  r$ ||||	          }|rd|d<    |j        |
|fi | m|r|dxx         dz  cc<   d|v r. ||||	          }|d                             |d                    dS )a  Helper method for multidigraph, digraph and graph.

    Modifies nxgraph in-place!

    Args:
        graph: an rdflib.Graph.
        nxgraph: a networkx.Graph/DiGraph/MultiDigraph.
        calc_weights: If True adds a 'weight' attribute to each edge according
            to the count of s,p,o triples between s and o, which is meaningful
            for Graph/DiGraph.
        edge_attrs: Callable to construct edge data from s, p, o.
            'triples' attribute is handled specially to be merged.
            'weight' should not be generated if calc_weights==True.
            (see invokers below!)
        transform_s: Callable to transform node generated from s.
        transform_o: Callable to transform node generated from o.
    r   N   weighttriples)callablenetworkxget_edge_data
isinstanceMultiDiGraphadd_edgeextend)r   nxgraphr   
edge_attrstransform_stransform_onxspotstodatads                 r   _rdflib_to_networkx_graphr)      sM   2 JK     K      5 51aQQB$$R,,<:gr??<:aA&&D #!"XGR,,t,,,,  $X!#D  Jq!Q''Y&&q|4445 5r   c                
    d|iS )Nkeyr
   r"   r#   r$   s      r   <lambda>r-   N   s
    eQZ r   c                V    ddl }|                                }t          | |d|fi | |S )a&  Converts the given graph into a networkx.MultiDiGraph.

    The subjects and objects are the later nodes of the MultiDiGraph.
    The predicates are used as edge keys (to identify multi-edges).

    Args:
        graph: a rdflib.Graph.
        edge_attrs: Callable to construct later edge_attributes. It receives
            3 variables (s, p, o) and should construct a dictionary that is
            passed to networkx's add_edge(s, o, \*\*attrs) function.

            By default this will include setting the MultiDiGraph key=p here.
            If you don't want to be able to re-identify the edge later on, you
            can set this to `lambda s, p, o: {}`. In this case MultiDiGraph's
            default (increasing ints) will be used.

    Returns:
        networkx.MultiDiGraph

    Example:
        ```python
        >>> from rdflib import Graph, URIRef, Literal
        >>> g = Graph()
        >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l')
        >>> p, q = URIRef('p'), URIRef('q')
        >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)]
        >>> for t in edges:
        ...     g.add(t)
        ...
        >>> mdg = rdflib_to_networkx_multidigraph(g)
        >>> len(mdg.edges())
        4
        >>> mdg.has_edge(a, b)
        True
        >>> mdg.has_edge(a, b, key=p)
        True
        >>> mdg.has_edge(a, b, key=q)
        True

        >>> mdg = rdflib_to_networkx_multidigraph(g, edge_attrs=lambda s,p,o: {})
        >>> mdg.has_edge(a, b, key=0)
        True
        >>> mdg.has_edge(a, b, key=1)
        True
        ```
    r   NF)r   r   r)   )r   r   kwdsr!   mdgs        r   rdflib_to_networkx_multidigraphr1   M   sA    b 
//

CeS%DDtDDDJr   Tc                    d| ||fgiS Nr   r
   r,   s      r   r-   r-          	Q1I;7 r   c                V    ddl }|                                }t          | |||fi | |S )aC  Converts the given graph into a networkx.DiGraph.

    As an rdflib.Graph() can contain multiple edges between nodes, by default
    adds the a 'triples' attribute to the single DiGraph edge with a list of
    all triples between s and o.
    Also by default calculates the edge weight as the length of triples.

    Args:
        graph: a rdflib.Graph.
        calc_weights: If true calculate multi-graph edge-count as edge 'weight'
        edge_attrs: Callable to construct later edge_attributes. It receives
            3 variables (s, p, o) and should construct a dictionary that is passed to
            networkx's add_edge(s, o, \*\*attrs) function.

            By default this will include setting the 'triples' attribute here,
            which is treated specially by us to be merged. Other attributes of
            multi-edges will only contain the attributes of the first edge.
            If you don't want the 'triples' attribute for tracking, set this to
            `lambda s, p, o: {}`.

    Returns: networkx.DiGraph

    Example:
        ```python
        >>> from rdflib import Graph, URIRef, Literal
        >>> g = Graph()
        >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l')
        >>> p, q = URIRef('p'), URIRef('q')
        >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)]
        >>> for t in edges:
        ...     g.add(t)
        ...
        >>> dg = rdflib_to_networkx_digraph(g)
        >>> dg[a][b]['weight']
        2
        >>> sorted(dg[a][b]['triples']) == [(a, p, b), (a, q, b)]
        True
        >>> len(dg.edges())
        3
        >>> dg.size()
        3
        >>> dg.size(weight='weight')
        4.0

        >>> dg = rdflib_to_networkx_graph(g, False, edge_attrs=lambda s,p,o:{})
        >>> 'weight' in dg[a][b]
        False
        >>> 'triples' in dg[a][b]
        False
        ```
    r   N)r   DiGraphr)   )r   r   r   r/   r!   dgs         r   rdflib_to_networkx_digraphr8      s?    r 	BeRzJJTJJJIr   c                    d| ||fgiS r3   r
   r,   s      r   r-   r-      r4   r   c                V    ddl }|                                }t          | |||fi | |S )ai  Converts the given graph into a networkx.Graph.

    As an [`rdflib.Graph()`][rdflib.Graph] can contain multiple directed edges between nodes, by
    default adds the a 'triples' attribute to the single DiGraph edge with a list of triples between s and o in graph.
    Also by default calculates the edge weight as the `len(triples)`.

    Args:
        graph: a rdflib.Graph.
        calc_weights: If true calculate multi-graph edge-count as edge 'weight'
        edge_attrs: Callable to construct later edge_attributes. It receives
            3 variables (s, p, o) and should construct a dictionary that is
            passed to networkx's add_edge(s, o, \*\*attrs) function.

            By default this will include setting the 'triples' attribute here,
            which is treated specially by us to be merged. Other attributes of
            multi-edges will only contain the attributes of the first edge.
            If you don't want the 'triples' attribute for tracking, set this to
            `lambda s, p, o: {}`.

    Returns:
        networkx.Graph

    Example:
        ```python
        >>> from rdflib import Graph, URIRef, Literal
        >>> g = Graph()
        >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l')
        >>> p, q = URIRef('p'), URIRef('q')
        >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)]
        >>> for t in edges:
        ...     g.add(t)
        ...
        >>> ug = rdflib_to_networkx_graph(g)
        >>> ug[a][b]['weight']
        3
        >>> sorted(ug[a][b]['triples']) == [(a, p, b), (a, q, b), (b, p, a)]
        True
        >>> len(ug.edges())
        2
        >>> ug.size()
        2
        >>> ug.size(weight='weight')
        4.0

        >>> ug = rdflib_to_networkx_graph(g, False, edge_attrs=lambda s,p,o:{})
        >>> 'weight' in ug[a][b]
        False
        >>> 'triples' in ug[a][b]
        False
        ```
    r   N)r   r   r)   )r   r   r   r/   r!   gs         r   rdflib_to_networkx_graphr<      s?    r 


AeQjIIDIIIHr   termc                
    d| iS Nr=   r
   r,   s      r   r-   r-   	  
     r   c                
    d|iS r?   r
   r,   s      r   r-   r-   
  r@   r   c                
    d|iS r?   r
   r,   s      r   r-   r-     r@   r   v_prop_names	List[str]e_prop_namesc                   ddl }|                                fd|D             }|D ]\  }}	|	j        |<   fd|D             }
|
D ]\  }}|j        |<   i }| D ]\  }}}|                    |          }|;                                }|||<    ||||          }|D ]\  }}	||         |	|<   |}|                    |          }|;                                }|||<    ||||          }|D ]\  }}	||         |	|<   |}                    ||          } ||||          }|
D ]\  }}||         ||<   S )aa	  Converts the given graph into a graph_tool.Graph().

    The subjects and objects are the later vertices of the Graph.
    The predicates become edges.

    Args:
        graph: a rdflib.Graph.
        v_prop_names: a list of names for the vertex properties. The default is set
            to ['term'] (see transform_s, transform_o below).
        e_prop_names: a list of names for the edge properties.
        transform_s: callable with s, p, o input. Should return a dictionary
            containing a value for each name in v_prop_names. By default is set
            to {'term': s} which in combination with v_prop_names = ['term']
            adds s as 'term' property to the generated vertex for s.
        transform_p: similar to transform_s, but wrt. e_prop_names. By default
            returns {'term': p} which adds p as a property to the generated
            edge between the vertex for s and the vertex for o.
        transform_o: similar to transform_s.

    Returns: graph_tool.Graph()

    Example:
        ```python
        >>> from rdflib import Graph, URIRef, Literal
        >>> g = Graph()
        >>> a, b, l = URIRef('a'), URIRef('b'), Literal('l')
        >>> p, q = URIRef('p'), URIRef('q')
        >>> edges = [(a, p, b), (a, q, b), (b, p, a), (b, p, l)]
        >>> for t in edges:
        ...     g.add(t)
        ...
        >>> mdg = rdflib_to_graphtool(g)
        >>> len(list(mdg.edges()))
        4
        >>> from graph_tool import util as gt_util
        >>> vpterm = mdg.vertex_properties['term']
        >>> va = gt_util.find_vertex(mdg, vpterm, a)[0]
        >>> vb = gt_util.find_vertex(mdg, vpterm, b)[0]
        >>> vl = gt_util.find_vertex(mdg, vpterm, l)[0]
        >>> (va, vb) in [(e.source(), e.target()) for e in list(mdg.edges())]
        True
        >>> epterm = mdg.edge_properties['term']
        >>> len(list(gt_util.find_edge(mdg, epterm, p))) == 3
        True
        >>> len(list(gt_util.find_edge(mdg, epterm, q))) == 1
        True

        >>> mdg = rdflib_to_graphtool(
        ...     g,
        ...     e_prop_names=[str('name')],
        ...     transform_p=lambda s, p, o: {str('name'): unicode(p)})
        >>> epterm = mdg.edge_properties['name']
        >>> len(list(gt_util.find_edge(mdg, epterm, unicode(p)))) == 3
        True
        >>> len(list(gt_util.find_edge(mdg, epterm, unicode(q)))) == 1
        True
        ```
    r   Nc                >    g | ]}|                     d           fS object)new_vertex_property).0vpnr;   s     r   
<listcomp>z'rdflib_to_graphtool.<locals>.<listcomp>L  s,    MMMsA))(334MMMr   c                >    g | ]}|                     d           fS rH   )new_edge_property)rK   epnr;   s     r   rM   z'rdflib_to_graphtool.<locals>.<listcomp>O  s,    KKKssA''112KKKr   )
graph_toolr   vertex_propertiesedge_propertiesget
add_vertexr   )r   rC   rE   r   transform_pr    gtvpropsrL   vpropepropsrP   epropnode_to_vertexr"   r#   r$   svv	tmp_propsover;   s                         @r   rdflib_to_graphtoolrb     s   F 


AMMMMMMMF ) )
U#(C  KKKKlKKKF ' '
U!&#%'N & &1a"":A !N1#Aq!,,I$ * *
U$S>aB"":A !N1#Aq!,,I$ * *
U$S>aBJJr2K1a((	  	& 	&JC ~E!HH	&Hr   )r   r   r   r   )r   r   )r   r   rC   rD   rE   rD   )__doc__
__future__r   loggingtypingr   r   r   r   rdflib.graphr   	getLogger__name__loggerr   r)   r1   r8   r<   rb   r
   r   r   <module>rk      sc  
 
 # " " " " "  1 1 1 1 1 1 1 1 1 1 1 1 #"""""" 
	8	$	$   -5 -5 -5 -5 -5b 875 5 5 5 5t 77= = = = =D 77= = = = =D  &h%h++++++e e e e e e er   