U
    Z+dw                     @   sL   d Z ddlmZ dZG dd dZdddZG d	d
 d
ZG dd dZdS )z7Object related utilities, including introspection, etc.    )reduce)BunchFallbackContextgetitem_property
mro_lookupc                   @   s   e Zd ZdZdd ZdS )r   z-Object that enables you to modify attributes.c                 K   s   | j | d S N)__dict__update)selfkwargs r   8/tmp/pip-unpacked-wheel-ucduq0nd/celery/utils/objects.py__init__
   s    zBunch.__init__N)__name__
__module____qualname____doc__r   r   r   r   r   r      s   r   Nc              
   C   s   |s
t  n|}|sg n|}|  D ]b}||krrz|j| }|j}W n ttfk
rZ   Y nX ||krl|  S  dS ||jkr"|  S q"dS )a  Return the first node by MRO order that defines an attribute.

    Arguments:
        cls (Any): Child class to traverse.
        attr (str): Name of attribute to find.
        stop (Set[Any]): A set of types that if reached will stop
            the search.
        monkey_patched (Sequence): Use one of the stop classes
            if the attributes module origin isn't in this list.
            Used to detect monkey patched attributes.

    Returns:
        Any: The attribute value, or :const:`None` if not found.
    N)setmror   r   AttributeErrorKeyError)clsattrstopZmonkey_patchednodevalueZmodule_originr   r   r   r      s    


r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r   a  Context workaround.

    The built-in ``@contextmanager`` utility does not work well
    when wrapping other contexts, as the traceback is wrong when
    the wrapped context raises.

    This solves this problem and can be used instead of ``@contextmanager``
    in this example::

        @contextmanager
        def connection_or_default_connection(connection=None):
            if connection:
                # user already has a connection, shouldn't close
                # after use
                yield connection
            else:
                # must've new connection, and also close the connection
                # after the block returns
                with create_new_connection() as connection:
                    yield connection

    This wrapper can be used instead for the above like this::

        def connection_or_default_connection(connection=None):
            return FallbackContext(connection, create_new_connection)
    c                 O   s"   || _ || _|| _|| _d | _d S r   )providedfallbackfb_args	fb_kwargs_context)r
   r   r   r   r   r   r   r   r   J   s
    zFallbackContext.__init__c                 C   s.   | j d k	r| j S | j| j| j  }| _|S r   )r   r   r   r   	__enter__r    )r
   contextr   r   r   r!   Q   s    
 zFallbackContext.__enter__c                 G   s   | j d k	r| j j| S d S r   )r    __exit__)r
   exc_infor   r   r   r#   Y   s    
zFallbackContext.__exit__N)r   r   r   r   r   r!   r#   r   r   r   r   r   .   s   r   c                   @   s4   e Zd ZdZdddZdd ZdddZd	d
 ZdS )r   a  Attribute -> dict key descriptor.

    The target object must support ``__getitem__``,
    and optionally ``__setitem__``.

    Example:
        >>> from collections import defaultdict

        >>> class Me(dict):
        ...     deep = defaultdict(dict)
        ...
        ...     foo = _getitem_property('foo')
        ...     deep_thing = _getitem_property('deep.thing')


        >>> me = Me()
        >>> me.foo
        None

        >>> me.foo = 10
        >>> me.foo
        10
        >>> me['foo']
        10

        >>> me.deep_thing = 42
        >>> me.deep_thing
        42
        >>> me.deep
        defaultdict(<type 'dict'>, {'thing': 42})
    Nc                 C   s0   | d\}}| _|r |dnd | _|| _d S )N.)
rpartitionkeysplitpathr   )r
   Zkeypathdocr)   _r   r   r   r      s    zgetitem_property.__init__c                 C   s    | j rtdd |g| j  S |S )Nc                 S   s   | | S r   r   )dkr   r   r   <lambda>       z(getitem_property._path.<locals>.<lambda>)r)   r   )r
   objr   r   r   _path   s    zgetitem_property._pathc                 C   s   |d kr|S |  || jS r   )r1   getr'   )r
   r0   typer   r   r   __get__   s    zgetitem_property.__get__c                 C   s   ||  || j< d S r   )r1   r'   )r
   r0   r   r   r   r   __set__   s    zgetitem_property.__set__)N)N)r   r   r   r   r   r1   r4   r5   r   r   r   r   r   ^   s
    

r   )NN)r   	functoolsr   __all__r   r   r   r   r   r   r   r   <module>   s   
 0