o
    "hY                     @   s`  d Z ddlZddlmZ ddlmZ ddlmZmZm	Z	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 dd	lmZmZ dd
lmZ ddlmZmZmZmZmZm Z  dZ!dZ"e
dedZ#de$e# de%e$e#  fddZ&de$e# de'de#fddZ(de#de)ee)e$e# e'f f fddZ*G dd dej+Z,G dd dej-Z.G dd deeeef Z/dS )z1This module contains the PicklePersistence class.    N)deepcopy)Path)AnyCallableOptionalTypeVarUnioncastoverload)BotTelegramObject)FilePathInput)warn)BasePersistencePersistenceInput)ContextTypes)BDCDUDCDCDataConversationDictConversationKeyz/a known bot replaced by PTB's PicklePersistencez2an unknown bot replaced by PTB's PicklePersistenceTelegramObj)boundclsreturnc                 C   s    |   }t|dd |D S )zsGets all subclasses of the specified object, recursively. from
    https://stackoverflow.com/a/3862957/9706202
    c                 S   s   g | ]}t |D ]}|qqS  )_all_subclasses).0csr   r   R/var/www/html/venv/lib/python3.10/site-packages/telegram/ext/_picklepersistence.py
<listcomp>+   s    z#_all_subclasses.<locals>.<listcomp>)__subclasses__setunion)r   
subclassesr   r   r!   r   &   s   r   kwargsc                 C   s   |  | }|| |S )a  
    This method is used for unpickling. The data, which is in the form a dictionary, is
    converted back into a class. Works mostly the same as :meth:`TelegramObject.__setstate__`.
    This function should be kept in place for backwards compatibility even if the pickling logic
    is changed, since `_custom_reduction` places references to this function into the pickled data.
    )__new____setstate__)r   r'   objr   r   r!   _reconstruct_to.   s   

r+   c                 C   s*   | j dd}t|d |d< t| j|ffS )z
    This method is used for pickling. The bot attribute is preserved so _BotPickler().persistent_id
    works as intended.
    T)include_private
api_kwargs)
_get_attrsdictr+   	__class__)r   datar   r   r!   _custom_reduction:   s   r2   c                       sj   e Zd ZdZdededef fddZdedee	ee
e ef f fd	d
Zdedee fddZ  ZS )_BotPickler_botbotargsr'   c                       || _ t j|i | d S Nr5   super__init__selfr6   r7   r'   r0   r   r!   r<   I      z_BotPickler.__init__r*   r   c                 C   s   t |tstS t|S )z
        This method is used for pickling. The bot attribute is preserved so
        _BotPickler().persistent_id works as intended.
        )
isinstancer   NotImplementedr2   r>   r*   r   r   r!   reducer_overrideM   s   
z_BotPickler.reducer_overridec                 C   s,   || j u rtS t|trtddd tS dS )zUsed to 'mark' the Bot, so it can be replaced later. See
        https://docs.python.org/3/library/pickle.html#pickle.Pickler.persistent_id for more info
        zHUnknown bot instance found. Will be replaced by `None` during unpickling   )
stacklevelN)r5   _REPLACED_KNOWN_BOTrA   r   r   _REPLACED_UNKNOWN_BOTrC   r   r   r!   persistent_idY   s   

z_BotPickler.persistent_id)__name__
__module____qualname__	__slots__r   r   r<   r   tupler   typer/   rD   objectr   strrI   __classcell__r   r   r?   r!   r3   F   s    
r3   c                       sD   e Zd ZdZdededef fddZdedee fd	d
Z	  Z
S )_BotUnpicklerr4   r6   r7   r'   c                    r8   r9   r:   r=   r?   r   r!   r<   k   r@   z_BotUnpickler.__init__pidr   c                 C   s$   |t kr| jS |tkrdS td)zSReplaces the bot with the current bot if known, else it is replaced by :obj:`None`.Nz,Found unknown persistent id when unpickling!)rG   r5   rH   pickleUnpicklingError)r>   rT   r   r   r!   persistent_loado   s
   
