U
    Lk7gg                    @   s  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Zd dlmZ d dl	m
Z
 d dlmZ d dlZd dlZd dlmZmZmZmZ d dlmZmZ d dlmZ d dlmZ zd dlZW n ek
r   dZY n
X d dlZd d	lmZmZm Z m!Z!m"Z"m#Z#m$Z$ d d
l%m&Z& d dl'm(Z( d dl)m*Z*m+Z+ d dl,m-Z-m.Z. d dl/m0Z0m1Z1m2Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8 z0d dl9m:Z:m;Z; e<e:dre:j=j>Z>ne:j>Z>W n ek
r   dZ:dZ;Y nX dZ?dZ@G dd deZAG dd deAZBG dd deAZCG dd deZDG dd deDZEG d d! d!eZFG d"d# d#eZGG d$d% d%eZHG d&d' d'eZIG d(d) d)eIZJG d*d+ d+eAZKG d,d- d-eZLG d.d/ d/eZMG d0d1 d1eZNG d2d3 d3e ZOG d4d5 d5eOZPG d6d7 d7eOZQd8d9 ZRd:d; ZSG d<d= d=e ZTG d>d? d?eTZUG d@dA dAeZVG dBdC dCeZWG dDdE dEeZXG dFdG dGeZYG dHdI dIeZZG dJdK dKe[Z\G dLdM dMZ]G dNdO dOeZ^G dPdQ dQe]Z_G dRdS dSe[Z`G dTdU dUe^ZaG dVdW dWeZbG dXdY dYeZcG dZd[ d[eZdG d\d] d]e!ZeG d^d_ d_e!ZfG d`da dae!ZgG dbdc dce!ZhG ddde dee!ZiG dfdg dge!ZjG dhdi dieZkG djdk dkeXZlG dldm dmeZmdS )n    N)isclass)BytesIO)
itemgetter)SONBinaryDBRefObjectId)
Decimal128create_decimal128_contextInt64)ReturnDocument)BaseDocument	BaseFieldComplexBaseFieldGeoJsonBaseFieldLazyReferenceObjectIdFieldget_document)LazyRegexCompiler)_import_class)DEFAULT_CONNECTION_NAMEget_db)DocumentEmbeddedDocument)DoesNotExistInvalidQueryErrorValidationError)
DO_NOTHING)BaseQuerySet)STRING_OPERATORS)ImageImageOps
Resampling),StringFieldURLField
EmailFieldIntField	LongField
FloatFieldDecimalFieldBooleanFieldDateTimeField	DateFieldComplexDateTimeFieldEmbeddedDocumentFieldr   GenericEmbeddedDocumentFieldDynamicField	ListFieldSortedListFieldEmbeddedDocumentListField	DictFieldMapFieldReferenceFieldCachedReferenceFieldLazyReferenceFieldGenericLazyReferenceFieldGenericReferenceFieldBinaryFieldGridFSErrorGridFSProxy	FileFieldImageGridFsProxyImproperlyConfigured
ImageFieldGeoPointField
PointFieldLineStringFieldPolygonFieldSequenceField	UUIDField	EnumFieldMultiPointFieldMultiLineStringFieldMultiPolygonFieldr   Decimal128Fieldselfc                       sF   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Z fddZ  Z	S )r$   zA unicode string field.Nc                    s2   |rt |nd| _|| _|| _t jf | dS )av  
        :param regex: (optional) A string pattern that will be applied during validation
        :param max_length: (optional) A max length that will be applied during validation
        :param min_length: (optional) A min length that will be applied during validation
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`
        N)recompileregex
max_length
min_lengthsuper__init__)rN   rQ   rR   rS   kwargs	__class__ 6/tmp/pip-unpacked-wheel-n1etwkgt/mongoengine/fields.pyrU   s   s    zStringField.__init__c                 C   s6   t |tr|S z|d}W n tk
r0   Y nX |S )Nzutf-8)
isinstancestrdecode	ExceptionrN   valuerY   rY   rZ   	to_python   s    
zStringField.to_pythonc                 C   s   t |ts| d | jd k	r6t|| jkr6| d | jd k	rXt|| jk rX| d | jd k	r|| j|d kr|| d d S )Nz&StringField only accepts string valueszString value is too longzString value is too shortz+String value did not match validation regex)r[   r\   errorrR   lenrS   rQ   matchr_   rY   rY   rZ   validate   s    



zStringField.validatec                 C   s   d S NrY   rN   member_namerY   rY   rZ   lookup_member   s    zStringField.lookup_memberc                    s   t |ts|S |tkr|d}|d}|r4tjnd}d}|dkrJd}n6|dkrXd}n(|dkrfd	}n|d
krtd}n|dkr|}|dkrt||}nt|}t|| |}t	 
||S )Nir   %s
startswithz^%sendswithz%s$exactz^%s$Z	wholewordz\b%s\brQ   )r[   r\   r    rl   lstriprO   
IGNORECASErP   escaperT   prepare_query_value)rN   opr`   Zcase_insensitiveflagsrQ   rW   rY   rZ   rr      s,    



zStringField.prepare_query_value)NNN)
__name__
__module____qualname____doc__rU   ra   re   ri   rr   __classcell__rY   rY   rW   rZ   r$   p   s   	r$   c                       sB   e Zd ZdZedejZddddgZd fdd		Z	d
d Z
  ZS )r%   z'A field that validates input as an URL.z^(?:[a-z0-9\.\-]*)://(?:(?:[A-Z0-9](?:[A-Z0-9-_]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?<!-)\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[?[A-F0-9]*:[A-F0-9:]+\]?)(?::\d+)?(?:/?|[/?]\S+)$httphttpsftpZftpsNc                    s*   |p| j | _|p| j| _t jf | dS )a  
        :param url_regex: (optional) Overwrite the default regex used for validation
        :param schemes: (optional) Overwrite the default URL schemes that are allowed
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.StringField`
        N)
_URL_REGEX	url_regex_URL_SCHEMESschemesrT   rU   )rN   r~   r   rV   rW   rY   rZ   rU      s    zURLField.__init__c                 C   sR   | dd  }|| jkr2| d| d|  | j|sN| d|  d S )Nz://r   zInvalid scheme z	 in URL: zInvalid URL: )splitlowerr   rb   r~   rd   )rN   r`   schemerY   rY   rZ   re      s
    
zURLField.validate)NN)ru   rv   rw   rx   r   rO   rp   r}   r   rU   re   ry   rY   rY   rW   rZ   r%      s   

r%   c                       sl   e Zd ZdZedejZedejejB Z	edejZ
dZd fdd		Zd
d Zdd Z fddZ  ZS )r&   z1A field that validates input as an email address.z(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)z(^[-!#$%&'*+/=?^_`{}|~0-9A-Z\u0080-\U0010FFFF]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z\u0080-\U0010FFFF]+)*\Z|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)zH((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+)(?:[A-Z0-9-]{2,63}(?<!-))\ZzInvalid email address: %sNFc                    s(   |pg | _ || _|| _t j|| dS )a{  
        :param domain_whitelist: (optional) list of valid domain names applied during validation
        :param allow_utf8_user: Allow user part of the email to contain utf8 char
        :param allow_ip_domain: Allow domain part of the email to be an IPv4 or IPv6 address
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.StringField`
        N)domain_whitelistallow_utf8_userallow_ip_domainrT   rU   )rN   r   r   r   argsrV   rW   rY   rZ   rU      s    
zEmailField.__init__c                 C   s   | j r| j|S | j|S )zgValidate the user part of the email address. Return True if
        valid and False otherwise.
        )r   UTF8_USER_REGEXrd   
USER_REGEX)rN   	user_partrY   rY   rZ   validate_user_part  s    zEmailField.validate_user_partc              
   C   s   || j krdS | j|rdS | jr|d dkr|d dkrtjtjfD ]:}zt||dd  W  dS  tt	fk
r   Y qHX qHdS )ziValidate the domain part of the email address. Return True if
        valid and False otherwise.
        Tr   []   F)
r   DOMAIN_REGEXrd   r   socketAF_INETAF_INET6	inet_ptonOSErrorUnicodeEncodeError)rN   domain_partZaddr_familyrY   rY   rZ   validate_domain_part  s    
zEmailField.validate_domain_partc              	      s   t  | d|kr$| | j|  |dd\}}| |sN| | j|  | |sz|dd}W n, t	k
r   | d
| j| d Y n$X | |s| d
| j| d d S )N@r   idnaasciiz{} {}z(domain failed IDN encoding)z(domain validation failed))rT   re   rb   	error_msgrsplitr   r   encoder]   UnicodeErrorformat)rN   r`   r   r   rW   rY   rZ   re   )  s.    

 

 zEmailField.validate)NFF)ru   rv   rw   rx   r   rO   rp   r   UNICODEr   r   r   rU   r   r   re   ry   rY   rY   rW   rZ   r&      s*   
   r&   c                       s>   e Zd ZdZd fdd	Zdd Zdd Z fd	d
Z  ZS )r'   z32-bit integer field.Nc                    s    || | _ | _t jf | dS a  
        :param min_value: (optional) A min value that will be applied during validation
        :param max_value: (optional) A max value that will be applied during validation
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`
        N	min_value	max_valuerT   rU   rN   r   r   rV   rW   rY   rZ   rU   K  s    zIntField.__init__c              	   C   s*   zt |}W n ttfk
r$   Y nX |S rf   )int	TypeError
ValueErrorr_   rY   rY   rZ   ra   T  s
    zIntField.to_pythonc              	   C   st   zt |}W n& ttfk
r2   | d|  Y nX | jd k	rR|| jk rR| d | jd k	rp|| jkrp| d d S )Nz %s could not be converted to intzInteger value is too smallzInteger value is too large)r   r   r   rb   r   r   r_   rY   rY   rZ   re   [  s    
zIntField.validatec                    s   |d kr|S t  |t|S rf   )rT   rr   r   rN   rs   r`   rW   rY   rZ   rr   g  s    zIntField.prepare_query_value)NN	ru   rv   rw   rx   rU   ra   re   rr   ry   rY   rY   rW   rZ   r'   H  s
   	r'   c                   @   s   e Zd ZdZdd ZdS )r(   zW64-bit integer field. (Equivalent to IntField since the support to Python2 was dropped)c                 C   s   t |S rf   r   r_   rY   rY   rZ   to_mongoq  s    zLongField.to_mongoN)ru   rv   rw   rx   r   rY   rY   rY   rZ   r(   n  s   r(   c                       s>   e Zd ZdZd fdd	Zdd Zdd Z fd	d
