3
dY             $   @   s<  d Z ddlmZ ddlmZ ddlZddlZddl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ZddlmZmZ ddlT ddlmZmZmZ d	Zd
ZejeZdd Zdd Zdd ZejeiZ e!e"e#e$e%e&e'e&e(ee)ee*eiZ+dd Z,dd Z-dd Z.dd Z/G dd de0Z1G dd deZ2G dd de3Z4G dd  d e2Z5G d!d" d"e2Z6G d#d$ d$e0Z7G d%d& d&e7Z8G d'd( d(e7Z9G d)d* d*e8Z:G d+d, d,e8Z;G d-d. d.e9Z<G d/d0 d0e9Z=G d1d2 d2e9Z>G d3d4 d4e9Z?G d5d6 d6e9Z@G d7d8 d8e9ZAG d9d: d:e9ZBG d;d< d<e8ZCG d=d> d>e9ZDG d?d@ d@e9ZEG dAdB dBe9ZFG dCdD dDe9ZGG dEdF dFe9ZHG dGdH dHe9ZIG dIdJ dJeHZJG dKdL dLe9ZKeLe:eMe;eNe<eOe=ePe>eQe?eRe@eSeAeTeBeUeCeVeDeWeEeXeFeYeGeZeHe[eIe\eJe]eKiZ^e_e`eadMZbG dNdO dOecZdG dPdQ dQe0ZeG dRdS dSeeZfdTdU ZgdS )VzPython implementation of the W3C Provenance Data Model (PROV-DM), including
support for PROV-JSON import/export

References:

PROV-DM: http://www.w3.org/TR/prov-dm/
PROV-JSON: https://openprovenance.org/prov-json/
    )defaultdict)deepcopyN)urlparse)Errorserializers)*)
IdentifierQualifiedName	NamespacezTrung Dong Huynhztrungdong@donggiang.comc             C   s   t | trtjj| S | S d S )N)
isinstancestrdateutilparserparse)value r   */tmp/pip-build-7vycvbft/prov/prov/model.py_ensure_datetime"   s    
r   c             C   s&   yt jj| S  tk
r    Y nX d S )N)r   r   r   
ValueError)r   r   r   r   parse_xsd_datetime)   s
    r   c             C   s(   | j  dkrdS | j  dkr dS d S d S )	Nfalse0Ftrue1T)r   r   )r   r   )lower)r   r   r   r   parse_boolean1   s
    r   c             C   s   |t krt | | S d S )N)XSD_DATATYPE_PARSERS)r   datatyper   r   r   parse_xsd_typesK   s    r   c             C   s   t t| d S )N)nextiter)Za_setr   r   r   firstS   s    r!   c             C   s0   t | }|jdd}d|kr$d| S d| S d S )N"z\"
z"""%s"""z"%s")r   replace)r   sr   r   r   &_ensure_multiline_string_triple_quotedW   s
    r&   c             C   s\   t | trt| S t | tjr,dj| j S t | tr>d|  S t | trPd|  S t| S d S )Nz"{0}" %% xsd:dateTimez"%g" %%%% xsd:floatz"%i" %%%% xsd:boolean)r   r   r&   datetimeformat	isoformatfloatbool)r   r   r   r   encoding_provn_valueb   s    


r,   c               @   sr   e Zd ZdddZdd Zdd Zdd	 Zd
d Zdd Ze	dd Z
e	dd Ze	dd Zdd Zdd ZdS )LiteralNc             C   sz   t || _|rZ|d kr2tjd||f  td }n(|td krZtjd|||f  td }|| _|d k	rpt |nd | _d S )Nz<Assuming prov:InternationalizedString as the type of "%s"@%sZInternationalizedStringzOInvalid data type (%s) for "%s"@%s, overridden as prov:InternationalizedString.)r   _valueloggerdebugPROVwarning	_datatype_langtag)selfr   r   langtagr   r   r   __init__q   s    

zLiteral.__init__c             C   s   | j  S )N)provn_representation)r5   r   r   r   __str__   s    zLiteral.__str__c             C   s   d| j   S )Nz<Literal: %s>)r8   )r5   r   r   r   __repr__   s    zLiteral.__repr__c             C   s2   t |tr.| j|jko0| j|jko0| j|jkS dS )NF)r   r-   r.   r   r3   r   r4   r6   )r5   otherr   r   r   __eq__   s    .zLiteral.__eq__c             C   s
   | |k S )Nr   )r5   r;   r   r   r   __ne__   s    zLiteral.__ne__c             C   s   t | j| j| jfS )N)hashr.   r3   r4   )r5   r   r   r   __hash__   s    zLiteral.__hash__c             C   s   | j S )N)r.   )r5   r   r   r   r      s    zLiteral.valuec             C   s   | j S )N)r3   )r5   r   r   r   r      s    zLiteral.datatypec             C   s   | j S )N)r4   )r5   r   r   r   r6      s    zLiteral.langtagc             C   s
   | j d kS )N)r4   )r5   r   r   r   has_no_langtag   s    zLiteral.has_no_langtagc             C   s:   | j rdt| jt| j f S dt| jt| jf S d S )Nz%s@%sz
%s %%%% %s)r4   r&   r.   r   r3   )r5   r   r   r   r8      s    zLiteral.provn_representation)NN)__name__
__module____qualname__r7   r9   r:   r<   r=   r?   propertyr   r   r6   r@   r8   r   r   r   r   r-   p   s   
r-   c               @   s   e Zd ZdZdS )ProvExceptionz%Base class for PROV model exceptions.N)rA   rB   rC   __doc__r   r   r   r   rE      s   rE   c               @   s   e Zd ZdZdS )ProvWarningz#Base class for PROV model warnings.N)rA   rB   rC   rF   r   r   r   r   rG      s   rG   c               @   s$   e Zd ZdZdZdd Zdd ZdS )!ProvExceptionInvalidQualifiedNamez3Exception for an invalid qualified identifier name.Nc             C   s
   || _ dS )zM
        Constructor.

        :param qname: Invalid qualified name.
        N)qname)r5   rI   r   r   r   r7      s    z*ProvExceptionInvalidQualifiedName.__init__c             C   s
   d| j  S )NzInvalid Qualified Name: %s)rI   )r5   r   r   r   r9      s    z)ProvExceptionInvalidQualifiedName.__str__)rA   rB   rC   rF   rI   r7   r9   r   r   r   r   rH      s   rH   c               @   s   e Zd ZdZdd ZdS )ProvElementIdentifierRequiredz+Exception for a missing element identifier.c             C   s   dS )NzGAn identifier is missing. All PROV elements require a valid identifier.r   )r5   r   r   r   r9      s    z%ProvElementIdentifierRequired.__str__N)rA   rB   rC   rF   r9   r   r   r   r   rJ      s   rJ   c               @   s   e Zd ZdZf ZdZd/ddZdd Zdd Zd	d
 Z	dd Z
dd Zdd Zedd Zedd Zedd Zedd Zedd Zedd Zedd Zedd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. ZdS )0
ProvRecordzBase class for PROV records.Nc             C   s(   || _ || _tt| _|r$| j| dS )z
        Constructor.

        :param bundle: Bundle for the PROV record.
        :param identifier: (Unique) identifier of the record.
        :param attributes: Attributes to associate with the record (default: None).
        N)_bundle_identifierr   set_attributesadd_attributes)r5   bundle
identifier
attributesr   r   r   r7      s
    
zProvRecord.__init__c             C   s   t | j | jt| jfS )N)r>   get_typerM   	frozensetrS   )r5   r   r   r   r?      s    zProvRecord.__hash__c             C   s   t | j  | j| j| jS )z6
        Return an exact copy of this record.
        )PROV_REC_CLSrT   rL   rR   rS   )r5   r   r   r   copy   s    
