
    01ip0                       S r SSKJr  SSKrSSKJrJrJrJr  \(       a  SSK	J
r
  \R                  " \5      rS r\\4   SS jjrS 4 SS	 jjrS
S 4   SS jjrS
S 4   SS jjrS/S/S S S 4     SS jjrg)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                    U $ )N )xs    [/home/james-whalen/.local/lib/python3.13/site-packages/rdflib/extras/external_graph_libs.py	_identityr      s    H    c                   [        U5      (       d   e[        U5      (       d   e[        U5      (       d   eSSKnU  H  u  pxn	U" U5      U" U	5      pUR                  X5      nUb  [        XR                  5      (       a*  U" XxU	5      nU(       a  SUS'   UR
                  " X40 UD6  Mm  U(       a  US==   S-  ss'   SU;   d  M  U" XxU	5      nUS   R                  US   5        M     g)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)graphnxgraphcalc_weights
edge_attrstransform_stransform_onxspotstodatads                 r   _rdflib_to_networkx_graphr(      s    2 JK    K    aQQB$$R,<:g??aA&D!"XR,t, X!#D qQ'Y&&q|4 r   c                
    SU0$ )Nkeyr
   r!   r"   r#   s      r   <lambda>r,   N   s    eQZr   c                J    SSK nUR                  5       n[        XSU40 UD6  U$ )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_multidigraphr0   M   s*    b 
//
Ce%DtDJr   Tc                    SXU4/0$ Nr   r
   r+   s      r   r,   r,          	Q1I;7r   c                H    SSK nUR                  5       n[        XX40 UD6  U$ )a  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_digraphr7      s'    r 	BeJTJIr   c                    SXU4/0$ r2   r
   r+   s      r   r,   r,      r3   r   c                H    SSK nUR                  5       n[        XX40 UD6  U$ )a  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eIDIHr   termc                
    SU 0$ Nr<   r
   r+   s      r   r,   r,   	      r   c                
    SU0$ r>   r
   r+   s      r   r,   r,   
  r?   r   c                
    SU0$ r>   r
   r+   s      r   r,   r,     r?   r   c                   SSK nUR                  5       nU Vs/ s H  oUR                  S5      4PM     n	nU	 H  u  pXR                  U'   M     U Vs/ s H  oUR	                  S5      4PM     nnU H  u  pXR
                  U'   M     0 nU  H  u  nnnUR                  U5      nUc3  UR                  5       nUX'   U" UUU5      nU	 H  u  pUU   U
U'   M     UnUR                  U5      nUc4  UR                  5       nUUU'   U" UUU5      nU	 H  u  pUU   U
U'   M     UnUR                  UU5      nU" UUU5      nU H  u  pUU   UU'   M     M     U$ s  snf s  snf )a  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   Nobject)	
graph_toolr   new_vertex_propertyvertex_propertiesnew_edge_propertyedge_propertiesget
add_vertexr   )r   v_prop_namese_prop_namesr   transform_pr   gtr:   vpnvpropsvpropepnepropsepropnode_to_vertexr!   r"   r#   svv	tmp_propsoves                          r   rdflib_to_graphtoolr[     s   F 

A@LMA))(34FM
#(C  >JKlsA''12lFK
!&# %'N1a":A !N#Aq!,I$
$S>a %B":A !N1#Aq!,I$
$S>a %BJJr21a(	 JC ~E!H !+ . H= N Ls   EE)r   r   r   bool)r   r   )r   r   rK   	List[str]rL   r]   )__doc__
__future__r   loggingtypingr   r   r   r   rdflib.graphr   	getLogger__name__loggerr   r(   r0   r7   r;   r[   r
   r   r   <module>rf      s   
 #  1 1" 
		8	$ -5-5 -5b 855t 7===D 7===D  &h%h+++eee er   