z_BotUnpickler.persistent_load)rJ   rK   rL   rM   r   r   r<   rQ   r   rW   rR   r   r   r?   r!   rS   h   s    rS   c                       sP  e Zd ZdZdZe				dFddd	ed
ee de	de	de
fddZe					dGddd	ed
ee de	de	de
deeeeeef  fddZ					dGd	ed
ee de	de	de
deeeeeef  f fddZdHddZd	edefddZdHddZd	ededdfddZdeeef fddZdeeef fd d!Zdefd"d#Zdee fd$d%Zd&edefd'd(Z d&ed)e!d*ee ddfd+d,Z"d-ededdfd.d/Z#d0ededdfd1d2Z$deddfd3d4Z%deddfd5d6Z&d0eddfd7d8Z'd-eddfd9d:Z(d-ed;eddfd<d=Z)d0ed>eddfd?d@Z*dAeddfdBdCZ+dHdDdEZ,  Z-S )IPicklePersistenceaq  Using python's builtin :mod:`pickle` 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:
        This implementation of :class:`BasePersistence` uses the functionality of the pickle module
        to support serialization of bot instances. Specifically any reference to
        :attr:`~BasePersistence.bot` will be replaced by a placeholder before pickling and
        :attr:`~BasePersistence.bot` will be inserted back when loading the data.

    Examples:
        :any:`Persistent Conversation Bot <examples.persistentconversationbot>`

    .. 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`.
        * The parameter and attribute ``filename`` were replaced by :attr:`filepath`.
        * :attr:`filepath` now also accepts :obj:`pathlib.Path` as argument.

    Args:
        filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files.
            When :attr:`single_file` is :obj:`False` this will be used as a prefix.
        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.
        single_file (:obj:`bool`, optional): When :obj:`False` will store 5 separate files of
            `filename_user_data`, `filename_bot_data`, `filename_chat_data`,
            `filename_callback_data` and `filename_conversations`. Default is :obj:`True`.
        on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when
            :meth:`flush` is called and keep data in memory until that happens. When
            :obj:`False` will store data on any transaction *and* on call to :meth:`flush`.
            Default is :obj:`False`.
        context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance
            of :class:`telegram.ext.ContextTypes` to customize the types used in the
            ``context`` interface. If not passed, the defaults documented in
            :class:`telegram.ext.ContextTypes` will be used.

            .. 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:
        filepath (:obj:`str` | :obj:`pathlib.Path`): The filepath for storing the pickle files.
            When :attr:`single_file` is :obj:`False` this will be used as a prefix.
        store_data (:class:`~telegram.ext.PersistenceInput`): Specifies which kinds of data will
            be saved by this persistence instance.
        single_file (:obj:`bool`): Optional. When :obj:`False` will store 5 separate files of
            `filename_user_data`, `filename_bot_data`, `filename_chat_data`,
            `filename_callback_data` and `filename_conversations`. Default is :obj:`True`.
        on_flush (:obj:`bool`): Optional. When :obj:`True` will only save to file when
            :meth:`flush` is called and keep data in memory until that happens. When
            :obj:`False` will store data on any transaction *and* on call to :meth:`flush`.
            Default is :obj:`False`.
        context_types (:class:`telegram.ext.ContextTypes`): Container for the types used
            in the ``context`` interface.

            .. versionadded:: 13.6
    )	bot_datacallback_data	chat_datacontext_typesconversationsfilepathon_flushsingle_file	user_dataNTF<   r>   zAPicklePersistence[dict[Any, Any], dict[Any, Any], dict[Any, Any]]r^   
store_datar`   r_   update_intervalc                 C      d S r9   r   )r>   r^   rc   r`   r_   rd   r   r   r!   r<      s   zPicklePersistence.__init__zPicklePersistence[UD, CD, BD]r\   c                 C   re   r9   r   r>   r^   rc   r`   r_   rd   r\   r   r   r!   r<      s   	c                    sZ   t  j||d t|| _|| _|| _d | _d | _d | _d | _	d | _
td|p(t | _d S )N)rc   rd   zContextTypes[Any, UD, CD, BD])r;   r<   r   r^   r`   r_   ra   r[   rY   rZ   r]   r	   r   r\   rf   r?   r   r!   r<      s   	


r   c              
   C   s  zA| j d}t| j| }W d    n1 sw   Y  |d | _|d | _|d| j	 | _	|di | _
|d | _W d S  ty]   i | _i | _i | _| j	 | _	d | _
Y d S  tjyv } z| j j}td| d|d }~w ty } z
td	| j j |d }~ww )
Nrbra   r[   rY   rZ   r]   File # does not contain valid pickle data Something went wrong unpickling )r^   openrS   r6   loadra   r[   getr\   rY   rZ   r]   OSErrorrU   rV   name	TypeError	Exception)r>   filer1   excfilenamer   r   r!   _load_singlefile   s.   

z"PicklePersistence._load_singlefilec              
   C   s   z!| d}t| j| W  d    W S 1 sw   Y  W d S  ty+   Y d S  tjyA } z
td|j d|d }~w t	yU } z	td|j |d }~ww )Nrg   rh   ri   rj   )
rk   rS   r6   rl   rn   rU   rV   rp   ro   rq   )r>   r^   rr   rs   r   r   r!   
_load_file
  s   (zPicklePersistence._load_filec                 C   sd   | j | j| j| j| jd}| jd}t| j|t	j
d| W d    d S 1 s+w   Y  d S )N)r]   ra   r[   rY   rZ   wbprotocol)r]   ra   r[   rY   rZ   r^   rk   r3   r6   rU   HIGHEST_PROTOCOLdump)r>   r1   rr   r   r   r!   _dump_singlefile  s   "z"PicklePersistence._dump_singlefiler1   c                 C   sH   | d}t| j|tjd| W d    d S 1 sw   Y  d S )Nrw   rx   )rk   r3   r6   rU   rz   r{   )r>   r^   r1   rr   r   r   r!   
_dump_file!  s   "zPicklePersistence._dump_filec                    H   | j rn| js| t| j d}|si }|| _ n|   t| j S )zReturns the user_data from the pickle file if it exists or an empty :obj:`dict`.

        Returns:
            dict[:obj:`int`, :obj:`dict`]: The restored user data.
        
_user_data)ra   r`   rv   r   r^   ru   r   r>   r1   r   r   r!   get_user_data%     
zPicklePersistence.get_user_datac                    r~   )zReturns the chat_data from the pickle file if it exists or an empty :obj:`dict`.

        Returns:
            dict[:obj:`int`, :obj:`dict`]: The restored chat data.
        