Z  ZS )r)   zFloating point number field.Nc                    s    || | _ | _t jf | dS r   r   r   rW   rY   rZ   rU   x  s    zFloatField.__init__c                 C   s&   zt |}W n tk
r    Y nX |S rf   )floatr   r_   rY   rY   rZ   ra     s
    zFloatField.to_pythonc                 C   s   t |tr6zt|}W n tk
r4   | d Y nX t |tsJ| d | jd k	rh|| jk rh| d | jd k	r|| jkr| d d S )Nz/The value is too large to be converted to floatz0FloatField only accepts float and integer valueszFloat value is too smallzFloat value is too large)r[   r   r   OverflowErrorrb   r   r   r_   rY   rY   rZ   re     s    



zFloatField.validatec                    s   |d kr|S t  |t|S rf   )rT   rr   r   r   rW   rY   rZ   rr     s    zFloatField.prepare_query_value)NNr   rY   rY   rW   rZ   r)   u  s
   	r)   c                       sR   e Zd ZdZddddejf fdd	Zdd Zd	d
 Zdd Z	 fddZ
  ZS )r*   a  Disclaimer: This field is kept for historical reason but since it converts the values to float, it
    is not suitable for true decimal storage. Consider using :class:`~mongoengine.fields.Decimal128Field`.

    Fixed-point decimal number field. Stores the value as a float by default unless `force_string` is used.
    If using floats, beware of Decimal to float conversion (potential precision loss)
    NF   c                    sL   || _ || _|| _|dk s$t|ts.| d || _|| _t j	f | dS )a%  
        :param min_value: (optional) A min value that will be applied during validation
        :param max_value: (optional) A max value that will be applied during validation
        :param force_string: Store the value as a string (instead of a float).
         Be aware that this affects query sorting and operation like lte, gte (as string comparison is applied)
         and some query operator won't work (e.g. inc, dec)
        :param precision: Number of decimal places to store.
        :param rounding: The rounding rule from the python decimal library:

            - decimal.ROUND_CEILING (towards Infinity)
            - decimal.ROUND_DOWN (towards zero)
            - decimal.ROUND_FLOOR (towards -Infinity)
            - decimal.ROUND_HALF_DOWN (to nearest with ties going towards zero)
            - decimal.ROUND_HALF_EVEN (to nearest with ties going to nearest even integer)
            - decimal.ROUND_HALF_UP (to nearest with ties going away from zero)
            - decimal.ROUND_UP (away from zero)
            - decimal.ROUND_05UP (away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)

            Defaults to: ``decimal.ROUND_HALF_UP``
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`
        r   z$precision must be a positive integerN)
r   r   force_stringr[   r   rb   	precisionroundingrT   rU   )rN   r   r   r   r   r   rV   rW   rY   rZ   rU     s    
zDecimalField.__init__c              
   C   sv   zt d| }W n  ttt jfk
r2   | Y S X | jdkr^|jt dd| j  | jdS |jt  | jdS d S )Nrk   r   z.%s0)r   )decimalDecimalr   r   InvalidOperationr   quantizer   r_   rY   rY   rZ   ra     s    

 zDecimalField.to_pythonc                 C   s"   | j rt| |S t| |S rf   )r   r\   ra   r   r_   rY   rY   rZ   r     s    zDecimalField.to_mongoc              
   C   s   t |tjsft |tst|}zt|}W n8 tttjfk
rd } z| d|  W 5 d }~X Y nX | jd k	r|| jk r| d | j	d k	r|| j	kr| d d S )Nz&Could not convert value to decimal: %sDecimal value is too smallDecimal value is too large)
r[   r   r   r\   r   r   r   rb   r   r   rN   r`   excrY   rY   rZ   re     s    
 
zDecimalField.validatec                    s    |d kr|S t  || |S rf   rT   rr   r   r   rW   rY   rZ   rr     s    z DecimalField.prepare_query_value)ru   rv   rw   rx   r   ROUND_HALF_UPrU   ra   r   re   rr   ry   rY   rY   rW   rZ   r*     s   	*r*   c                   @   s    e Zd ZdZdd Zdd ZdS )r+   zBoolean field type.c              	   C   s*   zt |}W n ttfk
r$   Y nX |S rf   )boolr   r   r_   rY   rY   rZ   ra     s
    zBooleanField.to_pythonc                 C   s   t |ts| d d S )Nz(BooleanField only accepts boolean values)r[   r   rb   r_   rY   rY   rZ   re     s    
zBooleanField.validateN)ru   rv   rw   rx   ra   re   rY   rY   rY   rZ   r+     s   r+   c                       s<   e Zd ZdZdd Zdd Zedd Z fdd	Z  Z	S )
r,   av  Datetime field.

    Uses the python-dateutil library if available alternatively use time.strptime
    to parse the dates.  Note: python-dateutil's parser is fully featured and when
    installed you can utilise it to convert varying types of date formats into valid
    python datetime objects.

    Note: To default the field to the current datetime, use: DateTimeField(default=datetime.utcnow)

    Note: Microseconds are rounded to the nearest millisecond.
      Pre UTC microsecond support is effectively broken.
      Use :class:`~mongoengine.fields.ComplexDateTimeField` if you
      need accurate microsecond support.
    c                 C   s.   |  |}t|tjtjfs*| d|  d S )Nzcannot parse date "%s")r   r[   datetimedaterb   )rN   r`   	new_valuerY   rY   rZ   re     s    
zDateTimeField.validatec                 C   sf   |d kr|S t |tjr|S t |tjr<t|j|j|jS t|rJ| S t |tr^| |S d S d S rf   )	r[   r   r   yearmonthdaycallabler\   _parse_datetimer_   rY   rY   rZ   r     s    

zDateTimeField.to_mongoc                 C   s@  |   } | sd S tr@ztj| W S  tttfk
r>   Y d S X d| kr|z| d\} }t|}W q tk
rx   Y d S X nd}d|i}zt	j	t
| dd d |W S  tk
r:   z"t	j	t
| dd d |W  Y S  tk
r4   z&t	j	t
| dd d	 |W  Y  Y S  tk
r.   Y Y Y d S X Y nX Y nX d S )
N.r   microsecondz%Y-%m-%d %H:%M:%S   z%Y-%m-%d %H:%M   z%Y-%m-%d   )stripdateutilparserparser   r   r   r   r   r   timestrptime)r`   ZusecsrV   rY   rY   rZ   r   +  sF    
  
 zDateTimeField._parse_datetimec                    s   t  || |S rf   r   r   rW   rY   rZ   rr   S  s    z!DateTimeField.prepare_query_value)
