U
    .eC                     @   s   d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ zdd	lZdd
lmZ W n ek
r   d	 ZZY nX dZeddZeeZG dd deZd	S )z"AWS DynamoDB result store backend.    )
namedtuple)sleeptime)
_parse_url)ImproperlyConfigured)
get_logger   )KeyValueStoreBackendN)ClientError)DynamoDBBackendDynamoDBAttributename	data_typec                       s  e Zd ZdZdZdZdZdZdZdZ	dZ
edddZed	d
dZedddZedddZdZd3 fdd	Zd4ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zd5d!d"Zd#d$ Zd%d& Zd'd( Zed)d* Zd+d, Z d-d. Z!d/d0 Z"d1d2 Z#  Z$S )6r   zAWS DynamoDB result backend.

    Raises:
        celery.exceptions.ImproperlyConfigured:
            if module :pypi:`boto3` is not available.
    Zceleryr   NTidSr   resultB	timestampNttlc              
      s  t  j|| || _|p| j| _ts,tdd}d }d }|d k	rlt|\}}	}
}}}}|}|}|d k	}|d k	}||krtd|}|	dkrd|
 | _d| _t	
d| j n|	| _| jjj}|d}|r|| _t|d	| j| _t|d
| j| _|d| j}|r^zt|| _W n> tk
r\ } zt	jd| d|d |W 5 d }~X Y nX |ph| j| _| j| j| jf| _d | _|r| j||d d S )NzBYou need to install the boto3 library to use the DynamoDB backend.Fz6You need to specify both the Access Key ID and Secret.	localhostzhttp://localhost:z	us-east-1z*Using local-only DynamoDB endpoint URL: {}Zdynamodb_endpoint_urlreadwriteZttl_secondszTTL must be a number; got "")exc_info)access_key_idsecret_access_key)super__init__url
table_nameboto3r   	parse_urlendpoint_url
aws_regionloggerwarningformatZappconfgetintread_capacity_unitswrite_capacity_unitstime_to_live_seconds
ValueErrorerror
_key_field_value_field_timestamp_field_available_fields_client_get_client)selfr    r!   argskwargsZaws_credentials_givenaws_access_key_idaws_secret_access_keyschemeZregionportusernamepasswordtablequeryZaccess_key_givenZsecret_key_given_getZconfig_endpoint_urlr   e	__class__ </tmp/pip-unpacked-wheel-f4liivr4/celery/backends/dynamodb.pyr   >   s    


zDynamoDBBackend.__init__c                 C   sx   | j dkrrd| ji}|dk	r,|||d | jdk	r@| j|d< tjd|| _ |   |  dk	rr|   | 	  | j S )zGet client connection.NZregion_name)r:   r;   r$   dynamodb)rH   )
r5   r%   updater$   r"   client_get_or_create_table_has_ttl_validate_ttl_methods_set_table_ttl)r7   r   r   Zclient_parametersrF   rF   rG   r6      s*    
 

 zDynamoDBBackend._get_clientc                 C   s6   | j j| j jdg| j| j jddg| j| jddS )z=Get the boto3 structure describing the DynamoDB table schema.)AttributeNameZAttributeTypeHASH)rO   ZKeyType)ZReadCapacityUnitsZWriteCapacityUnits)ZAttributeDefinitions	TableNameZ	KeySchemaZProvisionedThroughput)r1   r   r   r!   r,   r-   r7   rF   rF   rG   _get_table_schema   s    z!DynamoDBBackend._get_table_schemac              
   C   s   |   }z| jj| jdW S  tk
r } zj|jd dd}|dkr| jjf |}t	d
| j | d t	d
| j | W Y 
S |W 5 d	}~X Y nX d	S )
z=Create table if not exists, otherwise return the description.rQ   ErrorCodeUnknownZResourceNotFoundExceptionz*DynamoDB Table {} did not exist, creating.ACTIVEz#DynamoDB Table {} is now available.N)rS   r5   describe_tabler!   r
   responser*   Zcreate_tabler&   infor(   _wait_for_table_status)r7   Ztable_schemarC   
error_codetable_descriptionrF   rF   rG   rK      s(    
z$DynamoDBBackend._get_or_create_tablec                 C   s   | j dkrdS | j dkS )zReturn the desired Time to Live config.

        - True:  Enable TTL on the table; use expiry.
        - False: Disable TTL on the table; don't use expiry.
        - None:  Ignore TTL on the table; don't use expiry.
        Nr   )r.   rR   rF   rF   rG   rL      s    zDynamoDBBackend._has_ttlc                 C   sb   d}g }t |D ]}t| j|s|| q|r^tdjd|d tdjd|ddS )z:Verify boto support for the DynamoDB Time to Live methods.)update_time_to_livedescribe_time_to_livezdboto3 method(s) {methods} not found; ensure that boto3>=1.9.178 and botocore>=1.12.178 are installed,)methodsz#boto3 method(s) {methods} not foundN)	listhasattrr5   appendr&   r0   r(   joinAttributeError)r7   Zrequired_methodsZmissing_methodsmethodrF   rF   rG   rM      s"    z%DynamoDBBackend._validate_ttl_methodsc                 C   s   | j |  |ddS )zBGet the boto3 structure describing the DynamoDB TTL specification.)ZEnabledrO   )rQ   ZTimeToLiveSpecification)r!   rL   )r7   ttl_attr_namerF   rF   rG   _get_ttl_specification	  s
    z&DynamoDBBackend._get_ttl_specificationc              
   C   s|   z| j j| jd}W nb tk