_chat_data)r[   r`   rv   r   r^   ru   r   r   r   r   r!   get_chat_data6  r   zPicklePersistence.get_chat_datac                    sN   | j rn| js| t| j d}|s| j  }|| _ n|   t| j S )a  Returns the bot_data from the pickle file if it exists or an empty object of type
        :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`.

        Returns:
            :obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`: The restored bot data.
        	_bot_data)rY   r`   rv   r   r^   r\   ru   r   r   r   r   r!   get_bot_dataG  s   

zPicklePersistence.get_bot_datac                    sV   | j rn| js| t| j d}|sd}|| _ n|   | j du r&dS t| j S )ad  Returns the callback data from the pickle file if it exists or :obj:`None`.

        .. versionadded:: 13.6

        Returns:
            tuple[list[tuple[:obj:`str`, :obj:`float`, dict[:obj:`str`, :class:`object`]]],
            dict[:obj:`str`, :obj:`str`]] | :obj:`None`: The restored metadata or :obj:`None`,
            if no data was stored.
        _callback_dataN)rZ   r`   rv   r   r^   ru   r   r   r   r   r!   get_callback_dataY  s   


z#PicklePersistence.get_callback_dataro   c                    sT   | j rn| js| t| j d}|s|i i}|| _ n|   | j |i  S )zReturns the conversations from the pickle file if it exists or an empty dict.

        Args:
            name (:obj:`str`): The handlers name.

        Returns:
            :obj:`dict`: The restored conversations for the handler.
        _conversations)r]   r`   rv   r   r^   ru   rm   copy)r>   ro   r1   r   r   r!   get_conversationsp  s   	z#PicklePersistence.get_conversationskey	new_statec                    sr   | j si | _ | j |i ||krdS || j | |< | js7| js1| t| j d| j  dS |   dS dS )aJ  Will update the conversations for the given handler and depending on :attr:`on_flush`
        save the pickle file.

        Args:
            name (:obj:`str`): The handler's name.
            key (:obj:`tuple`): The key the state is changed for.
            new_state (:class:`object`): The new state for the given key.
        Nr   )	r]   
