U
    Lk7g=                     @   s   d dl Z d dlmZ d dlmZ d dlmZmZ dZdd Z	dd	 Z
G d
d deZG dd deZG dd deZG dd dZG dd deZdS )    N)DBRef)_import_class)DoesNotExistMultipleObjectsReturned)BaseDict
StrictDictBaseListEmbeddedDocumentListLazyReferencec                    s    fdd}|S )z;Decorator that ensures _mark_as_changed method gets called.c                    s    | f||}|    |S N_mark_as_changed)selfargskwargsresultparent_method C/tmp/pip-unpacked-wheel-n1etwkgt/mongoengine/base/datastructures.pywrapper   s    z(mark_as_changed_wrapper.<locals>.wrapperr   r   r   r   r   r   mark_as_changed_wrapper   s    r   c                    s    fdd}|S )zPDecorator that ensures _mark_as_changed method gets called with the key argumentc                    s8   |r|| ks| | |d kr&|  |  | |f||S )Nr   r   )r   keyr   r   r   r   r   r       s    
z,mark_key_as_changed_wrapper.<locals>.wrapperr   r   r   r   r   mark_key_as_changed_wrapper   s    r   c                       s   e Zd ZdZdZdZdZ fddZdddZ fdd	Z	d
d Z
dd ZeejZeejZeejZeejZeejZeejZeejZeejZdddZ  ZS )r   z+A special dict so we can watch any changes.FNc                    s4   t d}t||rt|| _|| _t | d S NBaseDocument)r   
isinstanceweakrefproxy	_instance_namesuper__init__)r   
dict_itemsinstancenamer   	__class__r   r   r#   0   s
    
zBaseDict.__init__c                 C   s*   z|  |W S  tk
r$   | Y S X d S r   )__getitem__KeyErrorr   r   defaultr   r   r   get8   s    zBaseDict.getc                    s   t  |}td}t||r2|jd kr2| j|_nt|trvt|tsvt|d | j d| }t  || | j|_nBt|t	rt|t
st
|d | j d| }t  || | j|_|S )NEmbeddedDocument.)r"   r)   r   r   r    dictr   r!   __setitem__listr   r   r   valuer.   r'   r   r   r)   ?   s    

zBaseDict.__getitem__c                 C   s   d | _ d| _| S NFr%   _dereferencedr   r   r   r   __getstate__O   s    zBaseDict.__getstate__c                 C   s   |} | S r   r   r   stater   r   r   __setstate__T   s    zBaseDict.__setstate__c                 C   s<   t | jdr8|r*| j| j d|  n| j| j d S Nr   r/   )hasattrr    r   r!   r   r   r   r   r   r   a   s    zBaseDict._mark_as_changed)N)N)__name__
__module____qualname____doc__r7   r    r!   r#   r-   r)   r9   r<   r   r0   r1   __delattr____delitem__r   popclearupdatepopitem
setdefaultr   __classcell__r   r   r'   r   r   )   s$   








r   c                       s   e Zd ZdZdZdZdZ fddZ fddZ fdd	Z	d
d Z
dd Z fddZeejZeejZeejZeejZeejZeejZeejZeejZeejZeejZdddZ  ZS )r   z+A special list so we can watch any changes.FNc                    sH   t d}t||r2t|tjr&|| _nt|| _|| _t | d S r   )	r   r   r   
ProxyTypesr    r   r!   r"   r#   )r   Z
list_itemsr%   r&   r   r'   r   r   r#   p   s    
zBaseList.__init__c                    s   t |tr|dk rt| | }t |}t |tr8|S td}t ||r^|jd kr^| j|_nt |trt |t	st	|d | j
 d| }t || | j|_nBt |trt |tst|d | j
 d| }t || | j|_|S )Nr   r.   r/   )r   intlenr"   r)   slicer   r    r0   r   r!   r1   r2   r   r3   r'   r   r   r)   |   s"    