rv } zD|jd dd}|jd dd}tdj| j||d |W 5 d }~X Y nX |S )NrT   rU   rV   rW   MessagezJError describing Time to Live on DynamoDB table {table}: {code}: {message})r@   codemessage)	r5   r`   r!   r
   rZ   r*   r&   r0   r(   )r7   descriptionrC   r]   error_messagerF   rF   rG   _get_table_ttl_description  s     
z*DynamoDBBackend._get_table_ttl_descriptionc           	      C   s|  |   }|d d }|dkrd|d d }|  r|| jjkrtdj|dkrPdnd| jd	 |S nN|d
kr|  stdj|dkrdnd| jd	 |S ntdj|| jd |dkr|n| jj}z<| j	j
f | j|d}tdj| j|  | jjd |W S  tk
rv } zT|jd dd}|jd dd}tdj|  rPdnd| j||d |W 5 d}~X Y nX dS )z,Enable or disable Time to Live on the table.ZTimeToLiveDescriptionZTimeToLiveStatus)ENABLEDZENABLINGrO   z5DynamoDB Time to Live is {situation} on table {table}rq   zalready enabledzcurrently being enabled)Z	situationr@   )DISABLEDZ	DISABLINGrr   zalready disabledzcurrently being disabledzWUnknown DynamoDB Time to Live status {status} on table {table}. Attempting to continue.)statusr@   )ri   zUDynamoDB table Time to Live updated: table={table} enabled={enabled} attribute={attr})r@   enabledattrrU   rV   rW   rk   zHError {action} Time to Live on DynamoDB table {table}: {code}: {message}ZenablingZ	disabling)actionr@   rl   rm   N)rp   rL   
_ttl_fieldr   r&   debugr(   r!   r'   r5   r_   rj   r[   r
   rZ   r*   r0   )	r7   rn   rs   Zcur_attr_name	attr_namespecificationrC   r]   ro   rF   rF   rG   rN   (  s|    
		&
	zDynamoDBBackend._set_table_ttlrX   c                 C   sN   d}|sJ| j j| jd}td| j| |d d }||k}td qdS )z#Poll for the expected table status.FrT   z+Waiting for DynamoDB table {} to become {}.ZTableZTableStatusr   N)rJ   rY   r!   r&   rx   r(   r   )r7   expectedZachieved_stater^   Zcurrent_statusrF   rF   rG   r\     s    z&DynamoDBBackend._wait_for_table_statusc                 C   s   | j | jj| jj|iidS )z0Construct the item retrieval request parameters.)rQ   ZKey)r!   r1   r   r   )r7   keyrF   rF   rG   _prepare_get_request  s     z$DynamoDBBackend._prepare_get_requestc              	   C   s~   t  }| j| jj| jj|i| jj| jj|i| jj| jjt|iid}|  rz|d 	| j
j| j
jtt|| j ii |S )z/Construct the item creation request parameters.)rQ   Itemr~   )r   r!   r1   r   r   r2   r3   strrL   rI   rw   r+   r.   )r7   r|   valuer   Zput_requestrF   rF   rG   _prepare_put_request  s0       z$DynamoDBBackend._prepare_put_requestc                    s    d kri S  fdd| j D S )z1Convert get_item() response to field-value pairs.r~   c                    s$   i | ]}|j  d  |j  |j qS )r~   r   ).0fieldraw_responserF   rG   
<dictcomp>  s    z1DynamoDBBackend._item_to_dict.<locals>.<dictcomp>)r4   )r7   r   rF   r   rG   _item_to_dict  s
    
zDynamoDBBackend._item_to_dictc                 C   s   |   S N)r6   rR   rF   rF   rG   rJ     s    zDynamoDBBackend.clientc                 C   s8   t |}| |}| jjf |}| |}|| jjS r   )r   r}   rJ   Zget_itemr   r*   r2   r   )r7   r|   request_parametersZitem_responseitemrF   rF   rG   r*     s
    

zDynamoDBBackend.getc                 C   s&   t |}| ||}| jjf | d S r   )r   r   rJ   Zput_item)r7   r|   r   r   rF   rF   rG   set  s    zDynamoDBBackend.setc                    s    fdd|D S )Nc                    s   g | ]}  |qS rF   )r*   )r   r|   rR   rF   rG   
<listcomp>  s     z(DynamoDBBackend.mget.<locals>.<listcomp>rF   )r7   keysrF   rR   rG   mget  s    zDynamoDBBackend.mgetc                 C   s$   t |}| |}| jjf | d S r   )r   r}   rJ   Zdelete_item)r7   r|   r   rF   rF   rG   delete  s    
zDynamoDBBackend.delete)NN)NN)rX   )%__name__
__module____qualname____doc__r!   r,   r-   r%   r$   r.   Zsupports_autoexpirer   r1   r2   r3   rw   r4   r   r6   rS   rK   rL   rM   rj   rp   rN   r\   r}   r   r   propertyrJ   r*   r   r   r   __classcell__rF   rF   rD   rG   r      s@   Y


p
	
r   )r   collectionsr   r   r   Zkombu.utils.urlr   r#   Zcelery.exceptionsr   Zcelery.utils.logr   baser	   r"   Zbotocore.exceptionsr
   ImportError__all__r   r   r&   r   rF   rF   rF   rG   <module>   s   