zProvRecord.copyc             C   s   | j S )z$Returns the PROV type of the record.)
_prov_type)r5   r   r   r   rT     s    zProvRecord.get_typec             C   s
   | j t S )z:Returns the set of all asserted PROV types of this record.)rO   	PROV_TYPE)r5   r   r   r   get_asserted_types	  s    zProvRecord.get_asserted_typesc             C   s   | j t j| dS )z~
        Adds a PROV type assertion to the record.

        :param type_identifier: PROV namespace identifier to add.
        N)rO   rY   add)r5   Ztype_identifierr   r   r   add_asserted_type  s    zProvRecord.add_asserted_typec             C   s   | j j|}| j| S )z
        Returns the attribute of the given name.

        :param attr_name: Name of the attribute.
        :return: Tuple (name, value)
        )rL   valid_qualified_namerO   )r5   	attr_namer   r   r   get_attribute  s    zProvRecord.get_attributec             C   s   | j S )zRecord's identifier.)rM   )r5   r   r   r   rR     s    zProvRecord.identifierc             C   s   dd | j j D S )zW
        All record attributes.

        :return: List of tuples (name, value)
        c             S   s"   g | ]\}}|D ]}||fqqS r   r   ).0r^   valuesr   r   r   r   
<listcomp>,  s   z)ProvRecord.attributes.<locals>.<listcomp>)rO   items)r5   r   r   r   rS   $  s    zProvRecord.attributesc                s   t  fdd jD S )zW
        All values of the record's formal attributes.

        :return: Tuple
        c             3   s   | ]}t  j| V  qd S )N)r!   rO   )r`   r^   )r5   r   r   	<genexpr>9  s    z"ProvRecord.args.<locals>.<genexpr>)tupleFORMAL_ATTRIBUTES)r5   r   )r5   r   args1  s    zProvRecord.argsc                s   t  fdd jD S )zy
        All names and values of the record's formal attributes.

        :return: Tuple of tuples (name, value)
        c             3   s    | ]}|t  j| fV  qd S )N)r!   rO   )r`   r^   )r5   r   r   rd   D  s   z/ProvRecord.formal_attributes.<locals>.<genexpr>)re   rf   )r5   r   )r5   r   formal_attributes<  s    
zProvRecord.formal_attributesc                s    fdd j D S )z
        All names and values of the record's attributes that are not formal
        attributes.

        :return: Tuple of tuples (name, value)
        c                s"   g | ]\}}| j kr||fqS r   )rf   )r`   r^   
attr_value)r5   r   r   rb   Q  s   z/ProvRecord.extra_attributes.<locals>.<listcomp>)rS   )r5   r   )r5   r   extra_attributesH  s    	
zProvRecord.extra_attributesc             C   s   | j S )zP
        Bundle of the record.

        :return: :py:class:`ProvBundle`
        )rL   )r5   r   r   r   rQ   V  s    zProvRecord.bundlec             C   s   | j t rt| j t S | jS )z Identifying label of the record.)rO   
PROV_LABELr!   rM   )r5   r   r   r   label_  s    zProvRecord.labelc             C   s
   | j t S )zValue of the record.)rO   
PROV_VALUE)r5   r   r   r   r   h  s    zProvRecord.valuec             C   s|   t |tr|j}t |tr"t|S t |tr8| jj|S t |trx|j rx|j	r`t
|j|j	}n| j|j}|d k	rx|S |S )N)r   rK   rR   r   r	   rL   r]   r-   r@   r   r   r   _auto_literal_conversion)r5   literalr   r   r   r   rn   n  s    


z#ProvRecord._auto_literal_conversionc       
      C   sV  |rRt |tr|j }tdd |D kr0d}nd}x|D ]\}}|dkrPq<| jj|}|dkrlt||tkrt |tr|j	n|}| jj|}n,|t
krt |tjr|nt|}n
| j|}|dkrtd||f | o|tko| j| r>t| j| }d}	y||k}	W n tk
r(   Y nX |	r<td| nq<| j| j| q<W dS )a  
        Add attributes to the record.

        :param attributes: Dictionary of attributes, with keys being qualified
            identifiers. Alternatively an iterable of tuples (key, value) with the
            keys satisfying the same condition.
        c             S   s   g | ]}|d  qS )r   r   )r`   Z_ir   r   r   rb     s    z-ProvRecord.add_attributes.<locals>.<listcomp>TFNz"Invalid value for attribute %s: %sz0Cannot have more than one value for attribute %s)r   dictrc   PROV_ATTR_COLLECTIONrL   r]   rH   ZPROV_ATTRIBUTE_QNAMESrK   rR   ZPROV_ATTRIBUTE_LITERALSr'   r   rn   rE   ZPROV_ATTRIBUTESrO   r!   	TypeErrorr[   )
r5   rS   Zis_collectionr^   original_valueattrrI   r   Zexisting_valueZis_not_same_valuer   r   r   rP     sJ    


zProvRecord.add_attributesc             C   sN   t |tsdS | j |j kr"dS | jr:| j|jk r:dS t| jt|jkS )NF)r   rK   rT   rM   rN   rS   )r5   r;   r   r   r   r<     s    
zProvRecord.__eq__c             C   s   | j  S )N)	get_provn)r5   r   r   r   r9     s    zProvRecord.__str__c       	      C   s@  g }d}| j r4t| j }| j r,|j| n|d }x^| jD ]T}|| jkr| j| rt| j| }|jt|tjrz|j	 nt| q<|jd q<W g }xl| jD ]b}|| jkrxR| j| D ]D}y|j
 }W n tk
r   t|}Y nX |jdt||f  qW qW |r |jddj|  dt| j  |dj|f }|S )z[
        Returns the PROV-N representation of the record.

        :return: String
         z; -z%s=%sz[%s]z, z%s(%s%s))rM   r   
is_elementappendrf   rO   r!   r   r'   r)   r8   AttributeErrorr,   joinZ
PROV_N_MAPrT   )	r5   rc   Zrelation_idrR   rt   r   extraZprovn_represenationZprov_nr   r   r   ru     s<    


zProvRecord.get_provnc             C   s   dS )z\
        True, if the record is an element, False otherwise.

        :return: bool
        Fr   )r5   r   r   r   rx     s    zProvRecord.is_elementc             C   s   dS )z\
        True, if the record is a relation, False otherwise.

        :return: bool
        Fr   )r5   r   r   r   is_relation   s    zProvRecord.is_relation)N)rA   rB   rC   rF   rf   rX   r7   r?   rW   rT   rZ   r\   r_   rD   rR   rS   rg   rh   rj   rQ   rl   r   rn   rP   r<   r9   ru   rx   r}   r   r   r   r   rK      s2   

		L
7rK   c                   s2   e Zd ZdZd	 fdd	Zdd Zdd Z  ZS )
ProvElementz3Provenance Element (nodes in the provenance graph).Nc                s&   |d krt  tt| j||| d S )N)rJ   superr~   r7   )r5   rQ   rR   rS   )	__class__r   r   r7   -  s    zProvElement.__init__c             C   s   dS )z\
        True, if the record is an element, False otherwise.

        :return: bool
        Tr   )r5   r   r   r   rx   4  s    zProvElement.is_elementc             C   s   d| j j| jf S )Nz<%s: %s>)r   rA   rM   )r5   r   r   r   r:   <  s    zProvElement.__repr__)N)rA   rB   rC   rF   r7   rx   r:   __classcell__r   r   )r   r   r~   *  s   r~   c               @   s    e Zd ZdZdd Zdd ZdS )ProvRelationz-Provenance Relationship (edge between nodes).c             C   s   dS )z\
        True, if the record is a relation, False otherwise.

        :return: bool
        Tr   )r5   r   r   r   r}   C  s    zProvRelation.is_relationc             C   sD   | j rd| j  nd}dd | jd d D \}}d| jj|||f S )Nz %srv   c             S   s   g | ]\}}|qS r   r   )r`   _rI   r   r   r   rb   M  s    z)ProvRelation.__repr__.<locals>.<listcomp>   z<%s:%s (%s, %s)>)rM   rh   r   rA   )r5   rR   Z	element_1Z	element_2r   r   r   r:   K  s    zProvRelation.__repr__N)rA   rB   rC   rF   r}   r:   r   r   r   r   r   @  s   r   c               @   sT   e Zd ZdZeZdddZdddZdddZdd	d
