3
do<                 @   s   d Z ddlmZmZ ddlZddlZddlZddlmZ ddl	m
Z
 ddlmZmZmZ dd ZG d	d
 d
e
Zdd Ze add Zdd Zdd ZefddZdd Zdd Zdd Zdd Zdd ZdS )z% Manages all registered adaptations.     )heappopheappushN)AdaptationError)	HasTraits)DictListStrc             C   s   | S )zv An adapter factory used to register that a protocol provides another.

    See 'register_provides' for details.

     )adapteer	   r	   F/tmp/pip-build-7vycvbft/traits/traits/adaptation/adaptation_manager.pyno_adapter_necessary   s    r   c               @   sn   e Zd ZdZedd Zedd ZefddZdd	 Z	d
d Z
dd Zdd ZeeeZdd Zdd ZdS )AdaptationManagerz% Manages all registered adaptations. c             C   sP   t j| |sdS tj| dd }d}x$|D ]}t j||rF|d7 }q,P q,W |S )a   Return the distance in the MRO from 'from_type' to 'to_protocol'.

        If `from_type` provides `to_protocol`, returns the distance between
        `from_type` and the super-most class in the MRO hierarchy providing
        `to_protocol` (that's where the protocol was provided in the first
        place).

        If `from_type` does not provide `to_protocol`, return None.

        N   r   )r   provides_protocolinspectgetmro)Z	from_typeto_protocolZ
supertypesZdistancetr	   r	   r   mro_distance_to_protocol'   s    

z*AdaptationManager.mro_distance_to_protocolc             C   s
   t | |S )ah   Does the given type provide (i.e implement) a given protocol?

        Parameters
        ----------
        type_
            Python 'type'.
        protocol
            Either a regular Python class or a traits Interface.

        Returns
        -------
        result : bool
            True if the object provides the protocol, otherwise False.

        )
issubclass)type_protocolr	   r	   r   r   J   s    z#AdaptationManager.provides_protocolc             C   sL   | j t||r|}n| j||}|dkrH|tkrDtd||f n|}|S )a   Attempt to adapt an object to a given protocol.

        If *adaptee* already provides (i.e. implements) the given protocol
        then it is simply returned unchanged.

        Otherwise, we try to build a chain of adapters that adapt *adaptee* to
        *to_protocol*. If no such adaptation is possible then either an
        AdaptationError is raised, or *default* is returned.

        Parameters
        ----------
        adaptee : object
            The object that we want to adapt.
        to_protocol : type or interface
            The protocol that the want to adapt *adaptee* to.
        default : object, optional
            Object to return if no adaptation is possible. If no default is
            provided, and adaptation fails, an ``AdaptationError`` is raised.

        Returns
        -------
        adapted_object : to_protocol
            The original adaptee adapted to the target protocol.

        Raises
        ------
        AdaptationError
            If adaptation is not possible, and no default is given.
        NzCould not adapt %r to %r)r   type_adaptr   )selfr
   r   defaultresultr	   r	   r   adapt_   s    !zAdaptationManager.adaptc             C   s   | j j|jg }|j| dS )z: Register an offer to adapt from one protocol to another. N)_adaptation_offers
setdefaultfrom_protocol_nameappend)r   offeroffersr	   r	   r   register_offer   s    
z AdaptationManager.register_offerc             C   s$   ddl m} | j||||d dS )z Register an adapter factory.

        This is a simply a convenience method that creates and registers an
        'AdaptationOffer' from the given arguments.

        r   )AdaptationOffer)factoryfrom_protocolr   N)Z"traits.adaptation.adaptation_offerr%   r$   )r   r&   r'   r   r%   r	   r	   r   register_factory   s    z"AdaptationManager.register_factoryc             C   s   | j t|| dS )z, Register that a protocol provides another. N)r(   r   )r   provider_protocolr   r	   r	   r   register_provides   s    z#AdaptationManager.register_providesc             C   s   | j ||ddk	S )z Does the object support a given protocol?

        An object "supports" a protocol if either it "provides" it directly,
        or it can be adapted to it.

        N)r   )r   objr   r	   r	   r   supports_protocol   s    z#AdaptationManager.supports_protocolc             C   s   t j }ddt|fg t|fg}xt|dkrt|\}}}| j||}|jtj	t