ru   rv   rw   rx   re   r   staticmethodr   rr   ry   rY   rY   rW   rZ   r,     s   
'r,   c                       s(   e Zd Z fddZ fddZ  ZS )r-   c                    s0   t  |}t|tjr,t|j|j|j}|S rf   )rT   r   r[   r   r   r   r   r_   rW   rY   rZ   r   X  s    zDateField.to_mongoc                    s0   t  |}t|tjr,t|j|j|j}|S rf   )rT   ra   r[   r   r   r   r   r   r_   rW   rY   rZ   ra   _  s    zDateField.to_python)ru   rv   rw   r   ra   ry   rY   rY   rW   rZ   r-   W  s   r-   c                       sn   e Zd ZdZd fdd	Zdd Zdd Z fd	d
Z fddZdd Z	dd Z
dd Z fddZ  ZS )r.   a  
    ComplexDateTimeField handles microseconds exactly instead of rounding
    like DateTimeField does.

    Derives from a StringField so you can do `gte` and `lte` filtering by
    using lexicographical comparison when filtering / sorting strings.

    The stored string has the following format:

        YYYY,MM,DD,HH,MM,SS,NNNNNN

    Where NNNNNN is the number of microseconds of the represented `datetime`.
    The `,` as the separator can be easily modified by passing the `separator`
    keyword when initializing the field.

    Note: To default the field to the current datetime, use: DateTimeField(default=datetime.utcnow)
    ,c              	      s2   || _ |dddddddg| _t jf | dS )	z
        :param separator: Allows to customize the separator used for storage (default ``,``)
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.StringField`
        z%Yz%mz%dz%Hz%Mz%Sz%fN)	separatorjoinr   rT   rU   )rN   r   rV   rW   rY   rZ   rU   z  s    zComplexDateTimeField.__init__c                 C   s   | | jS )aN  
        Convert a `datetime` object to a string representation (which will be
        stored in MongoDB). This is the reverse function of
        `_convert_from_string`.

        >>> a = datetime(2011, 6, 8, 20, 26, 24, 92284)
        >>> ComplexDateTimeField()._convert_from_datetime(a)
        '2011,06,08,20,26,24,092284'
        )strftimer   )rN   valrY   rY   rZ   _convert_from_datetime  s    
z+ComplexDateTimeField._convert_from_datetimec                 C   s    dd | | jD }tj| S )aV  
        Convert a string representation to a `datetime` object (the object you
        will manipulate). This is the reverse function of
        `_convert_from_datetime`.

        >>> a = '2011,06,08,20,26,24,092284'
        >>> ComplexDateTimeField()._convert_from_string(a)
        datetime.datetime(2011, 6, 8, 20, 26, 24, 92284)
        c                 S   s   g | ]}t |qS rY   )r   ).0drY   rY   rZ   
<listcomp>  s     z=ComplexDateTimeField._convert_from_string.<locals>.<listcomp>)r   r   r   )rN   datavaluesrY   rY   rZ   _convert_from_string  s    
z)ComplexDateTimeField._convert_from_stringc                    s<   |d kr| S t  ||}t|tjs.|d kr2|S | |S rf   )rT   __get__r[   r   r   )rN   instanceownerr   rW   rY   rZ   r     s    zComplexDateTimeField.__get__c                    sR   t  || |j| j }|d k	rNt|tjrB| ||j| j< n||j| j< d S rf   )rT   __set___datanamer[   r   r   rN   r   r`   rW   rY   rZ   r     s    zComplexDateTimeField.__set__c                 C   s$   |  |}t|tjs | d d S )Nz8Only datetime objects may used in a ComplexDateTimeField)ra   r[   r   rb   r_   rY   rY   rZ   re     s    
zComplexDateTimeField.validatec                 C   s.   |}z|  |W S  tk
r(   | Y S X d S rf   )r   r^   rN   r`   original_valuerY   rY   rZ   ra     s
    zComplexDateTimeField.to_pythonc                 C   s   |  |}| |S rf   )ra   r   r_   rY   rY   rZ   r     s    
zComplexDateTimeField.to_mongoc                    s    |d kr|S t  || |S rf   )rT   rr   r   r   rW   rY   rZ   rr     s    z(ComplexDateTimeField.prepare_query_value)r   )ru   rv   rw   rx   rU   r   r   r   r   re   ra   r   rr   ry   rY   rY   rW   rZ   r.   g  s   	
	r.   c                       s\   e Zd ZdZ fddZedd Zdd Zdd
dZdddZ	dd Z
 fddZ  ZS )r/   zAn embedded document field - with a declared document_type.
    Only valid values are subclasses of :class:`~mongoengine.EmbeddedDocument`.
    c                    s6   t |tst|ts| d || _t jf | d S NzDInvalid embedded document class provided to an EmbeddedDocumentField)r[   r\   
issubclassr   rb   document_type_objrT   rU   rN   document_typerV   rW   rY   rZ   rU     s    zEmbeddedDocumentField.__init__c                 C   sH   t | jtrB| jtkr| j}n
t| j}t|ts<| d || _| jS r   )	r[   r   r\   RECURSIVE_REFERENCE_CONSTANTowner_documentr   r   r   rb   )rN   Zresolved_document_typerY   rY   rZ   r     s    


z#EmbeddedDocumentField.document_typec                 C   s"   t || js| jj|| jdS |S )N)_auto_dereference)r[   r   	_from_sonr   r_   rY   rY   rZ   ra     s     zEmbeddedDocumentField.to_pythonTNc                 C   s    t || js|S | j|||S rf   )r[   r   r   rN   r`   use_db_fieldfieldsrY   rY   rZ   r     s    zEmbeddedDocumentField.to_mongoc                 C   s&   t || js| d |j|d dS )zMake sure that the document instance is an instance of the
        EmbeddedDocument subclass provided when the document was defined.
        zGInvalid embedded document instance provided to an EmbeddedDocumentFieldcleanN)r[   r   rb   re   rN   r`   r   rY   rY   rZ   re     s
    zEmbeddedDocumentField.validatec                 C   s8   | j g| j   }|D ]}|j|}|r|  S qd S rf   )r   __subclasses___fieldsget)rN   rh   doc_and_subclassesdoc_typefieldrY   rY   rZ   ri     s
    z#EmbeddedDocumentField.lookup_memberc                    s   |d k	rpt || jspt |tr8tdd | D r8|S z| j|}W n& tk
rn   td| jjf Y nX t	 
|| | |S )Nc                 s   s   | ]}| d V  qdS )$N)rl   )r   krY   rY   rZ   	<genexpr>  s     z<EmbeddedDocumentField.prepare_query_value.<locals>.<genexpr>zIQuerying the embedded document '%s' failed, due to an invalid query value)r[   r   dictallkeysr   r   r   _class_namerT   rr   r   r   rW   rY   rZ   rr   	  s     
z)EmbeddedDocumentField.prepare_query_value)TN)T)ru   rv   rw   rx   rU   propertyr   ra   r   re   ri   rr   ry   rY   rY   rW   rZ   r/     s   


r/   c                       sD   e Zd ZdZ fddZdd ZdddZd	d
 ZdddZ  Z	S )r0   a*  A generic embedded document field - allows any
    :class:`~mongoengine.EmbeddedDocument` to be stored.

    Only valid values are subclasses of :class:`~mongoengine.EmbeddedDocument`.

    .. note ::
        You can use the choices param to limit the acceptable
        EmbeddedDocument types
    c                    s   t  || |S rf   r   r   rW   rY   rZ   rr   $  s    z0GenericEmbeddedDocumentField.prepare_query_valuec                 C   s$   t |tr t|d }||}|S N_cls)r[   r   r   r   rN   r`   doc_clsrY   rY   rZ   ra   '  s    

z&GenericEmbeddedDocumentField.to_pythonTc                 C   sT   | j r0t|tr0| j D ]}|d |jkr dS qt|tsD| d |j|d d S )Nr  TzNInvalid embedded document instance provided to an GenericEmbeddedDocumentFieldr   )choicesr[   r   r  r   rb   re   )rN   r`   r   choicerY   rY   rZ   re   .  s    

z%GenericEmbeddedDocumentField.validatec                 C   sL   | j pg }|D ]8}|g|  }|D ] }|j|}|r$|    S q$qd S rf   )r	  r   r   r   )rN   rh   Zdocument_choicesZdocument_choicer   r   r   rY   rY   rZ   ri   <  s    
z*GenericEmbeddedDocumentField.lookup_memberNc                 C   s.   |d krd S | ||}d|kr*|j|d< |S r  )r   r  )rN   documentr   r   r   rY   rY   rZ   r   E  s    
z%GenericEmbeddedDocumentField.to_mongo)T)TN)
ru   rv   rw   rx   rr   ra   re   ri   r   ry   rY   rY   rW   rZ   r0     s   

	r0   c                       sH   e Zd ZdZdddZ fddZdd	 Z fd
dZdddZ  Z	S )r1   zA truly dynamic field type capable of handling different and varying
    types of data.

    Used by :class:`~mongoengine.DynamicDocument` to handle dynamic dataTNc           
      C   s   t |tr|S t|dr\|j}|||}t |trD| |jd}t |trX|j|d< |S t |t	t
tfsp|S d}t|dsd}dd t|D }i }| D ]\}}	| |	||||< q|}|rd	d
 t| tddD }|S )z3Convert a Python type to a MongoDB compatible type.r   )_refr  r  FitemsTc                 S   s   i | ]\}}||qS rY   rY   r   r   vrY   rY   rZ   
<dictcomp>j  s      z)DynamicField.to_mongo.<locals>.<dictcomp>c                 S   s   g | ]\}}|qS rY   rY   r  rY   rY   rZ   r   r  s     z)DynamicField.to_mongo.<locals>.<listcomp>r   )key)r[   r\   hasattrrX   r   r   Zto_dbrefru   r   r   listtuple	enumerater  sortedr   )
rN   r`   r   r   clsr   Zis_listr   r   r  rY   rY   rZ   r   T  s.    





zDynamicField.to_mongoc                    sN   t |trBd|krBt|d }d|kr8| |d }||S t |S Nr  r  )r[   r   r   _get_dbdereferencer   rT   ra   r  rW   rY   rZ   ra   u  s    
zDynamicField.to_pythonc                 C   s   |S rf   rY   rg   rY   rY   rZ   ri   ~  s    zDynamicField.lookup_memberc                    s,   t |trt ||S t || |S rf   )r[   r\   r$   rr   rT   r   r   rW   rY   rZ   rr     s    
z DynamicField.prepare_query_valuec                 C   s   t |dr|j|d d S )Nre   r   )r  re   r   rY   rY   rZ   re     s    
zDynamicField.validate)TN)T)
ru   rv   rw   rx   r   ra   ri   rr   re   ry   rY   rY   rW   rZ   r1   N  s   
!	r1   c                       sL   e Zd ZdZddd fddZ fddZ fdd	Z fd
dZ  ZS )r2   a,  A list field that wraps a standard field, allowing multiple instances
    of the field to be used as a list in the database.

    If using with ReferenceFields see: :ref:`many-to-many-with-listfields`

    .. note::
        Required means it cannot be empty - as the default for ListFields is []
    N)rR   c                   s,   || _ |dt t jf d|i| d S )Ndefaultr   )rR   
setdefaultr  rT   rU   )rN   r   rR   rV   rW   rY   rZ   rU     s    zListField.__init__c                    sf   |d kr S |j  j}td}td}t j||frX|rX fdd|D |j  j< t ||S )Nr9   r:   c                    s   g | ]} j |qS rY   )r   build_lazyref)r   xrN   rY   rZ   r     s     z%ListField.__get__.<locals>.<listcomp>)r   r   r   r   r[   r   rT   r   )rN   r   r   r`   r9   r:   rW   r  rZ   r     s    zListField.__get__c                    sL   t |tttfs| d | jdk	r<t|| jkr<| d t | dS )4Make sure that a list of valid fields is being used.z1Only lists and tuples may be used in a list fieldNList is too long)	r[   r  r  r   rb   rR   rc   rT   re   r_   rW   rY   rZ   re     s
    

zListField.validatec                    s    dkr*j d k	r*t|j kr*d jr|t|d}|oLt|ttf } dkrn|rn fdd|D S j |S t	  |S )Nsetr!  __iter__)r"  unsetgtZgteltZlteneNc                    s   g | ]}j  |qS rY   r   rr   )r   r  rs   rN   rY   rZ   r     s     z1ListField.prepare_query_value.<locals>.<listcomp>)
rR   rc   rb   r   r  r[   r\   r   rr   rT   )rN   rs   r`   Zis_iterZeligible_iterrW   r)  rZ   rr     s     

