U
    gJ                  	   @   s   d Z ddlZddlmZ ddlmZmZmZmZm	Z	 ddl
mZmZ ddlmZmZmZ erhddlmZ G dd	 d	eeeef eeef eeef f ZdS )
z/This module contains the DictPersistence class.    N)deepcopy)TYPE_CHECKINGAnyDictOptionalcast)BasePersistencePersistenceInput)CDCDataConversationDictConversationKey)JSONDictc                	       s  e Zd ZdZdZdPee eeeeeed fddZ	e
eeeeeef f  d	d
dZe
ed	ddZe
eeeeeef f  d	ddZe
ed	ddZe
eeeef  d	ddZe
ed	ddZe
ee d	ddZe
ed	ddZe
eeeef  d	ddZe
ed	ddZeeeeef f d	ddZeeeeef f d	d d!Zeeef d	d"d#Zee d	d$d%Zeed&d'd(Zee ee dd)d*d+Z!eeeef dd,d-d.Z"eeeef dd/d0d1Z#eeef dd2d3d4Z$edd2d5d6Z%edd7d8d9Z&edd:d;d<Z'eeeef dd=d>d?Z(eeeef dd@dAdBZ)eeef ddCdDdEZ*dd	dFdGZ+e,eeef edHdIdJZ-e,eeeef dKdLdMZ.e,eeeeeef f d2dNdOZ/  Z0S )QDictPersistenceay
  Using Python's :obj:`dict` and :mod:`json` for making your bot persistent.

    Attention:
        The interface provided by this class is intended to be accessed exclusively by
        :class:`~telegram.ext.Application`. Calling any of the methods below manually might
        interfere with the integration of persistence into :class:`~telegram.ext.Application`.

    Note:
        * Data managed by :class:`DictPersistence` is in-memory only and will be lost when the bot
          shuts down. This is, because :class:`DictPersistence` is mainly intended as starting
          point for custom persistence classes that need to JSON-serialize the stored data before
          writing them to file/database.

        * This implementation of :class:`BasePersistence` does not handle data that cannot be
          serialized by :func:`json.dumps`.

    .. seealso:: :wiki:`Making Your Bot Persistent <Making-your-bot-persistent>`

    .. versionchanged:: 20.0
        The parameters and attributes ``store_*_data`` were replaced by :attr:`store_data`.

    Args:
        store_data (:class:`~telegram.ext.PersistenceInput`, optional): Specifies which kinds of
            data will be saved by this persistence instance. By default, all available kinds of
            data will be saved.
        user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
            user_data on creating this persistence. Default is ``""``.
        chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
            chat_data on creating this persistence. Default is ``""``.
        bot_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
            bot_data on creating this persistence. Default is ``""``.
        conversations_json (:obj:`str`, optional): JSON string that will be used to reconstruct
            conversation on creating this persistence. Default is ``""``.
        callback_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct
            callback_data on creating this persistence. Default is ``""``.

            .. versionadded:: 13.6
        update_interval (:obj:`int` | :obj:`float`, optional): The
            :class:`~telegram.ext.Application` will update
            the persistence in regular intervals. This parameter specifies the time (in seconds) to
            wait between two consecutive runs of updating the persistence. Defaults to 60 seconds.

            .. versionadded:: 20.0
    Attributes:
        store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will
            be saved by this persistence instance.
    )
	_bot_data_bot_data_json_callback_data_callback_data_json
_chat_data_chat_data_json_conversations_conversations_json
_user_data_user_data_jsonN <   )
store_datauser_data_jsonchat_data_jsonbot_data_jsonconversations_jsoncallback_data_jsonupdate_intervalc           
   
      s  t  j||d d | _d | _d | _d | _d | _d | _d | _d | _	d | _
d | _|rz| || _|| _W n0 ttfk
r } ztd|W 5 d }~X Y nX |rz| || _|| _W n0 ttfk
r } ztd|W 5 d }~X Y nX |rJzt|| _|| _	W n2 ttfk
r2 } ztd|W 5 d }~X Y nX t| jtsJtd|rDzt|}	W n2 ttfk
r } ztd|W 5 d }~X Y nX z>|	d krd | _n"ttdd |	d	 D |	d
 f| _|| _