zBaseList.__getitem__c                 #   s   t   E d H  d S r   )r"   __iter__r8   r'   r   r   rP      s    zBaseList.__iter__c                 C   s   d | _ d| _| S r5   r6   r8   r   r   r   r9      s    zBaseList.__getstate__c                 C   s   |} | S r   r   r:   r   r   r   r<      s    zBaseList.__setstate__c                    s.   |}t |trd }t ||}| | |S r   )r   rO   r"   r1   r   )r   r   r4   Zchanged_keyr   r'   r   r   r1      s    

zBaseList.__setitem__c                 C   sH   t | jdrD|d k	r6| j| j d|t|    n| j| j d S r=   )r>   r    r   r!   rN   r?   r   r   r   r      s    "zBaseList._mark_as_changed)N)r@   rA   rB   rC   r7   r    r!   r#   r)   rP   r9   r<   r1   r   r2   appendextendinsertrF   removereversesortrE   __iadd____imul__r   rK   r   r   r'   r   r   i   s*   









r   c                   @   sl   e Z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d Zdd ZdS )r	   c                 C   s:   |  D ],\}}t||}||krt||kr dS qdS )zoReturn True if a given embedded doc matches all the filter
        kwargs. If it doesn't return False.
        FT)itemsgetattrstr)clsZembedded_docr   r   Zexpected_valueZdoc_valr   r   r   Z__match_all   s
    