zListField.prepare_query_value)N)	ru   rv   rw   rx   rU   r   re   rr   ry   rY   rY   rW   rZ   r2     s
   	r2   c                       s    e Zd ZdZ fddZ  ZS )r4   zA :class:`~mongoengine.ListField` designed specially to hold a list of
    embedded documents to provide additional query helpers.

    .. note::
        The only valid list values are subclasses of
        :class:`~mongoengine.EmbeddedDocument`.
    c                    s   t  jf dt|i| dS )z
        :param document_type: The type of
         :class:`~mongoengine.EmbeddedDocument` the list will hold.
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.ListField`
        r   N)rT   rU   r/   r   rW   rY   rZ   rU     s    z"EmbeddedDocumentListField.__init__ru   rv   rw   rx   rU   ry   rY   rY   rW   rZ   r4     s   r4   c                       s.   e Zd ZdZ fddZd fdd	Z  ZS )	r3   a  A ListField that sorts the contents of its list before writing to
    the database in order to ensure that a sorted list is always
    retrieved.

    .. warning::
        There is a potential race condition when handling lists.  If you set /
        save the whole list then other processes trying to save the whole list
        as well could overwrite changes.  The safest way to append to a list is
        to perform a push operation.
    c                    s0   | dd | _| dd| _t j|f| d S )NZorderingreverseF)pop	_ordering_order_reverserT   rU   )rN   r   rV   rW   rY   rZ   rU     s    zSortedListField.__init__TNc                    s>   t  |||}| jd k	r0t|t| j| jdS t|| jdS )N)r  r+  )r+  )rT   r   r-  r  r   r.  r   rW   rY   rZ   r     s    
  zSortedListField.to_mongo)TN)ru   rv   rw   rx   rU   r   ry   rY   rY   rW   rZ   r3     s   r3   c                 C   s8   |   D ]*\}}t|tr,t|trt|r dS qdS )z]Helper function to recursively determine if any key in a
    dictionary is not a string.
    TN)r  r[   r\   r   key_not_stringr   r   r  rY   rY   rZ   r/    s    r/  c                 C   s8   |   D ]*\}}|ds,t|trt|r dS qdS )zaHelper function to recursively determine if any key in a
    dictionary starts with a dollar
    r   TN)r  rl   r[   r   key_starts_with_dollarr0  rY   rY   rZ   r1     s    r1  c                       sB   e Zd ZdZd fdd	Z fddZdd Z fd	d
Z  ZS )r5   zA dictionary field that wraps a standard Python dictionary. This is
    similar to an embedded document, but the structure is not defined.

    .. note::
        Required means it cannot be empty - as the default for DictFields is {}
    Nc                    s0   | dt t j|d|i| | d d S )Nr  r   F)r  r   rT   rU   Zset_auto_dereferencingrN   r   r   rV   rW   rY   rZ   rU     s    zDictField.__init__c                    sL   t |ts| d t|r*d}| | t|r<| d t | dS )r   z,Only dictionaries may be used in a DictFieldz=Invalid dictionary key - documents must have only string keyszDInvalid dictionary key name - keys may not startswith "$" charactersN)r[   r   rb   r/  r1  rT   re   )rN   r`   msgrW   rY   rZ   re     s    


zDictField.validatec                 C   s
   t |dS )N)Zdb_field)r5   rg   rY   rY   rZ   ri   *  s    zDictField.lookup_memberc                    sx   t } |kr&t|tr&t  |S tjdrj dkr\t|tr\ fdd| D S j |S t	  |S )Nr   )r"  r$  c                    s    i | ]\}}|j  |qS rY   r(  r  r)  rY   rZ   r  7  s     z1DictField.prepare_query_value.<locals>.<dictcomp>)
r    r[   r\   r$   rr   r  r   r   r  rT   )rN   rs   r`   Zmatch_operatorsrW   r)  rZ   rr   -  s     zDictField.prepare_query_value)N)	ru   rv   rw   rx   rU   re   ri   rr   ry   rY   rY   rW   rZ   r5   	  s
   r5   c                       s"   e Zd ZdZd fdd	Z  ZS )r6   zA field that maps a name to a specified field type. Similar to
    a DictField, except the 'value' of each item must match the specified
    field type.
    Nc                    s.   t |ts| d t j|d|i| d S )Nz6Argument to MapField constructor must be a valid fieldr   )r[   r   rb   rT   rU   r2  rW   rY   rZ   rU   E  s    

zMapField.__init__)Nr*  rY   rY   rW   rZ   r6   ?  s   r6   c                       sv   e Zd ZdZdef fdd	Zedd Zedd Z	 fd	d
Z
dd Zdd Z fddZdd Zdd Z  ZS )r7   a  A reference to a document that will be automatically dereferenced on
    access (lazily).

    Note this means you will get a database I/O access everytime you access
    this field. This is necessary because the field returns a :class:`~mongoengine.Document`
    which precise type can depend of the value of the `_cls` field present in the
    document in database.
    In short, using this type of field can lead to poor performances (especially
    if you access this field only to retrieve it `pk` field which is already
    known before dereference). To solve this you should consider using the
    :class:`~mongoengine.fields.LazyReferenceField`.

    Use the `reverse_delete_rule` to handle what should happen if the document
    the field is referencing is deleted.  EmbeddedDocuments, DictFields and
    MapFields does not support reverse_delete_rule and an `InvalidDocumentError`
    will be raised if trying to set on one of these Document / Field types.

    The options are:

      * DO_NOTHING (0)  - don't do anything (default).
      * NULLIFY    (1)  - Updates the reference to null.
      * CASCADE    (2)  - Deletes the documents associated with the reference.
      * DENY       (3)  - Prevent the deletion of the reference object.
      * PULL       (4)  - Pull the reference from a :class:`~mongoengine.fields.ListField` of references

    Alternative syntax for registering delete rules (useful when implementing
    bi-directional delete rules)

    .. code-block:: python

        class Org(Document):
            owner = ReferenceField('User')

        class User(Document):
            org = ReferenceField('Org', reverse_delete_rule=CASCADE)

        User.register_delete_rule(Org, 'owner', DENY)
    Fc                    sJ   t |ts&t|rt|ts&| d || _|| _|| _t	 j
f | dS )aq  Initialises the Reference Field.

        :param document_type: The type of Document that will be referenced
        :param dbref:  Store the reference as :class:`~pymongo.dbref.DBRef`
          or as the :class:`~pymongo.objectid.ObjectId`.
        :param reverse_delete_rule: Determines what to do when the referring
          object is deleted
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`

        .. note ::
            A reference to an abstract document type is always stored as a
            :class:`~pymongo.dbref.DBRef`, regardless of the value of `dbref`.
        zKArgument to ReferenceField constructor must be a document class or a stringN)r[   r\   r   r   r   rb   dbrefr   reverse_delete_rulerT   rU   )rN   r   r4  r5  rV   rW   rY   rZ   rU   t  s    zReferenceField.__init__c                 C   s2   t | jtr,| jtkr | j| _nt| j| _| jS rf   r[   r   r\   r   r   r   r  rY   rY   rZ   r     s
    

zReferenceField.document_typec                 C   s.   |   |}|d kr$td| | |S Nz'Trying to dereference unknown document r  r  r   r   Zref_clsr4  Zdereferenced_sonrY   rY   rZ   _lazy_load_ref  s    zReferenceField._lazy_load_refc                    st   |dkr| S |j | j}|j| j j}|rft|trft|drLt|j	}n| j
}| |||j | j< t ||S )'Descriptor to allow lazy dereferencing.Nr  )r   r   r   r   r   r[   r   r  r   r  r   r:  rT   r   )rN   r   r   Z	ref_valueauto_dereferencer  rW   rY   rZ   r     s    
zReferenceField.__get__c                 C   s   t |tr| js|jS |S t |trB|j}|d kr<| d |}n
|}| j}|jd }|j	| }|
|}| jjdr| }t|||jdS | jr| }t||S |S )NJYou can only reference documents once they have been saved to the databaseid_fieldabstract)r  )r[   r   r4  idr   pkrb   r   _metar   r   r   _get_collection_namer  )rN   r  id_r  id_field_namer>  
collectionrY   rY   rZ   r     s.    