Z	dd Z
dd Zdd ZdS )
ProvEntityzProvenance Entity elementNc             C   s   | j j| |||d | S )a%  
        Creates a new generation record to this entity.

        :param activity: Activity or string identifier of the activity involved in
            the generation (default: None).
        :param time: Optional time for the generation (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )other_attributes)rL   
generation)r5   activitytimerS   r   r   r   wasGeneratedBy^  s    zProvEntity.wasGeneratedByc             C   s   | j j| |||d | S )a,  
        Creates a new invalidation record for this entity.

        :param activity: Activity or string identifier of the activity involved in
            the invalidation (default: None).
        :param time: Optional time for the invalidation (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   invalidation)r5   r   r   rS   r   r   r   wasInvalidatedBym  s    zProvEntity.wasInvalidatedByc             C   s   | j j| |||||d | S )a  
        Creates a new derivation record for this entity from a used entity.

        :param usedEntity: Entity or a string identifier for the used entity.
        :param activity: Activity or string identifier of the activity involved in
            the derivation (default: None).
        :param generation: Optionally extra activity to state qualified derivation
            through an internal generation (default: None).
        :param usage: Optionally extra entity to state qualified derivation through
            an internal usage (default: None).
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   
derivation)r5   
usedEntityr   r   usagerS   r   r   r   wasDerivedFrom|  s    zProvEntity.wasDerivedFromc             C   s   | j j| ||d | S )aU  
        Creates a new attribution record between this entity and an agent.

        :param agent: Agent or string identifier of the agent involved in the
            attribution.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   attribution)r5   agentrS   r   r   r   wasAttributedTo  s    	zProvEntity.wasAttributedToc             C   s   | j j| | | S )z
        Creates a new alternate record between this and another entity.

        :param alternate2: Entity or a string identifier for the second entity.
        )rL   	alternate)r5   
alternate2r   r   r   alternateOf  s    zProvEntity.alternateOfc             C   s   | j j| | | S )z
        Creates a new specialisation record for this from a general entity.

        :param generalEntity: Entity or a string identifier for the general entity.
        )rL   specialization)r5   generalEntityr   r   r   specializationOf  s    zProvEntity.specializationOfc             C   s   | j j| | | S )z
        Creates a new membership record to an entity for a collection.

        :param entity: Entity to be added to the collection.
        )rL   
membership)r5   entityr   r   r   	hadMember  s    zProvEntity.hadMember)NN)NN)NNNN)N)rA   rB   rC   rF   PROV_ENTITYrX   r   r   r   r   r   r   r   r   r   r   r   r   W  s   



		r   c               @   sh   e Zd ZdZeefZeZdddZ	dd Z
dd Zdd	d
ZdddZdddZdddZdddZdS )ProvActivityzProvenance Activity element.Nc             C   s,   |dk	r|h| j t< |dk	r(|h| j t< dS )a  
        Sets the time this activity took place.

        :param startTime: Start time for the activity.
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param endTime: Start time for the activity.
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        N)rO   PROV_ATTR_STARTTIMEPROV_ATTR_ENDTIME)r5   	startTimeendTimer   r   r   set_time  s    zProvActivity.set_timec             C   s   | j t }|rt|S dS )zh
        Returns the time the activity started.

        :return: :py:class:`datetime.datetime`
        N)rO   r   r!   )r5   ra   r   r   r   get_startTime  s    
zProvActivity.get_startTimec             C   s   | j t }|rt|S dS )zf
        Returns the time the activity ended.

        :return: :py:class:`datetime.datetime`
        N)rO   r   r!   )r5   ra   r   r   r   get_endTime  s    
zProvActivity.get_endTimec             C   s   | j j| |||d | S )a   
        Creates a new usage record for this activity.

        :param entity: Entity or string identifier of the entity involved in
            the usage relationship (default: None).
        :param time: Optional time for the usage (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   r   )r5   r   r   rS   r   r   r   used  s    zProvActivity.usedc             C   s   | j j| ||d | S )a)  
        Creates a new communication record for this activity.

        :param informant: The informing activity (relationship source).
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   communication)r5   	informantrS   r   r   r   wasInformedBy  s    zProvActivity.wasInformedByc             C   s   | j j| ||||d | S )a  
        Creates a new start record for this activity. The activity did not exist
        before the start by the trigger.

        :param trigger: Entity triggering the start of this activity.
        :param starter: Optionally extra activity to state a qualified start
            through which the trigger entity for the start is generated
            (default: None).
        :param time: Optional time for the start (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   start)r5   triggerstarterr   rS   r   r   r   wasStartedBy  s    zProvActivity.wasStartedByc             C   s   | j j| ||||d | S )a  
        Creates a new end record for this activity.

        :param trigger: Entity triggering the end of this activity.
        :param ender: Optionally extra activity to state a qualified end through
            which the trigger entity for the end is generated (default: None).
        :param time: Optional time for the end (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   end)r5   r   enderr   rS   r   r   r   
wasEndedBy  s    zProvActivity.wasEndedByc             C   s   | j j| |||d | S )a  
        Creates a new association record for this activity.

        :param agent: Agent or string identifier of the agent involved in the
            association (default: None).
        :param plan: Optionally extra entity to state qualified association through
            an internal plan (default: None).
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   association)r5   r   planrS   r   r   r   wasAssociatedWith!  s    zProvActivity.wasAssociatedWith)NN)NN)N)NNN)NNN)NN)rA   rB   rC   rF   r   r   rf   PROV_ACTIVITYrX   r   r   r   r   r   r   r   r   r   r   r   r   r     s   
	



r   c               @   s   e Zd ZdZeeefZeZ	dS )ProvGenerationz#Provenance Generation relationship.N)
rA   rB   rC   rF   PROV_ATTR_ENTITYPROV_ATTR_ACTIVITYPROV_ATTR_TIMErf   PROV_GENERATIONrX   r   r   r   r   r   0  s   
r   c               @   s   e Zd ZdZeeefZeZ	dS )	ProvUsagezProvenance Usage relationship.N)
rA   rB   rC   rF   r   r   r   rf   
PROV_USAGErX   r   r   r   r   r   8  s   
r   c               @   s   e Zd ZdZeefZeZdS )ProvCommunicationz&Provenance Communication relationship.N)	rA   rB   rC   rF   PROV_ATTR_INFORMEDPROV_ATTR_INFORMANTrf   PROV_COMMUNICATIONrX   r   r   r   r   r   @  s   r   c               @   s    e Zd ZdZeeeefZe	Z
dS )	ProvStartzProvenance Start relationship.N)rA   rB   rC   rF   r   PROV_ATTR_TRIGGERPROV_ATTR_STARTERr   rf   
PROV_STARTrX   r   r   r   r   r   H  s   r   c               @   s    e Zd ZdZeeeefZe	Z
dS )ProvEndzProvenance End relationship.N)rA   rB   rC   rF   r   r   PROV_ATTR_ENDERr   rf   PROV_ENDrX   r   r   r   r   r   U  s   r   c               @   s   e Zd ZdZeeefZeZ	dS )ProvInvalidationz%Provenance Invalidation relationship.N)
rA   rB   rC   rF   r   r   r   rf   PROV_INVALIDATIONrX   r   r   r   r   r   b  s   
r   c               @   s"   e Zd ZdZeeeeefZ	e
ZdS )ProvDerivationz#Provenance Derivation relationship.N)rA   rB   rC   rF   PROV_ATTR_GENERATED_ENTITYPROV_ATTR_USED_ENTITYr   PROV_ATTR_GENERATIONPROV_ATTR_USAGErf   PROV_DERIVATIONrX   r   r   r   r   r   k  s   r   c               @   s   e Zd ZdZeZdddZdS )	ProvAgentzProvenance Agent element.Nc             C   s   | j j| |||d | S )a  
        Creates a new delegation record on behalf of this agent.

        :param responsible: Agent the responsibility is delegated to.
        :param activity: Optionally extra activity to state qualified delegation
            internally (default: None).
        :param attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   )rL   