z EmbeddedDocumentList.__match_allc                    s   s|S  fdd|D S )z2Return embedded docs that match the filter kwargs.c                    s   g | ]}  |r|qS r   ) _EmbeddedDocumentList__match_all).0docr\   r   r   r   
<listcomp>   s      z7EmbeddedDocumentList.__only_matches.<locals>.<listcomp>r   )r\   Zembedded_docsr   r   r`   r   Z__only_matches   s    z#EmbeddedDocumentList.__only_matchesc                 K   s   |  | |}t|| j| jS )a  
        Filters the list by only including embedded documents with the
        given keyword arguments.

        This method only supports simple comparison (e.g. .filter(name='John Doe'))
        and does not support operators like __gte, __lte, __icontains like queryset.filter does

        :param kwargs: The keyword arguments corresponding to the fields to
         filter on. *Multiple arguments are treated as if they are ANDed
         together.*
        :return: A new ``EmbeddedDocumentList`` containing the matching
         embedded documents.

        Raises ``AttributeError`` if a given keyword is not a valid field for
        the embedded document class.
        #_EmbeddedDocumentList__only_matchesr	   r    r!   r   r   valuesr   r   r   filter   s    zEmbeddedDocumentList.filterc                    s.   |  | |  fdd| D }t|| j| jS )a  
        Filters the list by excluding embedded documents with the given
        keyword arguments.

        :param kwargs: The keyword arguments corresponding to the fields to
         exclude on. *Multiple arguments are treated as if they are ANDed
         together.*
        :return: A new ``EmbeddedDocumentList`` containing the non-matching
         embedded documents.

        Raises ``AttributeError`` if a given keyword is not a valid field for
        the embedded document class.
        c                    s   g | ]}| kr|qS r   r   )r^   itemexcluder   r   ra      s      z0EmbeddedDocumentList.exclude.<locals>.<listcomp>rb   rd   r   rh   r   ri      s    zEmbeddedDocumentList.excludec                 C   s   t | S )z
        The number of embedded documents in the list.

        :return: The length of the list, equivalent to the result of ``len()``.
        rN   r8   r   r   r   count   s    zEmbeddedDocumentList.countc                 K   sL   |  | |}t|dkr(td| j nt|dkrDtdt| |d S )a  
        Retrieves an embedded document determined by the given keyword
        arguments.

        :param kwargs: The keyword arguments corresponding to the fields to
         search on. *Multiple arguments are treated as if they are ANDed
         together.*
        :return: The embedded document matched by the given keyword arguments.

        Raises ``DoesNotExist`` if the arguments used to query an embedded
        document returns no results. ``MultipleObjectsReturned`` if more
        than one result is returned.
        r   z!%s matching query does not exist.   z%d items returned, instead of 1)rc   rN   r   r!   r   rd   r   r   r   r-     s    
zEmbeddedDocumentList.getc                 C   s   t | dkr| d S dS )zVReturn the first embedded document in the list, or ``None``
        if empty.
        r   Nrj   r8   r   r   r   first  s    zEmbeddedDocumentList.firstc                 K   s>   | j }| jj| jj}| j| j  |f | | j| j  d S )a  
        Creates a new instance of the EmbeddedDocument and appends it to this EmbeddedDocumentList.

        .. note::
            the instance of the EmbeddedDocument is not automatically saved to the database.
            You still need to call .save() on the parent Document.

        :param values: A dictionary of values for the embedded document.
        :return: The new embedded document instance.
        )r!   r    _fieldsfieldZdocument_type_objrQ   )r   re   r&   ZEmbeddedClassr   r   r   create   s    zEmbeddedDocumentList.createc                 O   s   | j j|| dS )z
        Saves the ancestor document.

        :param args: Arguments passed up to the ancestor Document's save
         method.
        :param kwargs: Keyword arguments passed up to the ancestor Document's
         save method.
        N)r    save)r   r   r   r   r   r   rr   1  s    	zEmbeddedDocumentList.savec                 C   s,   t | }|D ]}| j| j | qt|S )a  
        Deletes the embedded documents from the database.

        .. note::
            The embedded document changes are not automatically saved
            to the database after calling this method.

        :return: The number of entries deleted.
        )r2   r    r!   rT   rN   )r   re   rg   r   r   r   delete<  s    
zEmbeddedDocumentList.deletec                 K   sH   t |dkrdS t| }|D ]"}| D ]\}}t||| q(qt |S )a  
        Updates the embedded documents with the given replacement values. This
        function does not support mongoDB update operators such as ``inc__``.

        .. note::
            The embedded document changes are not automatically saved
            to the database after calling this method.

        :param update: A dictionary of update values to apply to each
         embedded document.
        :return: The number of entries updated.
        r   )rN   r2   rY   setattr)r   rH   re   rg   kvr   r   r   rH   L  s    zEmbeddedDocumentList.updateN)r@   rA   rB   classmethodr]   rc   rf   ri   rk   r-   rm   rq   rr   rs   rH   r   r   r   r   r	      s   


r	   c                   @   s   e Zd ZdZddddddhZi Zdd	 Zd
d Zdd Zdd Z	d'd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$ Zed%d& ZdS ))r   r   r-   rF   	iteritemsrY   keysrq   c                 K   s"   |  D ]\}}t| || qd S r   )rY   rt   )r   r   ru   rv   r   r   r   r#   h  s    zStrictDict.__init__c                 C   sD   || j krd| n|}zt| |W S  tk
r>   t|Y nX d S N
_reserved_)_special_fieldsrZ   AttributeErrorr*   r?   r   r   r   r)   l  s
    zStrictDict.__getitem__c                 C   s"   || j krd| n|}t| ||S rz   )r|   rt   )r   r   r4   r   r   r   r1   s  s    zStrictDict.__setitem__c                 C   s
   t | |S r   r>   r?   r   r   r   __contains__w  s    zStrictDict.__contains__Nc                 C   s(   z
| | W S  t k
r"   | Y S X d S r   )r*   r+   r   r   r   r-   z  s    
zStrictDict.getc                 C   s4   |  ||}zt| | W n tk
r.   Y nX |S r   )r-   delattrr}   )r   r   r,   rv   r   r   r   rF     s    zStrictDict.popc                 c   s   | D ]}|| | fV  qd S r   r   r?   r   r   r   rx     s    zStrictDict.iteritemsc                    s    fddt  D S )Nc                    s   g | ]}| | fqS r   r   r^   ru   r8   r   r   ra     s     z$StrictDict.items.<locals>.<listcomp>iterr8   r   r8   r   rY     s    zStrictDict.itemsc                 C   s   t | S r   r   r8   r   r   r   iterkeys  s    zStrictDict.iterkeysc                 C   s   t t| S r   )r2   r   r8   r   r   r   ry     s    zStrictDict.keysc                    s    fdd j D S )Nc                 3   s   | ]}t  |r|V  qd S r   r~   )r^   r   r8   r   r   	<genexpr>  s     
 z&StrictDict.__iter__.<locals>.<genexpr>)	__slots__r8   r   r8   r   rP     s    zStrictDict.__iter__c                 C   s   t t|  S r   )rN   r2   rY   r8   r   r   r   __len__  s    zStrictDict.__len__c                 C   s   t |  t | kS r   )r2   rY   r   otherr   r   r   __eq__  s    zStrictDict.__eq__c                 C   s
   | |k S r   r   r   r   r   r   __ne__  s    zStrictDict.__ne__c                    sP   t fdd|D  t }|jkrFG  fddd}|j|< j| S )Nc                 3   s$   | ]}| j krd | n|V  qdS )r{   N)r|   r   )r\   r   r   r     s    z$StrictDict.create.<locals>.<genexpr>c                       s   e Zd Z Zdd ZdS )z-StrictDict.create.<locals>.SpecificStrictDictc                 S   s   dd dd |  D  S )Nz{%s}, c                 s   s"   | ]\}}d |d|V  qdS )"z": Nr   )r^   ru   rv   r   r   r   r     s    zIStrictDict.create.<locals>.SpecificStrictDict.__repr__.<locals>.<genexpr>)joinrY   r8   r   r   r   __repr__  s    z6StrictDict.create.<locals>.SpecificStrictDict.__repr__N)r@   rA   rB   r   r   r   )allowed_keys_tupler   r   SpecificStrictDict  s   r   )tuple	frozenset_classes)r\   Zallowed_keysr   r   )r   r\   r   rq     s    

zStrictDict.create)N)N)r@   rA   rB   r   r|   r   r#   r)   r1   r   r-   rF   rx   rY   r   ry   rP   r   r   r   rw   rq   r   r   r   r   r   c  s&   

r   c                       sP   e Zd ZdZdddZedd Zd fdd		Zd
d Zdd Z	dd Z
  ZS )r
   )_cached_docpassthroughdocument_typeFc                 C   s6   | j r
|r0| jjj| jd| _ | j s0td|  | j S )N)pkz)Trying to dereference unknown document %s)r   r   Zobjectsr-   r   r   )r   forcer   r   r   fetch  s
    
zLazyReference.fetchc                 C   s   | j S r   )idr8   r   r   r   r     s    zLazyReference.pkNc                    s*   || _ || _|| _t | j  | d S r   )r   r   r   r"   r#   Z_get_collection_name)r   r   r   Z
cached_docr   r'   r   r   r#     s    zLazyReference.__init__c                 C   s   | j st |  }|| S r   )r   r*   r   r   r&   documentr   r   r   r)     s    zLazyReference.__getitem__c                 C   sD   t | dst |  }z
|| W S  tk
r>   t Y nX d S )Nr   )object__getattribute__r}   r   r*   r   r   r   r   __getattr__  s    
zLazyReference.__getattr__c                 C   s   d| j  d| jdS )Nz<LazyReference(r   z)>)r   r   r8   r   r   r   r     s    zLazyReference.__repr__)F)NF)r@   rA   rB   r   r   propertyr   r#   r)   r   r   rK   r   r   r'   r   r
     s   

	r
   )r   Zbsonr   Zmongoengine.commonr   Zmongoengine.errorsr   r   __all__r   r   r0   r   r2   r   r	   r   r
   r   r   r   r   <module>   s   	@W $R