zReferenceField.to_mongoc                 C   s8   | j s4t|tttfs4| j }t|| jj|}|S z3Convert a MongoDB-compatible type to a Python type.)	r4  r[   r   r   r   r   rC  r@  ra   rN   r`   rF  rY   rY   rZ   ra     s     
zReferenceField.to_pythonc                    s$   |d krd S t  || | |S rf   r   r   rW   rY   rZ   rr     s    z"ReferenceField.prepare_query_valuec                 C   s@   t || jtttfs| d t |tr<|jd kr<| d d S )NzIA ReferenceField only accepts DBRef, LazyReference, ObjectId or documentsr=  )r[   r   r   r   r   rb   r   r@  r_   rY   rY   rZ   re     s    zReferenceField.validatec                 C   s   | j j|S rf   r   r   r   rg   rY   rY   rZ   ri     s    zReferenceField.lookup_member)ru   rv   rw   rx   r   rU   r  r   r   r:  r   r   ra   rr   re   ri   ry   rY   rY   rW   rZ   r7   L  s   ( 

%	r7   c                       s   e Zd ZdZd fdd	Zdd Zdd	 Zd
d Zedd Z	e
dd Z fddZdddZdd Zdd Zdd Zdd Z  ZS )r8   z:A referencefield with cache fields to purpose pseudo-joinsNTc                    sX   |dkrg }t |ts4t|r*t|ts4| d || _|| _|| _	t
 jf | dS )a[  Initialises the Cached Reference Field.

        :param document_type: The type of Document that will be referenced
        :param fields:  A list of fields to be cached in document
        :param auto_sync: if True documents are auto updated
        :param kwargs: Keyword arguments passed into the parent :class:`~mongoengine.BaseField`
        NzQArgument to CachedReferenceField constructor must be a document class or a string)r[   r\   inspectr   r   r   rb   	auto_syncr   r   rT   rU   )rN   r   r   rK  rV   rW   rY   rZ   rU      s    
zCachedReferenceField.__init__c                 C   s$   ddl m} |jj| j| jd d S )Nr   )signals)sender)ZmongoenginerL  Z	post_saveconnecton_document_pre_saver   )rN   rL  rY   rY   rZ   start_listener  s    z#CachedReferenceField.start_listenerc                    sR   |rd S  fdd|  d  D }|rNi }|| j<  jjf |jf | d S )Nc                    s.   i | ]&\}}| j krd  j d| |qS )Zset____)r   r   )r   r  r   r  rY   rZ   r  "  s   
 z=CachedReferenceField.on_document_pre_save.<locals>.<dictcomp>r   )Z_deltar  r   r   objectsupdate)rN   rM  r  createdrV   update_kwargsfilter_kwargsrY   r  rZ   rO    s    

z)CachedReferenceField.on_document_pre_savec                 C   sH   t |trD| j }t|| jj|d }| j| j 	|S |S )N_id)
r[   r   r   rC  r   r@  ra   r   r  r  rH  rY   rY   rZ   ra   -  s    

zCachedReferenceField.to_pythonc                 C   s2   t | jtr,| jtkr | j| _nt| j| _| jS rf   r6  r  rY   rY   rZ   r   7  s
    

z"CachedReferenceField.document_typec                 C   s.   |   |}|d kr$td| | |S r7  r8  r9  rY   rY   rZ   r:  @  s    z#CachedReferenceField._lazy_load_refc                    sZ   |d kr| S |j | j}|j| j j}|rLt|trL| | j||j | j< t	 
||S rf   )r   r   r   r   r   r[   r   r:  r   rT   r   )rN   r   r   r`   r<  rW   rY   rZ   r   H  s    zCachedReferenceField.__get__c           	         s   | j jd }| j j| }t|tr<|j}|d krF| d n
| d td||ff} rt fdd| j	D }n| j	}|
t|j||d |S )Nr>  r=  zOnly accept a document objectrW  c                    s   g | ]}| kr|qS rY   rY   )r   fr   rY   rZ   r   j  s      z1CachedReferenceField.to_mongo.<locals>.<listcomp>rY  )r   rB  r   r[   r   rA  rb   r   r   r   rS  r   )	rN   r  r   r   rE  r>  rD  r`   
new_fieldsrY   rY  rZ   r   W  s    

zCachedReferenceField.to_mongoc                 C   s^   |d krd S t |trV|jd kr*| d d|ji}| jD ]}|||| i q:|S td S )Nr=  rW  )r[   r   rA  rb   r   rS  NotImplementedError)rN   rs   r`   Z
value_dictr   rY   rY   rZ   rr   q  s    



z(CachedReferenceField.prepare_query_valuec                 C   s8   t || js| d t |tr4|jd kr4| d d S )Nz-A CachedReferenceField only accepts documentsr=  )r[   r   rb   r   r@  r_   rY   rY   rZ   re     s    
zCachedReferenceField.validatec                 C   s   | j j|S rf   rI  rg   rY   rY   rZ   ri     s    z"CachedReferenceField.lookup_memberc                 C   sL   d| j  }| jjD ]4}i }||| j < i }|||< | jjf |jf | qdS )zb
        Sync all cached fields on demand.
        Caution: this operation may be slower.
        zset__%sN)r   r   rR  r   rS  )rN   Z
update_keydocrV  rU  rY   rY   rZ   sync_all  s    

zCachedReferenceField.sync_all)NT)TN)ru   rv   rw   rx   rU   rP  rO  ra   r  r   r   r:  r   r   rr   re   ri   r]  ry   rY   rY   rW   rZ   r8     s   




r8   c                       s\   e Zd ZdZ fddZ fddZedd Z fdd	Zd
d Z	dd Z
dd Z  ZS )r;   a  A reference to *any* :class:`~mongoengine.document.Document` subclass
    that will be automatically dereferenced on access (lazily).

    Note this field works the same way as :class:`~mongoengine.document.ReferenceField`,
    doing database I/O access the first time it is accessed (even if it's to access
    it ``pk`` or ``id`` field).
    To solve this you should consider using the
    :class:`~mongoengine.fields.GenericLazyReferenceField`.

    .. note ::
        * Any documents used as a generic reference must be registered in the
          document registry.  Importing the model will automatically register
          it.

        * You can use the choices param to limit the acceptable Document types
    c                    sx   | dd }t j|| g | _|rt|D ]J}t|trD| j| q(t|trht|t	rh| j|j
 q(| d q(d S )Nr	  zIInvalid choices provided: must be a list ofDocument subclasses and/or str)r,  rT   rU   r	  r[   r\   appendtyper   r   r  rb   )rN   r   rV   r	  r
  rW   rY   rZ   rU     s    
zGenericReferenceField.__init__c                    s6   t |tr|d}nt |tr&|j}t | d S r  )r[   r   r   r   r  rT   _validate_choicesr_   rW   rY   rZ   r`    s
    

z'GenericReferenceField._validate_choicesc                 C   s.   |   |}|d kr$td| | |S r7  r8  r9  rY   rY   rZ   r:    s    z$GenericReferenceField._lazy_load_refc                    sh   |d kr| S |j | j}|j| j j}|rZt|trZt|d }| ||d |j | j< t	 
||S r  )r   r   r   r   r   r[   r   r   r:  rT   r   )rN   r   r   r`   r<  r  rW   rY   rZ   r     s    zGenericReferenceField.__get__c                 C   sh   t |ttttfs| d t |ttfrFd|ks:d|krd| d nt |trd|jd krd| d d S )Nz,GenericReferences can only contain documentsr  r  r=  )r[   r   r   r   r   rb   r@  r_   rY   rY   rZ   re     s    
zGenericReferenceField.validatec                 C   s   |d krd S t |ttttfr"|S |jjd }|jj| }t |tr^|j	}|d krb| 
d n|}||}| }t||}td|jfd|ffS )Nr>  r=  r  r  )r[   r   r   r   r   rX   rB  r   r   r@  rb   r   rC  r  )rN   r  rE  r>  rD  rF  refrY   rY   rZ   r     s"    


zGenericReferenceField.to_mongoc                 C   s   |d krd S |  |S rf   r   r   rY   rY   rZ   rr     s    z)GenericReferenceField.prepare_query_value)ru   rv   rw   rx   rU   r`  r   r:  r   re   r   rr   ry   rY   rY   rW   rZ   r;     s   	
r;   c                       sJ   e Zd ZdZd fdd	Z fddZdd Zd	d
 Z fddZ  Z	S )r<   zA binary data field.Nc                    s   || _ t jf | d S rf   )	max_bytesrT   rU   )rN   rc  rV   rW   rY   rZ   rU     s    zBinaryField.__init__c                    s    t |trt|}t ||S )zHandle bytearrays in python 3.1)r[   	bytearraybytesrT   r   r   rW   rY   rZ   r     s    
zBinaryField.__set__c                 C   s   t |S rf   )r   r_   rY   rY   rZ   r   #  s    zBinaryField.to_mongoc                 C   sJ   t |ttfs$| dtjtjf  | jd k	rFt|| jkrF| d d S )Nz6BinaryField only accepts instances of (%s, %s, Binary)zBinary value is too long)r[   re  r   rb   ru   rc  rc   r_   rY   rY   rZ   re   &  s    
zBinaryField.validatec                    s    |d kr|S t  || |S rf   r   r   rW   rY   rZ   rr   0  s    zBinaryField.prepare_query_value)N)
ru   rv   rw   rx   rU   r   r   re   rr   ry   rY   rY   rW   rZ   r<     s   
r<   c                       sX   e Zd ZdZ fddZ fddZ fddZ fdd	Zd
d Z fddZ	  Z
S )rI   a  Enumeration Field. Values are stored underneath as is,
    so it will only work with simple types (str, int, etc) that
    are bson encodable

    Example usage:

    .. code-block:: python

        class Status(Enum):
            NEW = 'new'
            ONGOING = 'ongoing'
            DONE = 'done'

        class ModelWithEnum(Document):
            status = EnumField(Status, default=Status.NEW)

        ModelWithEnum(status='done')
        ModelWithEnum(status=Status.DONE)

    Enum fields can be searched using enum or its value:

    .. code-block:: python

        ModelWithEnum.objects(status='new').count()
        ModelWithEnum.objects(status=Status.NEW).count()

    The values can be restricted to a subset of the enum by using the ``choices`` parameter:

    .. code-block:: python

        class ModelWithEnum(Document):
            status = EnumField(Status, choices=[Status.NEW, Status.DONE])
    c                    sh   || _ |drHg }|d D ]}t||s|| q|rVtd| nt| j |d< t jf | d S )Nr	  zInvalid choices: %r)	_enum_clsr   r[   r^  r   r  rT   rU   )rN   enumrV   Zinvalid_choicesr
  rW   rY   rZ   rU   Y  s    

zEnumField.__init__c                    sV   t || jrt |S z| | W n* tk
rP   | | d| j  Y nX d S )Nz is not a valid )r[   rf  rT   re   r   rb   r_   rW   rY   rZ   re   f  s    zEnumField.validatec                    sB   t  |}t|| js>z| |W S  tk
r<   | Y S X |S rf   )rT   ra   r[   rf  r   r_   rW   rY   rZ   ra   n  s    
zEnumField.to_pythonc                    s   t  || |S rf   )rT   r   ra   r   rW   rY   rZ   r   w  s    zEnumField.__set__c                 C   s   t || jr|jS |S rf   )r[   rf  r`   r_   rY   rY   rZ   r   z  s    zEnumField.to_mongoc                    s    |d kr|S t  || |S rf   r   r   rW   rY   rZ   rr     s    zEnumField.prepare_query_value)ru   rv   rw   rx   rU   re   ra   r   r   rr   ry   rY   rY   rW   rZ   rI   6  s   "	rI   c                   @   s   e Zd ZdS )r=   Nru   rv   rw   rY   rY   rY   rZ   r=     s   r=   c                   @   s   e Zd ZdZdZdddedf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d Zedd Zd1ddZdd Zd d! Zd"d# Zd$d% Zd2d'd(Zd)d* Zd+d, Zd-d. Zd/d0 ZdS )3r>   zFProxy object to handle writing and reading of files to and from GridFSNfsc                 C   s.   || _ || _|| _|| _|| _d | _d | _d S rf   )grid_idr  r   db_aliascollection_namenewfilegridout)rN   rj  r  r   rk  rl  rY   rY   rZ   rU     s    zGridFSProxy.__init__c                 C   s:   d}||kr|  |S |  }t||r2t||S td S )N)_fsrj  r  r   rk  rl  rm  rn  )__getattribute__r   r  getattrAttributeError)rN   r   attrsobjrY   rY   rZ   __getattr__  s    



