o
    Zzj]Y  ã                   @   s`  d Z ddlZddlmZ ddlmZ ddlm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 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)ÚCallable)Údeepcopy)ÚPath)ÚAnyÚTypeVarÚ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   úZ/var/www/kodo/tsheker/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_to0   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   r0   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dB fdd„Z‡  ZS )Ú_BotPickler©Ú_botÚbotÚargsr%   c                    ó   || _ tƒ j|i |¤Ž d S ©N©r3   ÚsuperÚ__init__©Úselfr4   r5   r%   ©r.   r   r   r:   K   ó   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
   ÚNotImplementedr0   ©r<   r(   r   r   r   Úreducer_overrideO   s   
z_BotPickler.reducer_overrideNc                 C   s,   || j u rtS t|tƒrtddd� tS dS )z¢Used 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)r3   Ú_REPLACED_KNOWN_BOTr?   r	   r   Ú_REPLACED_UNKNOWN_BOTrA   r   r   r   Úpersistent_id[   s   

þz_BotPickler.persistent_id)Ú__name__Ú
__module__Ú__qualname__Ú	__slots__r	   r   r:   r   Útupler   Útyper-   rB   ÚobjectÚstrrG   Ú__classcell__r   r   r=   r   r1   H   s    ÿ
þr1   c                       sD   e Zd ZdZdededef‡ fdd„Zdeded	B fd
d„Z‡  Z	S )Ú_BotUnpicklerr2   r4   r5   r%   c                    r6   r7   r8   r;   r=   r   r   r:   m   r>   z_BotUnpickler.__init__Úpidr   Nc                 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!)rE   r3   rF   ÚpickleÚUnpicklingError)r<   rR   r   r   r   Úpersistent_loadq   s
   
z_BotUnpickler.persistent_load)
rH   rI   rJ   rK   r	   r   r:   rO   rU   rP   r   r   r=   r   rQ   j   s    rQ   c                       sP  e Zd ZdZdZe				dFddd	ed
edB dedede	fdd„ƒZ
e					dGddd	ed
edB dedede	deeeeef dB fdd„ƒZ
					dGd	ed
edB dedede	deeeeef dB 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dB fd$d%„Zd&edefd'd(„Zd&ed)e d*edB 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 r7   r   )r<   r\   ra   r^   r]   rb   r   r   r   r:   Ê   s   zPicklePersistence.__init__zPicklePersistence[UD, CD, BD]rZ   c                 C   rc   r7   r   ©r<   r\   ra   r^   r]   rb   rZ   r   r   r   r:   Ô   s   	c                    sZ   t ƒ j||d� t|ƒ| _|| _|| _d | _d | _d | _d | _	d | _
td|p(tƒ ƒ| _d S )N)ra   rb   zContextTypes[Any, UD, CD, BD])r9   r:   r   r\   r^   r]   r_   rY   rW   rX   r[   r   r   rZ   rd   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Úrbr_   rY   rW   rX   r[   úFile ú# does not contain valid pickle dataú Something went wrong unpickling )r\   ÚopenrQ   r4   Úloadr_   rY   ÚgetrZ   rW   rX   r[   ÚOSErrorrS   rT   ÚnameÚ	TypeErrorÚ	Exception)r<   Úfiler/   Ú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 )Nre   rf   rg   rh   )
ri   rQ   r4   rj   rl   rS   rT   rn   rm   ro   )r<   r\   rp   rq   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[   r_   rY   rW   rX   Úwb©Úprotocol)r[   r_   rY   rW   rX   r\   ri   r1   r4   rS   ÚHIGHEST_PROTOCOLÚdump)r<   r/   rp   r   r   r   Ú_dump_singlefile  s   û"ÿz"PicklePersistence._dump_singlefiler/   c                 C   sH   |  d¡�}t| j|tjd� |¡ W d   ƒ d S 1 sw   Y  d S )Nru   rv   )ri   r1   r4   rS   rx   ry   )r<   r\   r/   rp   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 )z®Returns 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)r_   r^   rt   r   r\   rs   r   ©r<   r/   r   r   r   Úget_user_data'  ó   €
zPicklePersistence.get_user_datac                 Ã   r|   )z®Returns 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)rY   r^   rt   r   r\   rs   r   r~   r   r   r   Úget_chat_data8  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)rW   r^   rt   r   r\   rZ   rs   r   r~   r   r   r   Úget_bot_dataI  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)rX   r^   rt   r   r\   rs   r   r~   r   r   r   Úget_callback_data[  s   €


z#PicklePersistence.get_callback_datarm   c                 Ã   sT   �| j rn| js|  t| j› d�ƒ¡}|s|i i}|| _ n|  ¡  | j  |i ¡ ¡ S )zîReturns 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^   rt   r   r\   rs   rk   Úcopy)r<   rm   r/   r   r   r   Úget_conversationsr  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[   Ú
setdefaultrk   r]   r^   r{   r   r\   rz   )r<   rm   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}   )r_   rk   r]   r^   r{   r   r\   rz   )r<   rŽ   r/   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�   )rY   rk   r]   r^   r{   r   r\   rz   )r<   r’   r/   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 )zôWill 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ƒ   )rW   r]   r^   r{   r   r\   rz   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…   )rX   r]   r^   r{   r   r\   rz   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 )zúWill 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�   )rY   Úpopr]   r^   r{   r   r\   rz   )r<   r’   r   r   r   Údrop_chat_dataä  ó   €
	üz PicklePersistence.drop_chat_datac                 Ã   r—   )zúWill 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}   )r_   r˜   r]   r^   r{   r   r\   rz   )r<   rŽ   r   r   r   Údrop_user_data÷  rš   z PicklePersistence.drop_user_datar_   c                 Ã   ó   �dS )z‚Does nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data`
        Nr   )r<   rŽ   r_   r   r   r   Úrefresh_user_data
  ó    z#PicklePersistence.refresh_user_datarY   c                 Ã   rœ   )z‚Does nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data`
        Nr   )r<   r’   rY   r   r   r   Úrefresh_chat_data  rž   z#PicklePersistence.refresh_chat_datarW   c                 Ã   rœ   )z�Does nothing.

        .. versionadded:: 13.6
        .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data`
        Nr   )r<   rW   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^   r_   rY   rW   rX   r[   rz   r{   r   r\   )r<   r   r   r   Úflush  s2   €ÿþýüûù	ÿzPicklePersistence.flush)NTFr`   )NTFr`   N)r   N)-rH   rI   rJ   Ú__doc__rK   r   r   r   ÚboolÚfloatr:   r   r   r   r   r   rs   r   rt   rz   rN   r{   r-   Úintr   r‚   r„   r   r†   rO   r   r‰   r   r�   r�   r“   r•   r–   r™   r›   r�   rŸ   r    r¡   rP   r   r   r=   r   rV   z   s°    Cúÿþýüûú	ùÿþýüûúùùþýüûúù

ÿÿÿ
þrV   )/r¢   rS   Úcollections.abcr   rˆ   r   Úpathlibr   Útypingr   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   rE   rF   r   rM   r"   r   r-   r)   rL   r0   ÚPicklerr1   Ú	UnpicklerrQ   rV   r   r   r   r   Ú<module>   s*    &"