delegation)r5   responsibler   rS   r   r   r   actedOnBehalfOf  s    
zProvAgent.actedOnBehalfOf)NN)rA   rB   rC   rF   
PROV_AGENTrX   r   r   r   r   r   r   z  s   r   c               @   s   e Zd ZdZeefZeZdS )ProvAttributionz$Provenance Attribution relationship.N)	rA   rB   rC   rF   r   PROV_ATTR_AGENTrf   PROV_ATTRIBUTIONrX   r   r   r   r   r     s   r   c               @   s   e Zd ZdZeeefZeZ	dS )ProvAssociationz$Provenance Association relationship.N)
rA   rB   rC   rF   r   r   PROV_ATTR_PLANrf   PROV_ASSOCIATIONrX   r   r   r   r   r     s   
r   c               @   s   e Zd ZdZeeefZeZ	dS )ProvDelegationz#Provenance Delegation relationship.N)
rA   rB   rC   rF   PROV_ATTR_DELEGATEPROV_ATTR_RESPONSIBLEr   rf   PROV_DELEGATIONrX   r   r   r   r   r     s   
r   c               @   s   e Zd ZdZeefZeZdS )ProvInfluencez"Provenance Influence relationship.N)	rA   rB   rC   rF   PROV_ATTR_INFLUENCEEPROV_ATTR_INFLUENCERrf   PROV_INFLUENCErX   r   r   r   r   r     s   r   c               @   s   e Zd ZdZeefZeZdS )ProvSpecializationz'Provenance Specialization relationship.N)	rA   rB   rC   rF   PROV_ATTR_SPECIFIC_ENTITYPROV_ATTR_GENERAL_ENTITYrf   PROV_SPECIALIZATIONrX   r   r   r   r   r     s   r   c               @   s   e Zd ZdZeefZeZdS )ProvAlternatez"Provenance Alternate relationship.N)	rA   rB   rC   rF   PROV_ATTR_ALTERNATE1PROV_ATTR_ALTERNATE2rf   PROV_ALTERNATErX   r   r   r   r   r     s   r   c               @   s   e Zd ZdZeeefZeZ	dS )ProvMentionz:Provenance Mention relationship (specific Specialization).N)
rA   rB   rC   rF   r   r   PROV_ATTR_BUNDLErf   PROV_MENTIONrX   r   r   r   r   r     s
   r   c               @   s   e Zd ZdZeefZeZdS )ProvMembershipz#Provenance Membership relationship.N)	rA   rB   rC   rF   rq   r   rf   PROV_MEMBERSHIPrX   r   r   r   r   r     s   r   )provZxsdxsic               @   sh   e Zd ZdZdZdddZdd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd ZdddZdd ZdS )NamespaceManagerz2Manages namespaces for PROV documents and bundles.Nc             C   sn   t j|  t| _| j| j i | _|dk	r6| j| nd| _|| _d| _	t  | _
t  | _t  | _| j| dS )aW  
        Constructor.

        :param namespaces: Optional namespaces to add to the manager
            (default: None).
        :param default: Optional default namespace to use (default: None).
        :param parent: Optional parent :py:class:`NamespaceManager` to make this
            namespace manager a child of (default: None).
        Nr   )rp   r7   DEFAULT_NAMESPACESZ_default_namespacesupdate_namespacesset_default_namespace_defaultparent_anon_id_count_uri_map_rename_map_prefix_renamed_mapadd_namespaces)r5   
namespacesdefaultr   r   r   r   r7     s    

zNamespaceManager.__init__c             C   s$   x| j  D ]}||jkr
|S q
W dS )z
        Returns the namespace prefix for the given URI.

        :param uri: Namespace URI.
        :return: :py:class:`~prov.identifier.Namespace`.
        N)ra   Z_uri)r5   uri	namespacer   r   r   get_namespace  s    
zNamespaceManager.get_namespacec             C   s
   | j j S )zz
        Returns all registered namespaces.

        :return: Iterable of :py:class:`~prov.identifier.Namespace`.
        )r   ra   )r5   r   r   r   get_registered_namespaces  s    z*NamespaceManager.get_registered_namespacesc             C   s   t d|| _| j| d< dS )zk
        Sets the default namespace to the one of a given URI.

        :param uri: Namespace URI.
        rv   N)r
   r   )r5   r   r   r   r   r   '  s    z&NamespaceManager.set_default_namespacec             C   s   | j S )zi
        Returns the default namespace.

        :return: :py:class:`~prov.identifier.Namespace`
        )r   )r5   r   r   r   get_default_namespace0  s    z&NamespaceManager.get_default_namespacec             C   s   || j  kr|S || jkr$| j| S |j}|j}|| jkr\| j| }|| j|< || j|< |S || kr| j|}t||j}|| j|< || j|< |}|}|| j|< || |< || j|< |S )z
        Adds a namespace (if not available, yet).

        :param namespace: :py:class:`~prov.identifier.Namespace` to add.
        )	ra   r   r   prefixr   r   _get_unused_prefixr
   r   )r5   r   r   r  existing_ns
new_prefixZnew_namespacer   r   r   add_namespace8  s,    










zNamespaceManager.add_namespacec             C   s<   t |trdd |j D }|r8x|D ]}| j| q&W dS )a  
        Add multiple namespaces into this manager.

        :param namespaces: A collection of namespace(s) to add.
        :type namespaces: List of :py:class:`~prov.identifier.Namespace` or
            dict of {prefix: uri}.
        :returns: None
        c             S   s   g | ]\}}t ||qS r   )r
   )r`   r  r   r   r   r   rb   n  s    z3NamespaceManager.add_namespaces.<locals>.<listcomp>N)r   rp   rc   r  )r5   r   nsr   r   r   r   b  s
    	

zNamespaceManager.add_namespacesc       
      C   s  |sdS t |tr|j}|j}|j}|sr| j|kr>| j| }q| jdkrR|| _|S td|j}| j|}|| }nJ|| kr| | |kr| | }||kr|S || }n| jt	|}||j }|S t |t
tfsdS t |tr|jnt
|}	|	jd rdS d|	krz|	jdd\}}|| kr*| | | S || jkrD| j| | S xF| j D ]&}|	j|jrN||	j|jd S qNW n| jr| j| S | jr| jj|S dS )a+  
        Resolves an identifier to a valid qualified name.

        :param qname: Qualified name as :py:class:`~prov.identifier.QualifiedName`
            or a tuple (namespace, identifier).
        :return: :py:class:`~prov.identifier.QualifiedName` or None in case of
            failure.
        Ndnz_::   rv   )r   r	   r   r  Z	localpartr   r
   r   r  r   r   r   
startswithsplitr   ra   r$   r   r]   )
r5   rI   r   r  Z
local_partZ	new_qnameZdn_namespacer  r	  Z	str_valuer   r   r   r]   s  sT    	









z%NamespaceManager.valid_qualified_nameidc             C   s    |  j d7  _ td|| j f S )z
        Returns an anonymous identifier (without a namespace prefix).

        :param local_prefix: Optional local namespace prefix as a string
            (default: 'id').
        :return: :py:class:`~prov.identifier.Identifier`
        r  z_:%s%d)r   r   )r5   Zlocal_prefixr   r   r   get_anonymous_identifier  s    z)NamespaceManager.get_anonymous_identifierc             C   sB   || kr|S d}x,dj |t|f}|| kr6|d7 }q|S qW d S )Nr  r   )r{   r   )r5   Zoriginal_prefixcountr  r   r   r   r    s    
z#NamespaceManager._get_unused_prefix)NNN)r  )rA   rB   rC   rF   r   r7   r  r  r   r  r  r   r]   r  r  r   r   r   r   r     s   
	*U
r   c               @   s4  e Zd ZdZdjddZdd Zedd Zed	d
 Zedd Z	edd Z
edd Zdd Zdd ZdkddZdd Zdd ZdlddZdd Zdd  Zd!d" Zd#d$ Zed%d& Zdmd(d)Zd*d+ Zd,d- ZdZd.d/ Zd0d1 Zd2d3 Zd4d5 Zdnd6d7Zd8d9 Z dod:d;Z!dpd<d=Z"dqd>d?Z#drd@dAZ$dsdBdCZ%dtdDdEZ&dudFdGZ'dvdHdIZ(dwdJdKZ)dxdLdMZ*dydNdOZ+dzdPdQZ,d{dRdSZ-d|dTdUZ.d}dVdWZ/d~dXdYZ0ddZd[Z1d\d] Z2d^d_ Z3d`da Z4ddbdcZ5ddde Z6ddhdiZ7e#Z8e$Z9e%Z:e&Z;e'Z<e(Z=e*Z>e+Z?e,Z@e-ZAe.ZBe/ZCe0ZDe1ZEe3ZFe2ZGe4ZHe6ZIdS )
ProvBundlezPROV BundleNc             C   sZ   || _ t | _tt| _|| _t||dk	r0|jndd| _|rVx|D ]}| j| qDW dS )a  
        Constructor.

        :param records: Optional iterable of records to add to the bundle
            (default: None).
        :param identifier: Optional identifier of the bundle (default: None).
        :param namespaces: Optional iterable of :py:class:`~prov.identifier.Namespace`s
            to set the document up with (default: None).
        :param document: Optional document to add to the bundle (default: None).
        N)r   )	rM   list_recordsr   _id_map	_documentr   r   