zGridFSProxy.__getattr__c                 C   s   | S rf   rY   r   rY   rY   rZ   r     s    zGridFSProxy.__get__c                 C   s
   t | jS rf   )r   rj  r  rY   rY   rZ   __bool__  s    zGridFSProxy.__bool__c                 C   s   | j }d |d< |S )Nro  )__dict__)rN   Z	self_dictrY   rY   rZ   __getstate__  s    zGridFSProxy.__getstate__c                 C   s   t  }|j|   |S rf   )r>   rw  rS  rx  )rN   copiedrY   rY   rZ   __copy__  s    zGridFSProxy.__copy__c                 C   s   |   S rf   )rz  )rN   memorY   rY   rZ   __deepcopy__  s    zGridFSProxy.__deepcopy__c                 C   s   d| j j d| j dS )N<: >)rX   ru   rj  r  rY   rY   rZ   __repr__  s    zGridFSProxy.__repr__c                 C   s4   |   }|r|jnd}d| jj d| d| j dS )Nz	<no file>r}  r~  z (z)>)r   filenamerX   ru   rj  )rN   rn  r  rY   rY   rZ   __str__  s    zGridFSProxy.__str__c                 C   s6   t |tr.| j|jko,| j|jko,| j|jkS dS d S )NF)r[   r>   rj  rl  rk  rN   otherrY   rY   rZ   __eq__  s    


zGridFSProxy.__eq__c                 C   s
   | |k S rf   rY   r  rY   rY   rZ   __ne__  s    zGridFSProxy.__ne__c                 C   s"   | j stt| j| j| _ | j S rf   )ro  gridfsZGridFSr   rk  rl  r  rY   rY   rZ   ri    s    zGridFSProxy.fsc                 C   sV   |r
|| _ | j d krd S z"| jd kr4| j| j | _| jW S  tk
rP   Y d S X d S rf   )rj  rn  ri  r   r^   )rN   rj  rY   rY   rZ   r     s    

zGridFSProxy.getc                 K   s&   | j jf || _| jj| _|   d S rf   )ri  new_filerm  rW  rj  _mark_as_changed)rN   rV   rY   rY   rZ   r    s    
zGridFSProxy.new_filec                 K   s,   | j rtd| jj|f|| _ |   d S NzRThis document already has a file. Either delete it or call replace to overwrite it)rj  r=   ri  putr  rN   file_objrV   rY   rY   rZ   r    s    zGridFSProxy.putc                 C   s.   | j r| jstdn|   | j| d S r  )rj  rm  r=   r  write)rN   stringrY   rY   rZ   r    s    zGridFSProxy.writec                 C   s(   | j s|   | j j| _| j | d S rf   )rm  r  rW  rj  
writelines)rN   linesrY   rY   rZ   r    s    
zGridFSProxy.writelinesr   c                 C   s<   |   }|d krd S z||W S  tk
r6   Y dS X d S )N )r   readr^   )rN   sizern  rY   rY   rZ   r    s    zGridFSProxy.readc                 C   s&   | j | j d | _d | _|   d S rf   )ri  deleterj  rn  r  r  rY   rY   rZ   r    s    zGridFSProxy.deletec                 K   s   |    | j|f| d S rf   )r  r  r  rY   rY   rZ   replace  s    zGridFSProxy.replacec                 C   s   | j r| j   d S rf   )rm  closer  rY   rY   rZ   r  !  s    zGridFSProxy.closec                 C   s   | j r| j | j dS )z4Inform the instance that `self.key` has been changedN)r   r  r  r  rY   rY   rZ   r  %  s    zGridFSProxy._mark_as_changed)N)r   )ru   rv   rw   rx   ro  r   rU   ru  r   rv  rx  rz  r|  r  r  r  r  r  ri  r   r  r  r  r  r  r  r  r  r  rY   rY   rY   rZ   r>     s<   



	

r>   c                       s\   e Zd ZdZeZedf fdd	Zdd Zdd Z	dd
dZ
dd Zdd Zdd Z  ZS )r?   zA GridFS storage field.ri  c                    s   t  jf | || _|| _d S rf   )rT   rU   rl  rk  )rN   rk  rl  rV   rW   rY   rZ   rU   0  s    zFileField.__init__c                 C   sZ   |d kr| S |j | j}t|| jsB| j| j|d}||j | j< |jsV| j|_||_|S )Nr  r   )r   r   r   r[   proxy_classget_proxy_objr  r   )rN   r   r   	grid_filerY   rY   rZ   r   7  s    zFileField.__get__c                 C   s   | j }t|drt|tr(t|ttfr|j| j }|r\z|  W n t	k
rZ   Y nX | j
||d|j|< |j| | n
||j|< || d S )Nr  r  )r   r  r[   r>   re  r\   r   r   r  r^   r  r  r  )rN   r   r`   r  r  rY   rY   rZ   r   F  s"    
zFileField.__set__Nc                 C   s.   |d kr| j }|d kr| j}| j||||dS )N)r  r   rk  rl  )rk  rl  r  )rN   r  r   rk  rl  rY   rY   rZ   r  \  s    zFileField.get_proxy_objc                 C   s    t || jr|jd k	r|jS d S rf   )r[   r  rj  r_   rY   rY   rZ   r   i  s    zFileField.to_mongoc                 C   s    |d k	r| j || j| jdS d S )N)rl  rk  )r  rl  rk  r_   rY   rY   rZ   ra   o  s      zFileField.to_pythonc                 C   s:   |j d k	r6t|| js | d t|j ts6| d d S )Nz)FileField only accepts GridFSProxy valueszInvalid GridFSProxy value)rj  r[   r  rb   r   r_   rY   rY   rZ   re   u  s
    

zFileField.validate)NN)ru   rv   rw   rx   r>   r  r   rU   r   r   r  r   ra   re   ry   rY   rY   rW   rZ   r?   +  s    
r?   c                       sh   e Zd ZdZ fddZ fddZdd Zedd	 Zed
d Z	edd Z
dd Zdd Z  ZS )r@   zProxy for ImageFieldc              
      s  | j j| j }t|dr*t|jtr*|j}zt|}|j	}W n. t
k
rl } ztd| W 5 d}~X Y nX |jdp|d}|drt|dtr|dkrd}nd}|jr |jd |jd	 ks|jd
 |jd kr |j}|d rt||d	 |d ft}n||d	 |d ft d}	|jrx|j}|d rXt||d	 |d ft}	n | }	|	|d	 |d ft |	r| |	||}
nd}
|j\}}t }|j|||d |d t j|f||||
d|S )ze
        Insert a image in database
        applying field properties (size, thumbnail_size)
        r   zInvalid image: %sNprogressiveFZJPEGTr   widthr   heightforcer  )r  r  r   thumbnail_id)r   r   r  r  r[   r   r?   r!   openr   r^   r   infor   r   r  r"   ZfitLANCZOS	thumbnailthumbnail_sizecopy_put_thumbnailr   saveseekrT   r  )rN   r  rV   r   imgZ
img_formater  r  r  Zthumb_idwhiorW   rY   rZ   r    sd    





   zImageGridFsProxy.putc                    s*   |   }|r |jr | j|j t  S rf   )r   r  ri  r  rT   )rN   r   rV   outrW   rY   rZ   r    s    
zImageGridFsProxy.deletec                 K   sF   |j \}}t }|j|||d |d | jj|f|||d|S )Nr  r   )r  r  r   )r  r   r  r  ri  r  )rN   r  r   r  rV   r  r  r  rY   rY   rZ   r    s
    

zImageGridFsProxy._put_thumbnailc                 C   s   |   }|r|j|jfS dS )z1
        return a width, height of image
        N)r   r  r  rN   r  rY   rY   rZ   r    s    zImageGridFsProxy.sizec                 C   s   |   }|r|jS dS )zH
        return format of image
        ex: PNG, JPEG, GIF, etc
        N)r   r   r  rY   rY   rZ   r     s    zImageGridFsProxy.formatc                 C   s$   |   }|r |jr | j |jS dS )z]
        return a gridfs.grid_file.GridOut
        representing a thumbnail of Image
        N)r   r  ri  r  rY   rY   rZ   r    s    
zImageGridFsProxy.thumbnailc                 O   s   t dd S NzPlease use "put" method insteadRuntimeErrorrN   r   rV   rY   rY   rZ   r    s    zImageGridFsProxy.writec                 O   s   t dd S r  r  r  rY   rY   rZ   r    s    zImageGridFsProxy.writelines)ru   rv   rw   rx   r  r  r  r  r  r   r  r  r  ry   rY   rY   rW   rZ   r@   }  s   @	

	
	r@   c                   @   s   e Zd ZdS )rA   Nrh  rY   rY   rY   rZ   rA     s   rA   c                       s&   e Zd ZdZeZd fdd	Z  ZS )rB   a   
    A Image File storage field.

    :param size: max size to store images, provided as (width, height, force)
        if larger, it will be automatically resized (ex: size=(800, 600, True))
    :param thumbnail_size: size to generate a thumbnail, provided as (width, height, force)
    Nimagesc           
         sx   t stdd}||d}| D ]:\}}d }	t|ttfrPttj||d d}	t	| ||	 q"t
 jf d|i| d S )NzPIL library was not found)r  r  r  )r  r  )	fillvaluerl  )r!   rA   r  r[   r  r  r   	itertoolszip_longestsetattrrT   rU   )
rN   r  r  rl  rV   Zparams_size
extra_argsZatt_nameZattr`   rW   rY   rZ   rU     s    
zImageField.__init__)NNr  )ru   rv   rw   rx   r@   r  rU   ry   rY   rY   rW   rZ   rB     s        rB   c                       sv   e Zd ZdZdZdZeZd fdd	Zdd Z	d	d
 Z