d x|D ]~\}	}
||
g }| j|
j|r|}xX|D ]}
|
j|}|dkrP qW |S qb|\}}}|d ||	 t|f}t||||
jf qbW q$W dS )zy Returns an adapter that adapts an object to the target class.

        Returns None if no such adapter exists.

        r   )keyNr   )	itertoolscountnextr   lenr   _get_applicable_offerssort	functools
cmp_to_key)_by_weight_then_from_protocol_specificityr   r   r&   r   )r   r
   r   counterZoffer_queueZweightpathcurrent_protocoledgesmro_distancer"   new_pathadapterZadapter_weightZ
mro_weight_Z
new_weightr	   r	   r   r      s0    ,
	




zAdaptationManager._adaptc       	      C   sb   g }xX| j j D ]J\}}|d j}| j||}|dk	rx"|D ]}||kr<|j||f q<W qW |S )a   Find all adaptation offers that can be applied to a protocol.

        Return all the applicable offers together with the number of steps
        up the MRO hierarchy that need to be taken from the protocol
        to the offer's from_protocol.
        The returned object is a list of tuples (mro_distance, offer) .

        In terms of our graph algorithm, we're looking for all outgoing edges
        from the current node.
        r   N)r   itemsr'   r   r!   )	r   r9   r8   r:   r    r#   r'   r;   r"   r	   r	   r   r2   3  s    

z(AdaptationManager._get_applicable_offersN)__name__
__module____qualname____doc__staticmethodr   r   r   r   r$   r(   r*   r,   r   r   r   r   r   r2   r	   r	   r	   r   r   "   s   #2
pr   c             C   s`   | \}}|\}}||k rdS ||kr(dS |j |j kr8dS t|j |j rJdS t|j |j r\dS dS )af   Comparison function for graph edges.

    Each edge is of the form (mro distance, adaptation offer).

    Comparison is done by mro distance first, and by offer's from_protocol
    issubclass next.

    If two edges have the same mro distance, and the from_protocols of the
    two edges are not subclasses of one another, they are considered "equal".

    r   r   rE   )r'   r   )Zedge_1Zedge_2Zmro_distance_1Zoffer_1Zmro_distance_2Zoffer_2r	   r	   r   r6   R  s    r6   c             C   s   | a dS )z: Set the global adaptation manager to the given instance. N)adaptation_manager)Znew_adaptation_managerr	   r	   r   set_global_adaptation_manager  s    rG   c               C   s
   t  adS )zL Set the global adaptation manager to a new AdaptationManager instance.
    N)r   rF   r	   r	   r	   r   reset_global_adaptation_manager  s    rH   c               C   s   t S )z3 Set a reference to the global adaptation manager. )rF   r	   r	   r	   r   get_global_adaptation_manager  s    rI   c             C   s   t  }|j| ||S )z1 Attempt to adapt an object to a given protocol. )rI   r   )r
   r   r   managerr	   r	   r   r     s    r   c             C   s   t  }|j| ||S )z Register an adapter factory. )rI   r(   )r&   r'   r   rJ   r	   r	   r   r(     s    r(   c             C   s   t  }|j| S )z: Register an offer to adapt from one protocol to another. )rI   r$   )r"   rJ   r	   r	   r   r$     s    r$   c             C   s   t  }|j| |S )z, Register that a protocol provides another. )rI   r*   )r)   r   rJ   r	   r	   r   r*     s    r*   c             C   s   t  }|j| |S )z+ Does the object support a given protocol? )rI   r,   )r+   r   rJ   r	   r	   r   r,     s    r,   c             C   s   t j| |S )z? Does the given type provide (i.e implement) a given protocol? )r   r   )r   r   r	   r	   r   r     s    r   )rC   heapqr   r   r   r.   r4   Z"traits.adaptation.adaptation_errorr   Ztraits.has_traitsr   Ztraits.trait_typesr   r   r   r   r   r6   rF   rG   rH   rI   r   r(   r$   r*   r,   r   r	   r	   r	   r   <module>   s,   
  2,