add_record)r5   recordsrR   r   documentrecordr   r   r   r7     s    

zProvBundle.__init__c             C   s   d| j j| jf S )Nz<%s: %s>)r   rA   rM   )r5   r   r   r   r:     s    zProvBundle.__repr__c             C   s   t | jj S )z|
        Returns the set of registered namespaces.

        :return: Set of :py:class:`~prov.identifier.Namespace`.
        )rN   r   r  )r5   r   r   r   r     s    zProvBundle.namespacesc             C   s   | j j }|r|jS dS )z_
        Returns the default namespace's URI, if any.

        :return: URI as string.
        N)r   r  r   )r5   Z
default_nsr   r   r   default_ns_uri  s    
zProvBundle.default_ns_uric             C   s   | j S )zb
        Returns the parent document, if any.

        :return: :py:class:`ProvDocument`.
        )r  )r5   r   r   r   r    s    zProvBundle.documentc             C   s   | j S )z1
        Returns the bundle's identifier
        )rM   )r5   r   r   r   rR     s    zProvBundle.identifierc             C   s
   t | jS )zG
        Returns the list of all records in the current bundle
        )r  r  )r5   r   r   r   r    s    zProvBundle.recordsc             C   s   | j j| dS )ze
        Sets the default namespace through a given URI.

        :param uri: Namespace URI.
        N)r   r   )r5   r   r   r   r   r   '  s    z ProvBundle.set_default_namespacec             C   s
   | j j S )zi
        Returns the default namespace.

        :return: :py:class:`~prov.identifier.Namespace`
        )r   r  )r5   r   r   r   r  /  s    z ProvBundle.get_default_namespacec             C   s*   |dkr| j j|S | j jt||S dS )a9  
        Adds a namespace (if not available, yet).

        :param namespace_or_prefix: :py:class:`~prov.identifier.Namespace` or its
            prefix as a string to add.
        :param uri: Namespace URI (default: None). Must be present if only a
            prefix is given in the previous parameter.
        N)r   r  r
   )r5   Znamespace_or_prefixr   r   r   r   r  7  s    	zProvBundle.add_namespacec             C   s
   | j j S )zz
        Returns all registered namespaces.

        :return: Iterable of :py:class:`~prov.identifier.Namespace`.
        )r   r  )r5   r   r   r   r  E  s    z$ProvBundle.get_registered_namespacesc             C   s   | j j|S )N)r   r]   )r5   rR   r   r   r   r]   M  s    zProvBundle.valid_qualified_namec                s(   t | j} r t fdd|S |S dS )a  
        Returns all records. Returned records may be filtered by the optional
        argument.

        :param class_or_type_or_tuple: A filter on the type for which records are
            to be returned (default: None). The filter checks by the type of the
            record using the `isinstance` check on the record.
        :return: List of :py:class:`ProvRecord` objects.
        c                s
   t |  S )N)r   )Zrec)class_or_type_or_tupler   r   <lambda>\  s    z(ProvBundle.get_records.<locals>.<lambda>N)r  r  filter)r5   r  resultsr   )r  r   get_recordsP  s    

zProvBundle.get_recordsc             C   sR   |dkrdS | j |}y
| j| S  tk
rL   | j rD| jj|S dS Y nX dS )z
        Returns a specific record matching a given identifier.

        :param identifier: Record identifier.
        :return: :py:class:`ProvRecord`
        N)r]   r  KeyError	is_bundler  
get_record)r5   rR   valid_idr   r   r   r#  `  s    	

zProvBundle.get_recordc             C   s   dS )z_
        `True` if the object is a document, `False` otherwise.

        :return: bool
        Fr   )r5   r   r   r   is_documentv  s    zProvBundle.is_documentc             C   s   dS )z]
        `True` if the object is a bundle, `False` otherwise.

        :return: bool
        Tr   )r5   r   r   r   r"  ~  s    zProvBundle.is_bundlec             C   s   dS )zi
        `True` if the object has at least one bundle, `False` otherwise.

        :return: bool
        Fr   )r5   r   r   r   has_bundles  s    zProvBundle.has_bundlesc             C   s   t  S )zq
        Returns bundles contained in the document

        :return: Iterable of :py:class:`ProvBundle`.
        )rU   )r5   r   r   r   bundles  s    zProvBundle.bundlesr   c                s   dd   }dd d   }| j  r*dgn
d| j g}| jj }|rT|jd|j  | jj }|rv|jdd	 |D  |s~|r|jd |jd
d	 | jD  | j  r|j fdd| j	D  |j
|d }||| j  rdnd 7 }|S )z[
        Returns the PROV-N representation of the bundle.

        :return: String
        rv   z  r#   r  r  z	bundle %szdefault <%s>c             S   s   g | ]}d |j |jf qS )zprefix %s <%s>)r  r   )r`   r   r   r   r   rb     s   z(ProvBundle.get_provn.<locals>.<listcomp>c             S   s   g | ]}|j  qS r   )ru   )r`   r  r   r   r   rb     s    c             3   s   | ]}|j  d  V  qdS )r  N)ru   )r`   rQ   )_indent_levelr   r   rd     s    z'ProvBundle.get_provn.<locals>.<genexpr>endDocumentZ	endBundle)r%  rM   r   r  ry   r   r  extendr  r'  r{   )r5   r(  indentationnewlinelinesdefault_namespaceZregistered_namespacesZ	provn_strr   )r(  r   ru     s(    



zProvBundle.get_provnc             C   s   t |tsdS t|j }t| j }t|t|kr:dS xN|D ]F}d}x$|D ]}||krN|j| d}P qNW |s@tjdt| dS q@W dS )NFTz5Equality (ProvBundle): Could not find this record: %s)	r   r  rN   r   lenremover/   r0   r   )r5   r;   Zother_recordsZthis_recordsZrecord_afoundZrecord_br   r   r   r<     s&    




zProvBundle.__eq__c             C   s
   | |k S )Nr   )r5   r;   r   r   r   r=     s    zProvBundle.__ne__c             C   s   t  }xf| jj D ]X\}}t|dkr|d j }x |dd D ]}|j|j q@W x|D ]}|||< qZW qW |s|t| jS t	 }t }xF| jD ]<}||kr|| }||kr|j