dd Zdd Z fddZ fddZdd Zdd Z  ZS )rG   a  Provides a sequential counter see:
     https://www.mongodb.com/docs/manual/reference/method/ObjectId/#ObjectIDs-SequenceNumbers

    .. note::

             Although traditional databases often use increasing sequence
             numbers for primary keys. In MongoDB, the preferred approach is to
             use Object IDs instead.  The concept is that in a very large
             cluster of machines, it is easier to create an object ID than have
             global, uniformly increasing sequence numbers.

    :param collection_name:  Name of the counter collection (default 'mongoengine.counters')
    :param sequence_name: Name of the sequence in the collection (default 'ClassName.counter')
    :param value_decorator: Any callable to use as a counter (default int)

    Use any callable as `value_decorator` to transform calculated counter into
    any value suitable for your needs, e.g. string or hexadecimal
    representation of the default integer counter value.

    .. note::

        In case the counter is defined in the abstract document, it will be
        common to all inherited documents and the default sequence name will
        be the class name of the abstract document.
    Tzmongoengine.countersNc                    sB   |p| j | _|pt| _|| _t|r(|n| j| _t j	|| d S rf   )
COLLECTION_NAMErl  r   rk  sequence_namer   VALUE_DECORATORvalue_decoratorrT   rU   )rN   rl  rk  r  r  r   rV   rW   rY   rZ   rU   5  s    	
zSequenceField.__init__c                 C   sX   |   }| d| j }t| jd| j }|jd|idddiitjdd}| |d S )	z4
        Generate and Increment the counter
        r   aliasrW  z$incnextr   TfilterrS  Zreturn_documentZupsert	get_sequence_namer   r   rk  rl  Zfind_one_and_updater   ZAFTERr  )rN   r  sequence_idrF  counterrY   rY   rZ   generateF  s    
zSequenceField.generatec                 C   sX   |   }| d| j }t| jd| j }|jd|idd|iitjdd}| |d S )z,Helper method to set the next sequence valuer   r  rW  z$setr  Tr  r  )rN   r`   r  r  rF  r  rY   rY   rZ   set_next_valueV  s    
zSequenceField.set_next_valuec                 C   sX   |   }| d| j }t| jd| j }|d|i}|rN| |d d S | dS )zHelper method to get the next value for previewing.

        .. warning:: There is no guarantee this will be the next value
        as it is only fixed on set.
        r   r  rW  r  r   )r  r   r   rk  rl  Zfind_oner  )rN   r  r  rF  r   rY   rY   rZ   get_next_valuec  s    zSequenceField.get_next_valuec                 C   sT   | j r| j S | j}t|tr0|jds0| S ddd |jD 	d
 S d S )Nr?  r  c                 s   s"   | ]}|  rd | n|V  qdS )z_%sN)isupper)r   crY   rY   rZ   r   {  s     z2SequenceField.get_sequence_name.<locals>.<genexpr>_)r  r   r   r   rB  r   rC  r   r  r   r   )rN   r   rY   rY   rZ   r  s  s    zSequenceField.get_sequence_namec                    s@   t  ||}|d kr<|jr<|  }||j| j< || j |S rf   )rT   r   _initialisedr  r   r   r  rN   r   r   r`   rW   rY   rZ   r     s    zSequenceField.__get__c                    s$   |d kr|j r|  }t ||S rf   )r  r  rT   r   r   rW   rY   rZ   r     s    zSequenceField.__set__c                 C   s
   |  |S )a  
        This method is overridden in order to convert the query value into to required
        type. We need to do this in order to be able to successfully compare query
        values passed as string, the base implementation returns the value as is.
        )r  r   rY   rY   rZ   rr     s    z!SequenceField.prepare_query_valuec                 C   s   |d kr|   }|S rf   )r  r_   rY   rY   rZ   ra     s    zSequenceField.to_python)NNNN)ru   rv   rw   rx   Z	_auto_genr  r   r  rU   r  r  r  r  r   r   rr   ra   ry   rY   rY   rW   rZ   rG     s"       	rG   c                       sF   e Zd ZdZdZd fdd	Zdd Zdd	 Zd
d Zdd Z	  Z
S )rH   zA UUID field.NTc                    s   || _ t jf | dS )ze
        Store UUID data in the database

        :param binary: if False store as a string.
        N)_binaryrT   rU   )rN   binaryrV   rW   rY   rZ   rU     s    zUUIDField.__init__c              
   C   sL   | j sH|}zt|tst|}t|W S  tttfk
rF   | Y S X |S rf   )r  r[   r\   uuidUUIDr   r   rr  r   rY   rY   rZ   ra     s    

zUUIDField.to_pythonc                 C   s&   | j st|S t|tr"t|S |S rf   )r  r\   r[   r  r  r_   rY   rY   rZ   r     s
    

zUUIDField.to_mongoc                 C   s   |d krd S |  |S rf   rb  r   rY   rY   rZ   rr     s    zUUIDField.prepare_query_valuec              
   C   sh   t |tjsdt |tst|}zt| W n6 tttfk
rb } z| d|  W 5 d }~X Y nX d S )NzCould not convert to UUID: %s)r[   r  r  r\   r   r   rr  rb   r   rY   rY   rZ   re     s    
zUUIDField.validate)T)ru   rv   rw   rx   r  rU   ra   r   rr   re   ry   rY   rY   rW   rZ   rH     s   	rH   c                   @   s   e Zd ZdZejZdd ZdS )rC   aQ  A list storing a longitude and latitude coordinate.

    .. note:: this represents a generic point in a 2D plane and a legacy way of
        representing a geo point. It admits 2d indexes but not "2dsphere" indexes
        in MongoDB > 2.4 which are more natural for modeling geospatial points.
        See :ref:`geospatial-indexes`
    c                 C   sr   t |ttfs| d t|dks8| dt|  n6t |d ttfr\t |d ttfsn| dt|  dS )z,Make sure that a geo-value is of type (x, y)z7GeoPointField can only accept tuples or lists of (x, y)r   z*Value (%s) must be a two-dimensional pointr   r   z.Both values (%s) in point must be float or intN)r[   r  r  rb   rc   reprr   r   r_   rY   rY   rZ   re     s    
 zGeoPointField.validateN)ru   rv   rw   rx   pymongoZGEO2DZ
_geo_indexre   rY   rY   rY   rZ   rC     s   rC   c                   @   s   e Zd ZdZdZdS )rD   a/  A GeoJSON field storing a longitude and latitude coordinate.

    The data is represented as:

    .. code-block:: js

        {'type' : 'Point' ,
         'coordinates' : [x, y]}

    You can either pass a dict with the full information or a list
    to set the value.

    Requires mongodb >= 2.4
    ZPointNru   rv   rw   rx   _typerY   rY   rY   rZ   rD     s   rD   c                   @   s   e Zd ZdZdZdS )rE   aM  A GeoJSON field storing a line of longitude and latitude coordinates.

    The data is represented as:

    .. code-block:: js

        {'type' : 'LineString' ,
         'coordinates' : [[x1, y1], [x2, y2] ... [xn, yn]]}

    You can either pass a dict with the full information or a list of points.

    Requires mongodb >= 2.4
    Z
LineStringNr  rY   rY   rY   rZ   rE     s   rE   c                   @   s   e Zd ZdZdZdS )rF   a  A GeoJSON field storing a polygon of longitude and latitude coordinates.

    The data is represented as:

    .. code-block:: js

        {'type' : 'Polygon' ,
         'coordinates' : [[[x1, y1], [x1, y1] ... [xn, yn]],
                          [[x1, y1], [x1, y1] ... [xn, yn]]}

    You can either pass a dict with the full information or a list
    of LineStrings. The first LineString being the outside and the rest being
    holes.

    Requires mongodb >= 2.4
    ZPolygonNr  rY   rY   rY   rZ   rF   		  s   rF   c                   @   s   e Zd ZdZdZdS )rJ   a/  A GeoJSON field storing a list of Points.

    The data is represented as:

    .. code-block:: js

        {'type' : 'MultiPoint' ,
         'coordinates' : [[x1, y1], [x2, y2]]}

    You can either pass a dict with the full information or a list
    to set the value.

    Requires mongodb >= 2.6
    Z
