§
    kÃ¿a…-  ã                   ó¬   — d Z ddlZ ej        e¦  «        Zd„ Zeefd„Zd„ fd„Zdd„ fd	„Zdd
„ fd„Z	 e
d¦  «        g e
d¦  «        gd„ d„ d„ f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
é    Nc                 ó   — | S )N© )Úxs    úC/usr/lib/python3/dist-packages/rdflib/extras/external_graph_libs.pyÚ	_identityr      s   € Ø€Hó    c                 óÜ  — 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!

    Arguments:
        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"      sM  € õ2 �JÑÔÐÐÐÝ�KÑ Ô Ð Ð Ð Ý�KÑ Ô Ð Ð Ð ØÐÐÐàð 5ð 5‰ˆˆ1ˆaØ�˜Q‘”  ¨Q¡¤ˆBˆØ×$Ò$ R¨Ñ,Ô,ˆØˆ<�: g¨r¬Ñ?Ô?ˆ<à�:˜a  AÑ&Ô&ˆDØð #Ø!"��X‘ØˆGÔ˜R Ð,Ð, tÐ,Ð,Ð,Ð,ð ð $Ø�X��” !Ñ#��‘Ø˜DÐ Ð Ø�J˜q ! QÑ'Ô'�Ø�Y”×&Ò& q¨¤|Ñ4Ô4Ð4øð5ð 5r   c                 ó
   — d|iS )NÚkeyr   ©r   r   r   s      r   ú<lambda>r&   I   s
   €  u¨a j€ 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).

    :Parameters:

        - 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

    >>> 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_multidigraphr*   H   sA   € ð^ ÐÐÐà
�/Š/Ñ
Ô
€CÝ˜e S¨%°ÐDÐD¸tÐDÐDÐDØ€Jr   Tc                 ó   — d| ||fgiS ©Nr   r   r%   s      r   r&   r&   �   ó   €  	¨Q°°1¨I¨;Ð7€ r   c                 óV   — ddl }|                     ¦   «         }t          | |||fi |¤Ž |S )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.

    :Parameters:

        - `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

    >>> 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_digraphr1   ~   s?   € ðp ÐÐÐà	�Š‰Œ€BÝ˜e R¨°zÐJÐJÀTÐJÐJÐJØ€Ir   c                 ó   — d| ||fgiS r,   r   r%   s      r   r&   r&   À   r-   r   c                 óV   — ddl }|                     ¦   «         }t          | |||fi |¤Ž |S )a  Converts the given graph into a networkx.Graph.

    As an 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).

    :Parameters:

        - 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

    >>> 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   ÚGraphr"   )r   r   r   r(   r   Úgs         r   Úrdflib_to_networkx_graphr6   ½   s?   € ðp ÐÐÐà
�Š‰
Œ
€AÝ˜e Q¨°jÐIÐIÀDÐIÐIÐIØ€Hr   Útermc                 ó$   — t          d¦  «        | iS ©Nr7   ©Ústrr%   s      r   r&   r&      ó   € ¥ V¡¤¨aÐ 0€ r   c                 ó$   — t          d¦  «        |iS r9   r:   r%   s      r   r&   r&     r<   r   c                 ó$   — t          d¦  «        |iS r9   r:   r%   s      r   r&   r&     r<   r   c                 ó‚  ‡— ddl }|                     ¦   «         Šˆfd„|D ¦   «         }|D ]\  }}	|	‰j        |<   Œˆfd„|D ¦   «         }
|
D ]\  }}|‰j        |<   Œi }| D ]à\  }}}|                     |¦  «        }|€;‰                     ¦   «         }|||<    ||||¦  «        }|D ]\  }}	||         |	|<   Œ|}|                     |¦  «        }|€;‰                     ¦   «         }|||<    ||||¦  «        }|D ]\  }}	||         |	|<   Œ|}‰                     ||¦  «        } ||||¦  «        }|
D ]\  }}||         ||<   ŒŒá‰S )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.

    :Parameters:
        - 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()

    >>> 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Úvpnr5   s     €r   ú
<listcomp>z'rdflib_to_graphtool.<locals>.<listcomp>@  s,   ø€ ÐMÐMÐM¸ˆs�A×)Ò)¨(Ñ3Ô3Ð4ÐMÐMÐMr   c                 ó>   •— g | ]}|‰                      d ¦  «        f‘ŒS rA   )Únew_edge_property)rD   Úepnr5   s     €r   rF   z'rdflib_to_graphtool.<locals>.<listcomp>C  s,   ø€ ÐKÐKÐK°sˆs�A×'Ò'¨Ñ1Ô1Ð2ÐKÐKÐKr   )Ú
graph_toolr4   Úvertex_propertiesÚedge_propertiesÚgetÚ
add_vertexr   )r   Úv_prop_namesÚe_prop_namesr   Útransform_pr   ÚgtÚvpropsrE   ÚvpropÚepropsrI   ÚepropÚnode_to_vertexr   r   r   ÚsvÚvÚ	tmp_propsÚovÚer5   s                         @r   Úrdflib_to_graphtoolr]   ü   sÕ  ø€ ð@ ÐÐÐà
�Š‰
Œ
€AàMÐMÐMÐMÀÐMÑMÔM€FØð )ð )‰
ˆˆUØ#(ˆÔ˜CÑ Ð ØKÐKÐKÐK¸lÐKÑKÔK€FØð 'ð '‰
ˆˆUØ!&ˆÔ˜#ÑÐØ€NØð &ð &‰ˆˆ1ˆaØ×Ò Ñ"Ô"ˆØˆ:Ø—’‘”ˆAØ !ˆN˜1ÑØ#˜ A q¨!Ñ,Ô,ˆIØ$ð *ð *‘
��UØ$ Sœ>��a‘�ØˆBà×Ò Ñ"Ô"ˆØˆ:Ø—’‘”ˆAØ !ˆN˜1ÑØ#˜ A q¨!Ñ,Ô,ˆIØ$ð *ð *‘
��UØ$ Sœ>��a‘�ØˆBà�JŠJ�r˜2ÑÔˆØ�K  1 aÑ(Ô(ˆ	Ø ð 	&ð 	&‰JˆC�Ø  ”~ˆE�!‰HˆHð	&à€Hr   )Ú__doc__ÚloggingÚ	getLoggerÚ__name__Úloggerr   r"   r*   r1   r6   r;   r]   r   r   r   ú<module>rc      s  ðð	ð 	ð €€€à	ˆÔ	˜8Ñ	$Ô	$€ðð ð ð Øð-5ð -5ð -5ð -5ðb 1Ð0ð3ð 3ð 3ð 3ðp Ø7Ð7ð<ð <ð <ð <ðB Ø7Ð7ð<ð <ð <ð <ðB �#�f‘+”+�Ø�#�f‘+”+�Ø0Ð0Ø0Ð0Ø0Ð0ðbð bð bð bð bð br   