| |j| q|j
| qW |S )z"Returns a list of unified records.r  r   N)rp   r  rc   r/  rW   rP   rS   r  r  rN   ry   r[   )r5   Zmerged_recordsrR   r  Zmergedr  Zadded_merged_recordsunified_recordsr   r   r   _unified_records  s(    


zProvBundle._unified_recordsc             C   s   | j  }t|| jd}|S )z
        Unifies all records in the bundle that haves same identifiers

        :returns: :py:class:`ProvBundle` -- the new unified bundle.
        )r  rR   )r3  r  rR   )r5   r2  rQ   r   r   r   unified   s    zProvBundle.unifiedc             C   sT   t |tr@|j r"|j r"tdx,|j D ]}| j| q,W ntdt| dS )z
        Append all the records of the *other* ProvBundle into this bundle.

        :param other: the other bundle whose records to be appended.
        :type other: :py:class:`ProvBundle`
        :returns: None.
        zGProvBundle.update(): The other bundle is a document with sub-bundle(s).zGProvBundle.update(): The other bundle is not a ProvBundle instance (%s)N)r   r  r%  r&  rE   r   r  type)r5   r;   r  r   r   r   r   
  s    
zProvBundle.updatec             C   s.   |j }|d k	r| j| j| | jj| d S )N)rR   r  ry   r  )r5   r  rR   r   r   r   _add_record"  s    zProvBundle._add_recordc             C   sz   g }|r6t |tr,|jdd |j D  n
|j| |rV|jt |trP|j n| t| | | j||}| j| |S )a  
        Creates a new record.

        :param record_type: Type of record (one of :py:const:`PROV_REC_CLS`).
        :param identifier: Identifier for new record.
        :param attributes: Attributes as a dictionary or list of tuples to be added
            to the record optionally (default: None).
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        c             s   s   | ]\}}||fV  qd S )Nr   )r`   rt   r   r   r   r   rd   :  s    z(ProvBundle.new_record.<locals>.<genexpr>)r   rp   r*  rc   rV   r]   r6  )r5   Zrecord_typerR   rS   r   Z	attr_list
new_recordr   r   r   r7  *  s    


zProvBundle.new_recordc             C   s   | j |j |j|j|jS )zs
        Adds a new record that to the bundle.

        :param record: :py:class:`ProvRecord` to be added.
        )r7  rT   rR   rh   rj   )r5   r  r   r   r   r  J  s
    zProvBundle.add_recordc             C   s   | j t|d|S )z
        Creates a new entity.

        :param identifier: Identifier for new entity.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        N)r7  r   )r5   rR   r   r   r   r   r   W  s    zProvBundle.entityc             C   s    | j t|tt|tt|i|S )a  
        Creates a new activity.

        :param identifier: Identifier for new activity.
        :param startTime: Optional start time for the activity (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param endTime: Optional start time for the activity (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   )r5   rR   r   r   r   r   r   r   r   a  s    
zProvBundle.activityc          
   C   s    | j t|t|t|tt|i|S )a  
        Creates a new generation record for an entity.

        :param entity: Entity or a string identifier for the entity.
        :param activity: Activity or string identifier of the activity involved in
            the generation (default: None).
        :param time: Optional time for the generation (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param identifier: Identifier for new generation record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   r   )r5   r   r   r   rR   r   r   r   r   r   y  s    
zProvBundle.generationc          
   C   s    | j t|t|t|tt|i|S )a  
        Creates a new usage record for an activity.

        :param activity: Activity or a string identifier for the entity.
        :param entity: Entity or string identifier of the entity involved in
            the usage relationship (default: None).
        :param time: Optional time for the usage (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param identifier: Identifier for new usage record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   r   )r5   r   r   r   rR   r   r   r   r   r     s    
zProvBundle.usagec             C   s$   | j t|t|t|t|tt|i|S )a   
        Creates a new start record for an activity.

        :param activity: Activity or a string identifier for the entity.
        :param trigger: Entity triggering the start of this activity.
        :param starter: Optionally extra activity to state a qualified start
            through which the trigger entity for the start is generated
            (default: None).
        :param time: Optional time for the start (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param identifier: Identifier for new start record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   r   r   )r5   r   r   r   r   rR   r   r   r   r   r     s    
zProvBundle.startc             C   s$   | j t|t|t|t|tt|i|S )a  
        Creates a new end record for an activity.

        :param activity: Activity or a string identifier for the entity.
        :param trigger: trigger: Entity triggering the end of this activity.
        :param ender: Optionally extra activity to state a qualified end
            through which the trigger entity for the end is generated
            (default: None).
        :param time: Optional time for the end (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param identifier: Identifier for new end record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   r   r   )r5   r   r   r   r   rR   r   r   r   r   r     s    
zProvBundle.endc          
   C   s    | j t|t|t|tt|i|S )a  
        Creates a new invalidation record for an entity.

        :param entity: Entity or a string identifier for the entity.
        :param activity: Activity or string identifier of the activity involved in
            the invalidation (default: None).
        :param time: Optional time for the invalidation (default: None).
            Either a :py:class:`datetime.datetime` object or a string that can be
            parsed by :py:func:`dateutil.parser`.
        :param identifier: Identifier for new invalidation record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   r   )r5   r   r   r   rR   r   r   r   r   r     s    
zProvBundle.invalidationc             C   s   | j t|t|t|i|S )a  
        Creates a new communication record for an entity.

        :param informed: The informed activity (relationship destination).
        :param informant: The informing activity (relationship source).
        :param identifier: Identifier for new communication record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   )r5   Zinformedr   rR   r   r   r   r   r     s
    
zProvBundle.communicationc             C   s   | j t|d|S )z
        Creates a new agent.

        :param identifier: Identifier for new agent.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        N)r7  r   )r5   rR   r   r   r   r   r   %  s    zProvBundle.agentc             C   s   | j t|t|t|i|S )a  
        Creates a new attribution record between an entity and an agent.

        :param entity: Entity or a string identifier for the entity (relationship
            source).
        :param agent: Agent or string identifier of the agent involved in the
            attribution (relationship destination).
        :param identifier: Identifier for new attribution record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   )r5   r   r   rR   r   r   r   r   r   /  s
    
zProvBundle.attributionc          	   C   s   | j t|t|t|t|i|S )ai  
        Creates a new association record for an activity.

        :param activity: Activity or a string identifier for the activity.
        :param agent: Agent or string identifier of the agent involved in the
            association (default: None).
        :param plan: Optionally extra entity to state qualified association through
            an internal plan (default: None).
        :param identifier: Identifier for new association record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   )r5   r   r   r   rR   r   r   r   r   r   B  s    zProvBundle.associationc          	   C   s   | j t|t|t|t|i|S )ad  
        Creates a new delegation record on behalf of an agent.

        :param delegate: Agent delegating the responsibility (relationship source).
        :param responsible: Agent the responsibility is delegated to (relationship
            destination).
        :param activity: Optionally extra activity to state qualified delegation
            internally (default: None).
        :param identifier: Identifier for new association record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   r   )r5   Zdelegater   r   rR   r   r   r   r   r   \  s    zProvBundle.delegationc             C   s   | j t|t|t|i|S )a  
        Creates a new influence record between two entities, activities or agents.

        :param influencee: Influenced entity, activity or agent (relationship
            source).
        :param influencer: Influencing entity, activity or agent (relationship
            destination).
        :param identifier: Identifier for new influence record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r7  r   r   r   )r5   Z
influenceeZ
influencerrR   r   r   r   r   	influence{  s
    
zProvBundle.influencec       	   
   C   s(   t |t|t|t|t|i}| jt|||S )a[  
        Creates a new derivation record for a generated entity from a used entity.

        :param generatedEntity: Entity or a string identifier for the generated
            entity (relationship source).
        :param usedEntity: Entity or a string identifier for the used entity
            (relationship destination).
        :param activity: Activity or string identifier of the activity involved in
            the derivation (default: None).
        :param generation: Optionally extra activity to state qualified generation
            through a generation (default: None).
        :param usage: XXX (default: None).
        :param identifier: Identifier for new derivation record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        )r   r   r   r   r   r7  r   )	r5   generatedEntityr   r   r   r   rR   r   rS   r   r   r   r     s    zProvBundle.derivationc       	      C   s(   | j |||||||}|jtd  |S )aM  
        Creates a new revision record for a generated entity from a used entity.

        :param generatedEntity: Entity or a string identifier for the generated
            entity (relationship source).
        :param usedEntity: Entity or a string identifier for the used entity
            (relationship destination).
        :param activity: Activity or string identifier of the activity involved in
            the revision (default: None).
        :param generation: Optionally to state qualified revision through a
            generation activity (default: None).
        :param usage: XXX (default: None).
        :param identifier: Identifier for new revision record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        ZRevision)r   r\   r1   )	r5   r9  r   r   r   r   rR   r   r  r   r   r   revision  s    zProvBundle.revisionc       	      C   s(   | j |||||||}|jtd  |S )aQ  
        Creates a new quotation record for a generated entity from a used entity.

        :param generatedEntity: Entity or a string identifier for the generated
            entity (relationship source).
        :param usedEntity: Entity or a string identifier for the used entity
            (relationship destination).
        :param activity: Activity or string identifier of the activity involved in
            the quotation (default: None).
        :param generation: Optionally to state qualified quotation through a
            generation activity (default: None).
        :param usage: XXX (default: None).
        :param identifier: Identifier for new quotation record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        Z	Quotation)r   r\   r1   )	r5   r9  r   r   r   r   rR   r   r  r   r   r   	quotation  s    zProvBundle.quotationc       	      C   s(   | j |||||||}|jtd  |S )am  
        Creates a new primary source record for a generated entity from a used
        entity.

        :param generatedEntity: Entity or a string identifier for the generated
            entity (relationship source).
        :param usedEntity: Entity or a string identifier for the used entity
            (relationship destination).
        :param activity: Activity or string identifier of the activity involved in
            the primary source (default: None).
        :param generation: Optionally to state qualified primary source through a
            generation activity (default: None).
        :param usage: XXX (default: None).
        :param identifier: Identifier for new primary source record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        ZPrimarySource)r   r\   r1   )	r5   r9  r   r   r   r   rR   r   r  r   r   r   primary_source  s    zProvBundle.primary_sourcec             C   s   | j tdt|t|iS )aO  
        Creates a new specialisation record for a specific from a general entity.

        :param specificEntity: Entity or a string identifier for the specific
            entity (relationship source).
        :param generalEntity: Entity or a string identifier for the general entity
            (relationship destination).
        N)r7  r   r   r   )r5   specificEntityr   r   r   r   r   &  s
    	zProvBundle.specializationc             C   s   | j tdt|t|iS )a/  
        Creates a new alternate record between two entities.

        :param alternate1: Entity or a string identifier for the first entity
            (relationship source).
        :param alternate2: Entity or a string identifier for the second entity
            (relationship destination).
        N)r7  r   r   r   )r5   Z
alternate1r   r   r   r   r   8  s    	zProvBundle.alternatec          	   C   s   | j tdt|t|t|iS )ac  
        Creates a new mention record for a specific from a general entity.

        :param specificEntity: Entity or a string identifier for the specific
            entity (relationship source).
        :param generalEntity: Entity or a string identifier for the general entity
            (relationship destination).
        :param bundle: XXX
        N)r7  r   r   r   r   )r5   r=  r   rQ   r   r   r   mentionG  s    
zProvBundle.mentionc             C   s"   | j t|d|}|jtd  |S )a+  
        Creates a new collection record for a particular record.

        :param identifier: Identifier for new collection record.
        :param other_attributes: Optional other attributes as a dictionary or list
            of tuples to be added to the record optionally (default: None).
        N
Collection)r7  r   r\   r1   )r5   rR   r   r  r   r   r   
collection[  s    zProvBundle.collectionc             C   s   | j tdt|t|iS )z
        Creates a new membership record for an entity to a collection.

        :param collection: Collection the entity is to be added to.
        :param entity: Entity to be added to the collection.
        N)r7  r   rq   r   )r5   r@  r   r   r   r   r   g  s    zProvBundle.membershipTFc             C   s  ddl m} |r0tjj|d j jtjj}nd}|j }|j| ||||d}d| }	t	||	snt
d| tj &}
|
jt||	  |
jdd |rt|d}|j|
j  W d	Q R X ndd	lj}dd	lj}d
}|j|
}|ddddf }|jd d |jd d f}t||kr0|t| }nd}||d  ||d  f}|j|d |jddddd |jg  |jg  |j| |jd |j  W d	Q R X d	S )a  
        Convenience function to plot a PROV document.

        :param filename: The filename to save to. If not given, it will open
            an interactive matplotlib plot. The filetype is determined from
            the filename ending.
        :type filename: String
        :param show_nary: Shows all elements in n-ary relations.
        :type show_nary: bool
        :param use_labels: Uses the `prov:label` property of an element as its
            name (instead of its identifier).
        :type use_labels: bool
        :param show_element_attributes: Shows attributes of elements.
        :type show_element_attributes: bool
        :param show_relation_attributes: Shows attributes of relations.
        :type show_relation_attributes: bool
        r   )dotr  Zpng)	show_nary
use_labelsshow_element_attributesshow_relation_attributesz	create_%szFormat '%s' cannot be saved.wbN   g      Y@g      ?)Zfigsize)ZbottomtopleftrightoffrL  rL  ) r   rA  ospathsplitextr   stripextsepZprov_to_dothasattrr   ioBytesIOwritegetattrseekopenreadZmatplotlib.pylabZpylabZmatplotlib.imageimageZimreadshapemaxfigureZsubplots_adjustZxticksZyticksZimshowZaxisshow)r5   filenamerB  rC  rD  rE  rA  r(   dmethodbuffhZpltZmpimgmax_sizeimgsizeZscaler   r   r   plott  sJ     







zProvBundle.plot)NNNN)N)N)r   )NN)N)NNN)NNNN)NNNN)NNNNN)NNNNN)NNNN)NN)N)NN)NNNN)NNN)NN)NNNNN)NNNNN)NNNNN)NNNNN)N)NTFTT)JrA   rB   rC   rF   r7   r:   rD   r   r  r  rR   r  r   r  r  r  r]   r   r#  r%  r"  r&  r'  ru   r<   r=   r?   r3  r4  r   r6  r7  r  r   r   r   r   r   r   r   r   r   r   r   r   r8  r   r:  r;  r<  r   r   r>  r@  r   rg  r   r   r   r   r   r   r   r   r   ZwasInfluencedByr   ZwasRevisionOfZwasQuotedFromZhadPrimarySourcer   r   Z	mentionOfr   r   r   r   r   r    s   
	
	

	
+ 
	





    
     






  

    
!    
"    
"    

    
Hr  c                   s   e Zd ZdZd ddZdd Z fddZd	d
 Zdd Zdd Z	e
dd Zdd Zdd Zdd Zd!ddZdd Zd"ddZed#ddZ  ZS )$ProvDocumentzProvenance Document.Nc             C   s   t j| |d|d t | _dS )a  
        Constructor.

        :param records: Optional records to add to the document (default: None).
        :param namespaces: Optional iterable of :py:class:`~prov.identifier.Namespace`s
            to set the document up with (default: None).
        N)r  rR   r   )r  r7   rp   _bundles)r5   r  r   r   r   r   r7     s    zProvDocument.__init__c             C   s   dS )Nz<ProvDocument>r   )r5   r   r   r   r:     s    zProvDocument.__repr__c                sb   t |tsdS tt| j|s"dS x:| jj D ],\}}||jkrDdS |j| }||kr.dS q.W dS )NFT)r   rh  r   r<   ri  rc   )r5   r;   Zb_idrQ   Zother_bundle)r   r   r   r<     s    


zProvDocument.__eq__c             C   s   dS )z_
        `True` if the object is a document, `False` otherwise.

        :return: bool
        Tr   )r5   r   r   r   r%    s    zProvDocument.is_documentc             C   s   dS )z]
        `True` if the object is a bundle, `False` otherwise.

        :return: bool
        Fr   )r5   r   r   r   r"  	  s    zProvDocument.is_bundlec             C   s   t | jdkS )zi
        `True` if the object has at least one bundle, `False` otherwise.

        :return: bool
        r   )r/  ri  )r5   r   r   r   r&  	  s    zProvDocument.has_bundlesc             C   s
   | j j S )zq
        Returns bundles contained in the document

        :return: Iterable of :py:class:`ProvBundle`.
        )ri  ra   )r5   r   r   r   r'  	  s    zProvDocument.bundlesc             C   sT   | j rLt }tjdd | j j D  }x tj| j|D ]}|j| q6W |S | S dS )z
        Flattens the document by moving all the records in its bundles up
        to the document level.

        :returns: :py:class:`ProvDocument` -- the (new) flattened document.
        c             S   s   g | ]}|j  qS r   )r   )r`   br   r   r   rb   (	  s    z*ProvDocument.flattened.<locals>.<listcomp>N)ri  rh  	itertoolschainra   r  r  )r5   Znew_docZbundled_recordsr  r   r   r   	flattened	  s    zProvDocument.flattenedc             C   s:   t | j }| j|_x | jD ]}|j }|j| qW |S )z
        Returns a new document containing all records having same identifiers
        unified (including those inside bundles).

        :return: :py:class:`ProvDocument`
        )rh  r3  r   r'  r4  