MultiPointNr  rY   rY   rY   rZ   rJ   	  s   rJ   c                   @   s   e Zd ZdZdZdS )rK   az  A GeoJSON field storing a list of LineStrings.

    The data is represented as:

    .. code-block:: js

        {'type' : 'MultiLineString' ,
         'coordinates' : [[[x1, y1], [x1, y1] ... [xn, yn]],
                          [[x1, y1], [x1, y1] ... [xn, yn]]]}

    You can either pass a dict with the full information or a list of points.

    Requires mongodb >= 2.6
    ZMultiLineStringNr  rY   rY   rY   rZ   rK   1	  s   rK   c                   @   s   e Zd ZdZdZdS )rL   a  A GeoJSON field storing  list of Polygons.

    The data is represented as:

    .. code-block:: js

        {'type' : 'MultiPolygon' ,
         'coordinates' : [[
               [[x1, y1], [x1, y1] ... [xn, yn]],
               [[x1, y1], [x1, y1] ... [xn, yn]]
           ], [
               [[x1, y1], [x1, y1] ... [xn, yn]],
               [[x1, y1], [x1, y1] ... [xn, yn]]
           ]
        }

    You can either pass a dict with the full information or a list
    of Polygons.

    Requires mongodb >= 2.6
    ZMultiPolygonNr  rY   rY   rY   rZ   rL   D	  s   rL   c                       st   e Zd ZdZddef fdd	Zedd Zdd Z fd	d
Z	dd Z
dd Zdd Z fddZdd Z  ZS )r9   aZ  A really lazy reference to a document.
    Unlike the :class:`~mongoengine.fields.ReferenceField` it will
    **not** be automatically (lazily) dereferenced on access.
    Instead, access will return a :class:`~mongoengine.base.LazyReference` class
    instance, allowing access to `pk` or manual dereference by using
    ``fetch()`` method.
    Fc                    sH   t |tst|ts| d || _|| _|| _|| _t	 j
f | dS )aV  Initialises the Reference Field.

        :param dbref:  Store the reference as :class:`~pymongo.dbref.DBRef`
          or as the :class:`~pymongo.objectid.ObjectId`.id .
        :param reverse_delete_rule: Determines what to do when the referring
          object is deleted
        :param passthrough: When trying to access unknown fields, the
          :class:`~mongoengine.base.datastructure.LazyReference` instance will
          automatically call `fetch()` and try to retrieve the field on the fetched
          document. Note this only work getting field (not setting or deleting).
        zOArgument to LazyReferenceField constructor must be a document class or a stringN)r[   r\   r   r   rb   r4  passthroughr   r5  rT   rU   )rN   r   r  r4  r5  rV   rW   rY   rZ   rU   g	  s     zLazyReferenceField.__init__c                 C   s2   t | jtr,| jtkr | j| _nt| j| _| jS rf   r6  r  rY   rY   rZ   r   	  s
    

z LazyReferenceField.document_typec                 C   s   t |tr,|j| jkrt|j|j| jd}n\|d k	rt || jrVt| j|j| jd}n2t |trvt| j|j| jd}nt| j|| jd}|S )Nr  )r[   r   r  r   rA  r   r@  r_   rY   rY   rZ   r  	  s4    
    
    z LazyReferenceField.build_lazyrefc                    s>   |dkr| S |  |j| j}|r0||j| j< t ||S )r;  Nr  r   r   r   rT   r   r  rW   rY   rZ   r   	  s    zLazyReferenceField.__get__c                 C   s|   t |tr|j}n*t || jr&|j}nt |tr8|j}n|}| jjd }| jj| }||}| j	rtt| j
 |S |S d S )Nr>  )r[   r   rA  r   r   r@  rB  r   r   r4  rC  )rN   r`   rA  rE  r>  rY   rY   rZ   r   	  s    


zLazyReferenceField.to_mongoc                 C   s<   t |tttfs8| j }t|| jj|}| |}|S rG  )	r[   r   r   r   r   rC  r@  ra   r  rH  rY   rY   rZ   ra   	  s
    

zLazyReferenceField.to_pythonc              
   C   s   t |tr2|j| j kr*| d| j  |j}nt || jrF|j}nt |trz| j }|j|krr| d|  |j}n\| jj	d }t
| j|}|}z|| W n0 tk
r   | d| jjt|j Y nX |d kr| d d S )Nz%Reference must be on a `%s` document.z)DBRef on bad collection (must be on `%s`)r>  zcvalue should be `{0}` document, LazyReference or DBRef on `{0}` or `{0}`'s primary key (i.e. `{1}`)r=  )r[   r   rF  r   rC  rb   rA  r   r@  rB  rq  re   r   r   ru   r_  )rN   r`   rA  rF  rE  r>  rY   rY   rZ   re   	  s6    



 
zLazyReferenceField.validatec                    s$   |d krd S t  || | |S rf   r   r   rW   rY   rZ   rr   	  s    z&LazyReferenceField.prepare_query_valuec                 C   s   | j j|S rf   rI  rg   rY   rY   rZ   ri   	  s    z LazyReferenceField.lookup_member)ru   rv   rw   rx   r   rU   r  r   r  r   r   ra   re   rr   ri   ry   rY   rY   rW   rZ   r9   ^	  s   "
"r9   c                       sX   e Zd ZdZ fddZ fddZdd Z fdd	Z fd
dZ fddZ	  Z
S )r:   a  A reference to *any* :class:`~mongoengine.document.Document` subclass.
    Unlike the :class:`~mongoengine.fields.GenericReferenceField` it will
    **not** be automatically (lazily) dereferenced on access.
    Instead, access will return a :class:`~mongoengine.base.LazyReference` class
    instance, allowing access to `pk` or manual dereference by using
    ``fetch()`` method.

    .. note ::
        * Any documents used as a generic reference must be registered in the
          document registry.  Importing the model will automatically register
          it.

        * You can use the choices param to limit the acceptable Document types
    c                    s    | dd| _t j|| d S )Nr  F)r,  r  rT   rU   r  rW   rY   rZ   rU   

  s    z"GenericLazyReferenceField.__init__c                    s"   t |tr|jj}t | d S rf   )r[   r   r   r  rT   r`  r_   rW   rY   rZ   r`  
  s    
z+GenericLazyReferenceField._validate_choicesc                 C   s   t |tr,|j| jkrt|j|j| jd}nV|d k	rt |ttfrbtt|d |d j| jd}n t |t	rtt
||j| jd}|S )Nr  r  r  )r[   r   r  r   rA  r   r   r   r@  r   r_  r_   rY   rY   rZ   r  
  s*    
  

  z'GenericLazyReferenceField.build_lazyrefc                    s>   |d kr| S |  |j| j}|r0||j| j< t ||S rf   r  r  rW   rY   rZ   r   &
  s    z!GenericLazyReferenceField.__get__c                    s*   t |tr|jd kr| d t |S )Nr=  )r[   r   rA  rb   rT   re   r_   rW   rY   rZ   re   0
  s
    z"GenericLazyReferenceField.validatec                    sL   |d krd S t |tr<td|jjfdt|j |jffS t 	|S d S r  )
r[   r   r   r   r  r   rC  rA  rT   r   )rN   r  rW   rY   rZ   r   8
  s    

 z"GenericLazyReferenceField.to_mongo)ru   rv   rw   rx   rU   r`  r  r   re   r   ry   rY   rY   rW   rZ   r:   	  s   
r:   c                       sL   e Zd ZdZe Zd fdd	Zdd Zdd Zd	d
 Z	 fddZ
  ZS )rM   a%  
    128-bit decimal-based floating-point field capable of emulating decimal
    rounding with exact precision. This field will expose decimal.Decimal but stores the value as a
    `bson.Decimal128` behind the scene, this field is intended for monetary data, scientific computations, etc.
    Nc                    s   || _ || _t jf | d S rf   r   r   rW   rY   rZ   rU   U
  s    zDecimal128Field.__init__c              	   C   sP   |d krd S t |tr|S t |tjsHt| j}||}W 5 Q R X t|S rf   )r[   r	   r   r   localcontextDECIMAL_CONTEXTcreate_decimal)rN   r`   ctxrY   rY   rZ   r   Z
  s    
zDecimal128Field.to_mongoc                 C   s   |d krd S |  | S rf   )r   
to_decimalr_   rY   rY   rZ   ra   d
  s    zDecimal128Field.to_pythonc              
   C   s   t |tsPzt|}W n8 tttjfk
rN } z| d|  W 5 d }~X Y nX | jd k	rr| | jk rr| d | j	d k	r| | j	kr| d d S )Nz)Could not convert value to Decimal128: %sr   r   )
r[   r	   r   r   r   r   rb   r   r  r   r   rY   rY   rZ   re   i
  s    
 
zDecimal128Field.validatec                    s   t  || |S rf   r   r   rW   rY   rZ   rr   v
  s    z#Decimal128Field.prepare_query_value)NN)ru   rv   rw   rx   r
   r  rU   r   ra   re   rr   ry   rY   rY   rW   rZ   rM   L
  s   
rM   )nr   r   rJ  r  rO   r   r   r  r   r  r   operatorr   r  r  Zbsonr   r   r   r   Zbson.decimal128r	   r
   Z
bson.int64r   r   r   ImportErrorZdateutil.parserZmongoengine.baser   r   r   r   r   r   r   Zmongoengine.base.utilsr   Zmongoengine.commonr   Zmongoengine.connectionr   r   Zmongoengine.documentr   r   Zmongoengine.errorsr   r   r   Zmongoengine.querysetr   Zmongoengine.queryset.baser   Zmongoengine.queryset.transformr    ZPILr!   r"   r  r#   r  __all__r   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r4   r3   r/  r1  r5   r6   r7   r8   r;   r<   rI   r^   r=   r>   r?   r@   rA   rB   rG   rH   rC   rD   rE   rF   rJ   rK   rL   r9   r:   rM   rY   rY   rY   rZ   <module>   s   
$	


/G$m&*YP^T5=@		6 2 &t O #Rx / R