W n2 ttfk
r } ztd|W 5 d }~X Y nX | jd k	rDtdd | jd	 D r<t| jd
 tsDtd|rz| || _|| _W n2 ttfk
r } ztd|W 5 d }~X Y nX d S )N)r   r!   z4Unable to deserialize user_data_json. Not valid JSONz4Unable to deserialize chat_data_json. Not valid JSONz3Unable to deserialize bot_data_json. Not valid JSONz%bot_data_json must be serialized dictz8Unable to deserialize callback_data_json. Not valid JSONc                 S   s    g | ]\}}}|t ||fqS  )float).0ZoneZtwoZthreer"   r"   A/tmp/pip-unpacked-wheel-swnnwir2/telegram/ext/_dictpersistence.py
<listcomp>   s     z,DictPersistence.__init__.<locals>.<listcomp>r      z0callback_data_json is not in the required formatc                 s   s*   | ]"}t |d  to t |d tV  qdS )   r   N)
isinstancedictstr)r$   entryr"   r"   r%   	<genexpr>   s   z+DictPersistence.__init__.<locals>.<genexpr>z8Unable to deserialize conversations_json. Not valid JSON)super__init__r   r   r   r   r   r   r   r   r   r    _decode_user_chat_data_from_json
ValueErrorAttributeError	TypeErrorjsonloadsr)   r*   r   r
   
IndexErrorall_decode_conversations_from_json)
selfr   r   r   r   r   r    r!   excdata	__class__r"   r%   r/   ]   s    






zDictPersistence.__init__)returnc                 C   s   | j S )z%:obj:`dict`: The user_data as a dict.)r   r9   r"   r"   r%   	user_data   s    zDictPersistence.user_datac                 C   s   | j r| j S t| jS )z6:obj:`str`: The user_data serialized as a JSON-string.)r   r4   dumpsr@   r?   r"   r"   r%   r      s    zDictPersistence.user_data_jsonc                 C   s   | j S )z%:obj:`dict`: The chat_data as a dict.)r   r?   r"   r"   r%   	chat_data   s    zDictPersistence.chat_datac                 C   s   | j r| j S t| jS )z6:obj:`str`: The chat_data serialized as a JSON-string.)r   r4   rA   rB   r?   r"   r"   r%   r      s    zDictPersistence.chat_data_jsonc                 C   s   | j S )z$:obj:`dict`: The bot_data as a dict.)r   r?   r"   r"   r%   bot_data   s    zDictPersistence.bot_datac                 C   s   | j r| j S t| jS )z5:obj:`str`: The bot_data serialized as a JSON-string.)r   r4   rA   rC   r?   r"   r"   r%   r      s    zDictPersistence.bot_data_jsonc                 C   s   | j S )zTuple[List[Tuple[:obj:`str`, :obj:`float`, Dict[:obj:`str`, :class:`object`]]],         Dict[:obj:`str`, :obj:`str`]]: The metadata on the stored callback data.

        .. versionadded:: 13.6
        )r   r?   r"   r"   r%   callback_data   s    zDictPersistence.callback_datac                 C   s   | j r| j S t| jS )zo:obj:`str`: The metadata on the stored callback data as a JSON-string.

        .. versionadded:: 13.6
        )r   r4   rA   rD   r?   r"   r"   r%   r       s    z"DictPersistence.callback_data_jsonc                 C   s   | j S )z):obj:`dict`: The conversations as a dict.)r   r?   r"   r"   r%   conversations   s    zDictPersistence.conversationsc                 C   s*   | j r| j S | jr| | jS t| jS )z::obj:`str`: The conversations serialized as a JSON-string.)r   rE   _encode_conversations_to_jsonr4   rA   r?   r"   r"   r%   r      s
    z"DictPersistence.conversations_jsonc                    s   | j dkri | _t| j S )zReturns the user_data created from the ``user_data_json`` or an empty :obj:`dict`.

        Returns:
            :obj:`dict`: The restored user data.
        N)r@   r   r   r?   r"   r"   r%   get_user_data   s    