add_bundle)r5   r  rQ   Zunified_bundler   r   r   r4  1	  s    zProvDocument.unifiedc             C   s   t |trvx|j D ]}| j| qW |j rxV|jD ]:}|j| jkrZ| j|j j| q6| j	|j}|j| q6W nt
dt| dS )aB  
        Append all the records of the *other* document/bundle into this document.
        Bundles having same identifiers will be merged.

        :param other: The other document/bundle whose records to be appended.
        :type other: :py:class:`ProvDocument` or :py:class:`ProvBundle`
        :returns: None.
        zRProvDocument.update(): The other is not a ProvDocument or ProvBundle instance (%s)N)r   r  r   r  r&  r'  rR   ri  r   rQ   rE   r5  )r5   r;   r  rQ   
new_bundler   r   r   r   ?	  s    	
zProvDocument.updatec             C   s   t |tstd|j rD|j r*tdt|jd}|j| |}|dkrR|j}|s^td| j|j_	|j
|}||_|| jkrtd|| j|< | |_dS )aM  
        Add a bundle to the current document.

        :param bundle: The bundle to add to the document.
        :type bundle: :py:class:`ProvBundle`
        :param identifier: The (optional) identifier to use for the bundle
            (default: None). If none given, use the identifier from the bundle
            itself.
        zFOnly a ProvBundle instance can be added as a bundle in a ProvDocument.z6Cannot add a document with nested bundles as a bundle.)r   Nz%The provided bundle has no identifierz,A bundle with that identifier already exists)r   r  rE   r%  r&  r   r   rR   r   r   r]   rM   ri  r  )r5   rQ   rR   ro  r$  r   r   r   rn  Y	  s*    