setdefaultrm   r_   r`   r}   r   r^   r|   )r>   ro   r   r   r   r   r!   update_conversation  s   z%PicklePersistence.update_conversationuser_idc                    j   | j du r	i | _ | j ||krdS || j |< | js3| js-| t| j d| j  dS |   dS dS )a  Will update the user_data and depending on :attr:`on_flush` save the pickle file.

        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]``.
        Nr   )ra   rm   r_   r`   r}   r   r^   r|   )r>   r   r1   r   r   r!   update_user_data     

z"PicklePersistence.update_user_datachat_idc                    r   )a  Will update the chat_data and depending on :attr:`on_flush` save the pickle file.

        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]``.
        Nr   )r[   rm   r_   r`   r}   r   r^   r|   )r>   r   r1   r   r   r!   update_chat_data  r   z"PicklePersistence.update_chat_datac                    P   | j |krdS || _ | js&| js | t| j d| j  dS |   dS dS )zWill update the bot_data and depending on :attr:`on_flush` save the pickle file.

        Args:
            data (:obj:`dict` | :attr:`telegram.ext.ContextTypes.bot_data`): The
                :attr:`telegram.ext.Application.bot_data`.
        Nr   )rY   r_   r`   r}   r   r^   r|   r   r   r   r!   update_bot_data  s   
z!PicklePersistence.update_bot_datac                    r   )a  Will update the callback_data (if changed) and depending on :attr:`on_flush` save the
        pickle file.

        .. 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`.
        Nr   )rZ   r_   r`   r}   r   r^   r|   r   r   r   r!   update_callback_data  s   
z&PicklePersistence.update_callback_datac                    X   | j du rdS | j |d | js*| js$| t| j d| j  dS |   dS dS )zWill delete the specified key from the ``chat_data`` and depending on
        :attr:`on_flush` save the pickle file.

        .. versionadded:: 20.0

        Args:
            chat_id (:obj:`int`): The chat id to delete from the persistence.
        Nr   )r[   popr_   r`   r}   r   r^   r|   )r>   r   r   r   r!   drop_chat_data     
	z PicklePersistence.drop_chat_datac                    r   )zWill delete the specified key from the ``user_data`` and depending on
        :attr:`on_flush` save the pickle file.

        .. versionadded:: 20.0

        Args:
            user_id (:obj:`int`): The user id to delete from the persistence.
        Nr   )ra   r   r_   r`   r}   r   r^   r|   )r>   r   r   r   r!   drop_user_data  r   z PicklePersistence.drop_user_datara   c                       dS )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data`
        Nr   )r>   r   ra   r   r   r!   refresh_user_data      z#PicklePersistence.refresh_user_datar[   c                    r   )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data`
        Nr   )r>   r   r[   r   r   r!   refresh_chat_data  r   z#PicklePersistence.refresh_chat_datarY   c                    r   )zDoes nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data`
        Nr   )r>   rY   r   r   r!   refresh_bot_data  r   z"PicklePersistence.refresh_bot_datac                    s   | j r| js| js| js| js| jr|   dS dS | jr+| t| j	 d| j | jr;| t| j	 d| j | jrK| t| j	 d| j | jr[| t| j	 d| j | jrm| t| j	 d| j dS dS )z/Will save all data in memory to pickle file(s).r   r   r   r   r   N)
r`   ra   r[   rY   rZ   r]   r|   r}   r   r^   )r>   r   r   r!   flush  s2   	zPicklePersistence.flush)NTFrb   )NTFrb   N)r   N).rJ   rK   rL   __doc__rM   r
   r   r   r   boolfloatr<   r   r   r   r   r   ru   r   rv   r|   rP   r}   r/   intr   r   r   r   r   rQ   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rR   r   r   r?   r!   rX   x   s    C	


rX   )0r   rU   r   r   pathlibr   typingr   r   r   r   r   r	   r
   telegramr   r   telegram._utils.typesr   telegram._utils.warningsr   telegram.extr   r   telegram.ext._contexttypesr   telegram.ext._utils.typesr   r   r   r   r   r   rG   rH   r   rO   r$   r   r/   r+   rN   r2   Picklerr3   	UnpicklerrS   rX   r   r   r   r!   <module>   s(   $ &"