zDictPersistence.get_user_datac                    s   | j dkri | _t| j S )zReturns the chat_data created from the ``chat_data_json`` or an empty :obj:`dict`.

        Returns:
            :obj:`dict`: The restored chat data.
        N)rB   r   r   r?   r"   r"   r%   get_chat_data   s    
zDictPersistence.get_chat_datac                    s   | j dkri | _t| j S )zReturns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`.

        Returns:
            :obj:`dict`: The restored bot data.
        N)rC   r   r   r?   r"   r"   r%   get_bot_data  s    
zDictPersistence.get_bot_datac                    s   | j dkrd| _dS t| j S )ad  Returns the callback_data created from the ``callback_data_json`` or :obj:`None`.

        .. versionadded:: 13.6

        Returns:
            Tuple[List[Tuple[:obj:`str`, :obj:`float`, Dict[:obj:`str`, :class:`object`]]],                 Dict[:obj:`str`, :obj:`str`]]: The restored metadata or :obj:`None`,                 if no data was stored.
        N)rD   r   r   r?   r"   r"   r%   get_callback_data  s    

z!DictPersistence.get_callback_data)namer>   c                    s"   | j dkri | _| j |i  S )zReturns the conversations created from the ``conversations_json`` or an empty
        :obj:`dict`.

        Returns:
            :obj:`dict`: The restored conversations data.
        N)rE   r   getcopy)r9   rK   r"   r"   r%   get_conversations  s    
z!DictPersistence.get_conversations)rK   key	new_stater>   c                    s@   | j si | _ | j |i ||kr(dS || j | |< d| _dS )a  Will update the conversations for the given handler.

        Args:
            name (:obj:`str`): The handler's name.
            key (:obj:`tuple`): The key the state is changed for.
            new_state (:obj:`tuple` | :class:`object`): The new state for the given key.
        N)r   
setdefaultrL   r   )r9   rK   rO   rP   r"   r"   r%   update_conversation)  s    
z#DictPersistence.update_conversation)user_idr;   r>   c                    s8   | j dkri | _ | j ||kr$dS || j |< d| _dS )zWill update the user_data (if changed).

        Args:
            user_id (:obj:`int`): The user the data might have been changed for.
            data (:obj:`dict`): The :attr:`telegram.ext.Application.user_data` ``[user_id]``.
        N)r   rL   r   )r9   rS   r;   r"   r"   r%   update_user_data:  s    

z DictPersistence.update_user_data)chat_idr;   r>   c                    s8   | j dkri | _ | j ||kr$dS || j |< d| _dS )zWill update the chat_data (if changed).

        Args:
            chat_id (:obj:`int`): The chat the data might have been changed for.
            data (:obj:`dict`): The :attr:`telegram.ext.Application.chat_data` ``[chat_id]``.
        N)r   rL   r   )r9   rU   r;   r"   r"   r%   update_chat_dataH  s    

z DictPersistence.update_chat_data)r;   r>   c                    s   | j |krdS || _ d| _dS )zWill update the bot_data (if changed).

        Args:
            data (:obj:`dict`): The :attr:`telegram.ext.Application.bot_data`.
        N)r   r   r9   r;   r"   r"   r%   update_bot_dataV  s    
zDictPersistence.update_bot_datac                    s   | j |krdS || _ d| _dS )aK  Will update the callback_data (if changed).

        .. versionadded:: 13.6

        Args:
            data (Tuple[List[Tuple[:obj:`str`, :obj:`float`, Dict[:obj:`str`, :class:`object`]]],                 Dict[:obj:`str`, :obj:`str`]]): The relevant data to restore
                :class:`telegram.ext.CallbackDataCache`.
        N)r   r   rW   r"   r"   r%   update_callback_dataa  s    

z$DictPersistence.update_callback_data)rU   r>   c                    s&   | j dkrdS | j |d d| _dS )zWill delete the specified key from the :attr:`chat_data`.

        .. versionadded:: 20.0

        Args:
            chat_id (:obj:`int`): The chat id to delete from the persistence.
        N)r   popr   )r9   rU   r"   r"   r%   drop_chat_datap  s    
zDictPersistence.drop_chat_data)rS   r>   c                    s&   | j dkrdS | j |d d| _dS )zWill delete the specified key from the :attr:`user_data`.

        .. versionadded:: 20.0

        Args:
            user_id (:obj:`int`): The user id to delete from the persistence.
        N)r   rZ   r   )r9   rS   r"   r"   r%   drop_user_data}  s    
zDictPersistence.drop_user_data)rS   r@   r>   c                    s   dS )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data`
        Nr"   )r9   rS   r@   r"   r"   r%   refresh_user_data  s    z!DictPersistence.refresh_user_data)rU   rB   r>   c                    s   dS )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data`
        Nr"   )r9   rU   rB   r"   r"   r%   refresh_chat_data  s    z!DictPersistence.refresh_chat_data)rC   r>   c                    s   dS )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data`
        Nr"   )r9   rC   r"   r"   r%   refresh_bot_data  s    z DictPersistence.refresh_bot_datac                    s   dS )zvDoes nothing.

        .. versionadded:: 20.0
        .. seealso:: :meth:`telegram.ext.BasePersistence.flush`
        Nr"   r?   r"   r"   r%   flush  s    zDictPersistence.flush)rE   r>   c                 C   sL   i }|   D ]4\}}i ||< |  D ]\}}||| t|< q$qt|S )af  Helper method to encode a conversations dict (that uses tuples as keys) to a
        JSON-serializable way. Use :meth:`self._decode_conversations_from_json` to decode.

        Args:
            conversations (:obj:`dict`): The conversations dict to transform to JSON.

        Returns:
            :obj:`str`: The JSON-serialized conversations dict
        )itemsr4   rA   )rE   tmphandlerstatesrO   stater"   r"   r%   rF     s    z-DictPersistence._encode_conversations_to_json)json_stringr>   c                 C   sT   t | }i }| D ]8\}}i ||< | D ]\}}||| tt |< q.q|S )aQ  Helper method to decode a conversations dict (that uses tuples as keys) from a
        JSON-string created with :meth:`self._encode_conversations_to_json`.

        Args:
            json_string (:obj:`str`): The conversations dict as JSON string.

        Returns:
            :obj:`dict`: The conversations dict after decoding
        )r4   r5   ra   tuple)rf   rb   rE   rc   rd   rO   re   r"   r"   r%   r8     s    