zProvDocument.add_bundlec             C   sZ   |dkrt d| j|}|dkr.t d| || jkr@t dt|| d}|| j|< |S )z
        Returns a new bundle from the current document.

        :param identifier: The identifier to use for the bundle.
        :return: :py:class:`ProvBundle`
        Nz;An identifier is required. Cannot create an unnamed bundle.z)The provided identifier "%s" is not validz,A bundle with that identifier already exists)rR   r  )rE   r]   ri  r  )r5   rR   r$  rj  r   r   r   rQ   	  s    



zProvDocument.bundlejsonc             K   s   t j|| }|dkr4tj }|j|f| |j S t|drR|}|j|f| n|}t|\}}}	}
}}|dkr~td dS t	j
 \}}tj|d}|j|f| |j  ttdrtj||	 ntj||	 tj| dS )	ai  
        Serialize the :py:class:`ProvDocument` to the destination.

        Available serializers can be queried by the value of
        `:py:attr:~prov.serializers.Registry.serializers` after loading them via
        `:py:func:~prov.serializers.Registry.load_serializers()`.

        :param destination: Stream object to serialize the output to. Default is
            `None`, which serializes as a string.
        :param format: Serialization format (default: 'json'), defaulting to
            PROV-JSON.
        :return: Serialization in a string if no destination was given,
            None otherwise.
        NrU  rv   z WARNING: not saving as location zis not a local file referencerF  movez=WARNING: not saving as location is not a local file reference)r   getrS  StringIO	serializegetvaluerR  r   printtempfilemkstemprM  fdopencloseshutilrq  rW   r0  )r5   Zdestinationr(   rg   
serializerstreamlocationschemenetlocrN  paramsZ_queryfragmentfdnamer   r   r   rt  	  s,    

zProvDocument.serializec          
   K   s   t j| }|dk	r>tjt|tr&|n|j }|j|f|S | dk	r|t| dr^|j| f|S t	| }|j|f|S Q R X dS )a  
        Deserialize the :py:class:`ProvDocument` from source (a stream or a
        file path) or directly from a string content.

        Available serializers can be queried by the value of
        `:py:attr:~prov.serializers.Registry.serializers` after loading them via
        `:py:func:~prov.serializers.Registry.load_serializers()`.

        Note: Not all serializers support deserialization.

        :param source: Stream object to deserialize the PROV document from
            (default: None).
        :param content: String to deserialize the PROV document from
            (default: None).
        :param format: Serialization format (default: 'json'), defaulting to
            PROV-JSON.
        :return: :py:class:`ProvDocument`
        NrY  )
r   rr  rS  rs  r   r   decodedeserializerR  rX  )sourcecontentr(   rg   r|  r}  fr   r   r   r  	  s    

zProvDocument.deserialize)NN)N)Nrp  )NNrp  )rA   rB   rC   rF   r7   r:   r<   r%  r"  r&  rD   r'  rm  r4  r   rn  rQ   rt  staticmethodr  r   r   r   )r   r   rh    s    


-
)rh  c             C   s   t |}t t|  j}|jtttttg dd }g }xZ|D ]R}g }x2t |D ]&}|d |kr`qN|j	| |j
| qNW |j|d |j| q<W |j|d |j| |S )z
    Helper function sorting attributes into the order required by PROV-XML.

    :param element: The prov element used to derive the type and the
        attribute order for the type.
    :param attributes: The attributes to sort.
    c             S   s0   t | d t t| d dr$| d jn| d fS )Nr   r  r   )r   rR  r   )xr   r   r   sort_fct	  s    z#sorted_attributes.<locals>.sort_fctr   )key)r  rV   rf   r*  rk   ZPROV_LOCATIONZ	PROV_ROLErY   rm   ry   r0  sort)elementrS   orderr  Zsorted_elementsitemZthis_type_lister   r   r   sorted_attributes	  s"    


r  )hrF   collectionsr   rW   r   r'   rS  rk  loggingrM  r{  rw  urllib.parser   Zdateutil.parserr   r   r   r   Zprov.constantsZprov.identifierr   r	   r
   
__author__	__email__	getLoggerrA   r/   r   r   r   ZDATATYPE_PARSERSZ
XSD_STRINGr   Z
XSD_DOUBLEr*   ZXSD_LONGintZXSD_INTZXSD_BOOLEANZXSD_DATETIMEZ
XSD_ANYURIr   r   r!   r&   r,   objectr-   rE   WarningrG   rH   rJ   rK   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rV   r1   ZXSDZXSIr   rp   r   r  rh  r  r   r   r   r   <module>   s   


L
  Hbw		
 n       ~  