z/DictPersistence._decode_conversations_from_jsonc           	   
   C   sx   i }t | }| D ]\\}}t|}i ||< | D ]:\}}zt|}W n tk
rb   |}Y nX ||| |< q6q|S )a  Helper method to decode chat or user data (that uses ints as keys) from a
        JSON-string.

        Args:
            data (:obj:`str`): The user/chat_data dict as JSON string.

        Returns:
            :obj:`dict`: The user/chat_data defaultdict after decoding
        )r4   r5   ra   intr1   )	r;   rb   decoded_datauserr@   Zint_user_idrO   valueZ_idr"   r"   r%   r0     s    

z0DictPersistence._decode_user_chat_data_from_json)Nr   r   r   r   r   r   )1__name__
__module____qualname____doc__	__slots__r   r	   r+   r#   r/   propertyr   rh   r   r@   r   rB   r   rC   r   r
   rD   r    r   rE   r   objectrG   rH   rI   rJ   rN   r   rR   rT   rV   rX   rY   r[   r\   r]   r^   r_   r`   staticmethodrF   r8   r0   __classcell__r"   r"   r<   r%   r      s   0       O$$	


  r   )ro   r4   rM   r   typingr   r   r   r   r   Ztelegram.extr   r	   Ztelegram.ext._utils.typesr
   r   r   Ztelegram._utils.typesr   r   r"   r"   r"   r%   <module>   s   