U
    g                     @   s*  d Z ddlZddlZddlZddlmZmZmZmZm	Z	m
Z
mZmZ z(ddlZddlmZ ddlmZ dZW n ek
r   dZY nX ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ererddlm Z! ddl"m#Z# e$e%dZ&ee'ddZ(G dd dee Z)G dd dee Z dS )z2This module contains the classes JobQueue and Job.    N)TYPE_CHECKINGAnyGenericOptionalTupleUnioncastoverload)AsyncIOExecutor)AsyncIOSchedulerTF)
get_logger)build_repr_with_selected_attrs)JSONDict)ExtBot)CCTJobCallback)Job)Application   JobQueue)
class_namec                   @   s  e Zd ZdZdZdZddddZeddd	Ze	d
dddZ
e	edddZejdddZed;deddddZed<eeejejejf eejdddZd=eeejejejdf eeej dddZd
ddddZeddddddZd>ee eeejejejf ee ee ee ee ee ddd d!Zd?ee eeejf eeeejejejf  eeeejejejf  ee ee ee ee ee dd"
d#d$Zd@ee ejeee ee ee ee ee dd%	d&d'Z e!dddddfee eje"ed(f ee ee ee ee ee dd)	d*d+Z#dAee eee ee ee ee dd,d-d.Z$ddd/d0Z%dBedd2d3d4Z&e"d5 dd6d7Z'ee"d5 d8d9d:Z(dS )Cr   a  This class allows you to periodically perform tasks with the bot. It is a convenience
    wrapper for the APScheduler library.

    This class is a :class:`~typing.Generic` class and accepts one type variable that specifies
    the type of the argument ``context`` of the job callbacks (:paramref:`~run_once.callback`) of
    :meth:`run_once` and the other scheduling methods.

    Important:
        If you want to use this class, you must install PTB with the optional requirement
        ``job-queue``, i.e.

        .. code-block:: bash

           pip install "python-telegram-bot[job-queue]"

    Examples:
        :any:`Timer Bot <examples.timerbot>`

    .. seealso:: :wiki:`Architecture Overview <Architecture>`,
        :wiki:`Job Queue <Extensions---JobQueue>`

    .. versionchanged:: 20.0
        To use this class, PTB must be installed via
        ``pip install "python-telegram-bot[job-queue]"``.

    Attributes:
        scheduler (:class:`apscheduler.schedulers.asyncio.AsyncIOScheduler`): The scheduler.

            Warning:
                This scheduler is configured by :meth:`set_application`. Additional configuration
                settings can be made by users. However, calling
                :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` will delete any
                previous configuration settings. Therefore, please make sure to pass the values
                returned by :attr:`scheduler_configuration` to the method call in addition to your
                custom values.
                Alternatively, you can also use methods like
                :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
                :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.

            .. versionchanged:: 20.0
                Uses :class:`~apscheduler.schedulers.asyncio.AsyncIOScheduler` instead of
                :class:`~apscheduler.schedulers.background.BackgroundScheduler`

    )_application	_executor	scheduler)sunmontuewedthufrisatNreturnc                 C   s,   t stdd | _t | _tf | j| _d S )Nz\To use `JobQueue`, PTB must be installed via `pip install "python-telegram-bot[job-queue]"`.)APS_AVAILABLERuntimeErrorr   r
   r   r   scheduler_configurationr   self r(   :/tmp/pip-unpacked-wheel-swnnwir2/telegram/ext/_jobqueue.py__init__d   s    zJobQueue.__init__c                 C   s   t | | jdS )a$  Give a string representation of the JobQueue in the form ``JobQueue[application=...]``.

        As this class doesn't implement :meth:`object.__str__`, the default implementation
        will be used, which is equivalent to :meth:`__repr__`.

        Returns:
            :obj:`str`
        )application)r   r+   r&   r(   r(   r)   __repr__q   s    	zJobQueue.__repr__3Application[Any, CCT, Any, Any, Any, JobQueue[CCT]]c                 C   s2   | j dkrtd|   }|dk	r&|S tddS )z1The application this JobQueue is associated with.Nz)No application was set for this JobQueue.z,The application instance is no longer alive.)r   r$   r'   r+   r(   r(   r)   r+   |   s    
zJobQueue.applicationc                 C   sF   t j}| jr6t| jjtr6| jjjr6| jjjjp4t j}|d| j	idS )a_  Provides configuration values that are used by :class:`JobQueue` for :attr:`scheduler`.

        Tip:
            Since calling
            :meth:`scheduler.configure() <apscheduler.schedulers.base.BaseScheduler.configure>`
            deletes any previous setting, please make sure to pass these values to the method call
            in addition to your custom values:

            .. code-block:: python

                scheduler.configure(..., **job_queue.scheduler_configuration)

            Alternatively, you can also use methods like
            :meth:`~apscheduler.schedulers.base.BaseScheduler.add_jobstore` to avoid using
            :meth:`~apscheduler.schedulers.base.BaseScheduler.configure` altogether.

        .. versionadded:: 20.7

        Returns:
            Dict[:obj:`str`, :obj:`object`]: The configuration values as dictionary.

        default)timezoneZ	executors)
pytzutcr   
isinstancer+   Zbotr   defaultstzinfor   )r'   r0   r(   r(   r)   r%      s    z JobQueue.scheduler_configurationc                 C   s   t j | jjS N)datetimenowr   r0   r&   r(   r(   r)   _tz_now   s    zJobQueue._tz_nowF)time	shift_dayr"   c                 C   s   d S r6   r(   r'   r:   r;   r(   r(   r)   _parse_time_input   s    zJobQueue._parse_time_inputc                 C   s   d S r6   r(   r<   r(   r(   r)   r=      s    c                 C   s   |d krd S t |ttfr.|  tj|d S t |tjrF|  | S t |tjrtjtjj|j	pj| j
jd |}|j	d kr| j
j|}|r|tjtjkr|tjdd7 }|S |S )N)seconds)tz   )days)r3   intfloatr9   r7   	timedeltar:   combiner8   r5   r   r0   dateZlocalizer1   r2   )r'   r:   r;   	date_timer(   r(   r)   r=      s"     
r+   r"   c                 C   s    t || _| jjf | j dS )zSet the application to be used by this JobQueue.

        Args:
            application (:class:`telegram.ext.Application`): The application.

        N)weakrefrefr   r   	configurer%   r.   r(   r(   r)   set_application   s    	zJobQueue.set_applicationzJobQueue[CCT]Job[CCT])	job_queuejobr"   c                    s   | | jI dH  dS )a  This method is used as a callback for the APScheduler jobs.

        More precisely, the ``func`` argument of :class:`apscheduler.job.Job` is set to this method
        and the ``arg`` argument (representing positional arguments to ``func``) is set to a tuple
        containing the :class:`JobQueue` itself and the :class:`~telegram.ext.Job` instance.

        Tip:
            This method is a static method rather than a bound method. This makes the arguments
            more transparent and allows for easier handling of PTBs integration of APScheduler
            when utilizing advanced features of APScheduler.

        Hint:
            This method is effectively a wrapper for :meth:`telegram.ext.Job.run`.

        .. versionadded:: 20.4

        Args:
            job_queue (:class:`JobQueue`): The job queue that created the job.
            job (:class:`~telegram.ext.Job`): The job to run.
        N)runr+   )rN   rO   r(   r(   r)   job_callback   s    zJobQueue.job_callback)callbackwhendatanamechat_iduser_id
job_kwargsr"   c                 C   sl   |si }|p|j }t|||||d}| j|dd}	| jj| jf|d|	| |f|	jpV| jjd|}
|
|_|S )a  Creates a new :class:`Job` instance that runs once and adds it to the queue.

        Args:
            callback (:term:`coroutine function`): The callback function that should be executed by
                the new job. Callback signature::

                    async def callback(context: CallbackContext)

            when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` |                                           :obj:`datetime.datetime` | :obj:`datetime.time`):
                Time in or at which the job should run. This parameter will be interpreted
                depending on its type.

                * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the
                  job should run.
                * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the
                  job should run.
                * :obj:`datetime.datetime` will be interpreted as a specific date and time at
                  which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is
                  :obj:`None`, the default timezone of the bot will be used, which is UTC unless
                  :attr:`telegram.ext.Defaults.tzinfo` is used.
                * :obj:`datetime.time` will be interpreted as a specific time of day at which the
                  job should run. This could be either today or, if the time has already passed,
                  tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the
                  default timezone of the bot will be used, which is UTC unless
                  :attr:`telegram.ext.Defaults.tzinfo` is used.

            chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will
                be available in the callback.

                .. versionadded:: 20.0

            user_id (:obj:`int`, optional): User id of the user associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will
                be available in the callback.

                .. versionadded:: 20.0
            data (:obj:`object`, optional): Additional data needed for the callback function.
                Can be accessed through :attr:`Job.data` in the callback. Defaults to
                :obj:`None`.

                .. versionchanged:: 20.0
                    Renamed the parameter ``context`` to :paramref:`data`.
            name (:obj:`str`, optional): The name of the new job. Defaults to
                :external:attr:`callback.__name__ <definition.__name__>`.
            job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the
                :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`.

        Returns:
            :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job
            queue.

        rR   rT   rU   rV   rW   T)r;   rF   )rU   triggerZrun_dateargsr0   )	__name__r   r=   r   add_jobrQ   r5   r0   _job)r'   rR   rS   rT   rU   rV   rW   rX   rO   rG   jr(   r(   r)   run_once   s$    @

zJobQueue.run_once)
rR   intervalfirstlastrT   rU   rV   rW   rX   r"   c
              	   C   s   |	si }	|p|j }t|||||d}
| |}| |}|rP|rP||k rPtdt|tjrd| }| jj	| j
fd| |
f||||d|	}||
_|
S )a~  Creates a new :class:`Job` instance that runs at specified intervals and adds it to the
        queue.

        Note:
            For a note about DST, please see the documentation of `APScheduler`_.

        .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html
                           #daylight-saving-time-behavior

        Args:
            callback (:term:`coroutine function`): The callback function that should be executed by
                the new job. Callback signature::

                    async def callback(context: CallbackContext)

            interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which
                the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted
                as seconds.
            first (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` |                                           :obj:`datetime.datetime` | :obj:`datetime.time`, optional):
                Time in or at which the job should run. This parameter will be interpreted
                depending on its type.

                * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the
                  job should run.
                * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the
                  job should run.
                * :obj:`datetime.datetime` will be interpreted as a specific date and time at
                  which the job should run. If the timezone (:attr:`datetime.datetime.tzinfo`) is
                  :obj:`None`, the default timezone of the bot will be used.
                * :obj:`datetime.time` will be interpreted as a specific time of day at which the
                  job should run. This could be either today or, if the time has already passed,
                  tomorrow. If the timezone (:attr:`datetime.time.tzinfo`) is :obj:`None`, the
                  default timezone of the bot will be used, which is UTC unless
                  :attr:`telegram.ext.Defaults.tzinfo` is used.

                Defaults to :paramref:`interval`

                Note:
                    Setting :paramref:`first` to ``0``, ``datetime.datetime.now()`` or another
                    value that indicates that the job should run immediately will not work due
                    to how the APScheduler library works. If you want to run a job immediately,
                    we recommend to use an approach along the lines of::

                        job = context.job_queue.run_repeating(callback, interval=5)
                        await job.run(context.application)

                    .. seealso:: :meth:`telegram.ext.Job.run`

            last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` |                                           :obj:`datetime.datetime` | :obj:`datetime.time`, optional):
                Latest possible time for the job to run. This parameter will be interpreted
                depending on its type. See :paramref:`first` for details.

                If :paramref:`last` is :obj:`datetime.datetime` or :obj:`datetime.time` type
                and ``last.tzinfo`` is :obj:`None`, the default timezone of the bot will be
                assumed, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.

                Defaults to :obj:`None`.
            data (:obj:`object`, optional): Additional data needed for the callback function.
                Can be accessed through :attr:`Job.data` in the callback. Defaults to
                :obj:`None`.

                .. versionchanged:: 20.0
                    Renamed the parameter ``context`` to :paramref:`data`.
            name (:obj:`str`, optional): The name of the new job. Defaults to
                :external:attr:`callback.__name__ <definition.__name__>`.
            chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will
                be available in the callback.

                .. versionadded:: 20.0

            user_id (:obj:`int`, optional): User id of the user associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will
                be available in the callback.

                .. versionadded:: 20.0
            job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the
                :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`.

        Returns:
            :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job
            queue.

        rY   z"'last' must not be before 'first'!ra   )rZ   r[   Z
start_dateend_dater>   rU   )r\   r   r=   
ValueErrorr3   r7   rD   total_secondsr   r]   rQ   r^   )r'   rR   ra   rb   rc   rT   rU   rV   rW   rX   rO   Zdt_firstZdt_lastr_   r(   r(   r)   run_repeatingF  s0    b


zJobQueue.run_repeating)	rR   rS   dayrT   rU   rV   rW   rX   r"   c	                 C   sv   |si }|p|j }t|||||d}	| jj| jfd| |	f||dkrFdn||j|j|j|jp`| jj	d|}
|
|	_
|	S )a	  Creates a new :class:`Job` that runs on a monthly basis and adds it to the queue.

        .. versionchanged:: 20.0
            The ``day_is_strict`` argument was removed. Instead one can now pass ``-1`` to the
            :paramref:`day` parameter to have the job run on the last day of the month.

        Args:
            callback (:term:`coroutine function`): The callback function that should be executed by
                the new job. Callback signature::

                    async def callback(context: CallbackContext)

            when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
                (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used,
                which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
            day (:obj:`int`): Defines the day of the month whereby the job would run. It should
                be within the range of ``1`` and ``31``, inclusive. If a month has fewer days than
                this number, the job will not run in this month. Passing ``-1`` leads to the job
                running on the last day of the month.
            data (:obj:`object`, optional): Additional data needed for the callback function.
                Can be accessed through :attr:`Job.data` in the callback. Defaults to
                :obj:`None`.

                .. versionchanged:: 20.0
                    Renamed the parameter ``context`` to :paramref:`data`.
            name (:obj:`str`, optional): The name of the new job. Defaults to
                :external:attr:`callback.__name__ <definition.__name__>`.
            chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will
                be available in the callback.

                .. versionadded:: 20.0

            user_id (:obj:`int`, optional): User id of the user associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will
                be available in the callback.

                .. versionadded:: 20.0
            job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the
                :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`.

        Returns:
            :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job
            queue.

        rY   cronrc   )rZ   r[   rU   rh   hourminutesecondr0   )r\   r   r   r]   rQ   rk   rl   rm   r5   r0   r^   )r'   rR   rS   rh   rT   rU   rV   rW   rX   rO   r_   r(   r(   r)   run_monthly  s(    9

zJobQueue.run_monthly.)	rR   r:   rA   rT   rU   rV   rW   rX   r"   c	                    s~   |si }|p|j }t|||||d}	 jj jf| |	fdd fdd|D |j|j|j|j	ph jj
d|}
|
|	_|	S )a	  Creates a new :class:`Job` that runs on a daily basis and adds it to the queue.

        Note:
            For a note about DST, please see the documentation of `APScheduler`_.

        .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html
                           #daylight-saving-time-behavior

        Args:
            callback (:term:`coroutine function`): The callback function that should be executed by
                the new job. Callback signature::

                    async def callback(context: CallbackContext)

            time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone
                (:obj:`datetime.time.tzinfo`) is :obj:`None`, the default timezone of the bot will
                be used, which is UTC unless :attr:`telegram.ext.Defaults.tzinfo` is used.
            days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should
                run (where ``0-6`` correspond to sunday - saturday). By default, the job will run
                every day.

                .. versionchanged:: 20.0
                    Changed day of the week mapping of 0-6 from monday-sunday to sunday-saturday.

            data (:obj:`object`, optional): Additional data needed for the callback function.
                Can be accessed through :attr:`Job.data` in the callback. Defaults to
                :obj:`None`.

                .. versionchanged:: 20.0
                    Renamed the parameter ``context`` to :paramref:`data`.
            name (:obj:`str`, optional): The name of the new job. Defaults to
                :external:attr:`callback.__name__ <definition.__name__>`.
            chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will
                be available in the callback.

                .. versionadded:: 20.0

            user_id (:obj:`int`, optional): User id of the user associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will
                be available in the callback.

                .. versionadded:: 20.0
            job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the
                :meth:`apscheduler.schedulers.base.BaseScheduler.add_job()`.

        Returns:
            :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job
            queue.

        rY   ri   ,c                    s   g | ]} j | qS r(   )_CRON_MAPPING).0dr&   r(   r)   
<listcomp>\  s     z&JobQueue.run_daily.<locals>.<listcomp>)rU   r[   rZ   Zday_of_weekrk   rl   rm   r0   )r\   r   r   r]   rQ   joinrk   rl   rm   r5   r0   r^   )r'   rR   r:   rA   rT   rU   rV   rW   rX   rO   r_   r(   r&   r)   	run_daily  s(    >

zJobQueue.run_daily)rR   rX   rT   rU   rV   rW   r"   c           	      C   sF   |p|j }t|||||d}| jj| jf| |f|d|}||_|S )aL  Creates a new custom defined :class:`Job`.

        Args:
            callback (:term:`coroutine function`): The callback function that should be executed by
                the new job. Callback signature::

                    async def callback(context: CallbackContext)

            job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for
                :meth:`apscheduler.schedulers.base.BaseScheduler.add_job`.
            data (:obj:`object`, optional): Additional data needed for the callback function.
                Can be accessed through :attr:`Job.data` in the callback. Defaults to
                :obj:`None`.

                .. versionchanged:: 20.0
                    Renamed the parameter ``context`` to :paramref:`data`.
            name (:obj:`str`, optional): The name of the new job. Defaults to
                :external:attr:`callback.__name__ <definition.__name__>`.
            chat_id (:obj:`int`, optional): Chat id of the chat associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.chat_data` will
                be available in the callback.

                .. versionadded:: 20.0

            user_id (:obj:`int`, optional): User id of the user associated with this job. If
                passed, the corresponding :attr:`~telegram.ext.CallbackContext.user_data` will
                be available in the callback.

                .. versionadded:: 20.0

        Returns:
            :class:`telegram.ext.Job`: The new :class:`Job` instance that has been added to the job
            queue.

        rY   )r[   rU   )r\   r   r   r]   rQ   r^   )	r'   rR   rX   rT   rU   rV   rW   rO   r_   r(   r(   r)   
run_customg  s
    ,
 zJobQueue.run_customc                    s   | j js| j   dS )z+Starts the :class:`~telegram.ext.JobQueue`.N)r   runningstartr&   r(   r(   r)   rx     s    zJobQueue.startT)waitr"   c                    sH   |rt j| jjddiI dH  | jjrD| jj|d t dI dH  dS )zShuts down the :class:`~telegram.ext.JobQueue`.

        Args:
            wait (:obj:`bool`, optional): Whether to wait until all currently running jobs
                have finished. Defaults to :obj:`True`.

        Zreturn_exceptionsTN)ry   g{Gz?)asyncioZgatherr   Z_pending_futuresr   rw   shutdownsleep)r'   ry   r(   r(   r)   stop  s    zJobQueue.stop)rM   .c                 C   s   t dd | j D S )zReturns a tuple of all *scheduled* jobs that are currently in the :class:`JobQueue`.

        Returns:
            Tuple[:class:`Job`]: Tuple of all *scheduled* jobs.
        c                 s   s   | ]}t |V  qd S r6   )r   from_aps_jobrq   rO   r(   r(   r)   	<genexpr>  s     z JobQueue.jobs.<locals>.<genexpr>)tupler   Zget_jobsr&   r(   r(   r)   jobs  s    zJobQueue.jobs)rU   r"   c                    s   t  fdd|  D S )zReturns a tuple of all *pending/scheduled* jobs with the given name that are currently
        in the :class:`JobQueue`.

        Returns:
            Tuple[:class:`Job`]: Tuple of all *pending* or *scheduled* jobs matching the name.
        c                 3   s   | ]}|j  kr|V  qd S r6   rU   r   r   r(   r)   r     s     
 z,JobQueue.get_jobs_by_name.<locals>.<genexpr>)r   r   )r'   rU   r(   r   r)   get_jobs_by_name  s    zJobQueue.get_jobs_by_name)F)F)F)NNNNN)NNNNNNN)NNNNN)NNNN)T))r\   
__module____qualname____doc__	__slots__rp   r*   strr,   propertyr+   r   r%   r7   r9   r	   boolr=   r   rC   rD   r:   r   rL   staticmethodrQ   r   r   objectrB   r`   rg   rn   	_ALL_DAYSr   ru   rv   rx   r}   r   r   r(   r(   r(   r)   r   3   s   -	$ 	      X             R
X    4c                   @   s"  e Zd ZdZdZd)ee ee ee	 ee
 ee
 dddZe	eddd	Zeed
ddZe
dddZe	dddZeddddZeedddZeedddZejeddddZeeej dddZeddddd Zd!dd"d#d$Zd!dd"d%d&Zddd'd(ZdS )*r   a
  This class is a convenience wrapper for the jobs held in a :class:`telegram.ext.JobQueue`.
    With the current backend APScheduler, :attr:`job` holds a :class:`apscheduler.job.Job`
    instance.

    Objects of this class are comparable in terms of equality. Two objects of this class are
    considered equal, if their :class:`id <apscheduler.job.Job>` is equal.

    This class is a :class:`~typing.Generic` class and accepts one type variable that specifies
    the type of the argument ``context`` of :paramref:`callback`.

    Important:
        If you want to use this class, you must install PTB with the optional requirement
        ``job-queue``, i.e.

        .. code-block:: bash

           pip install "python-telegram-bot[job-queue]"

    Note:
        All attributes and instance methods of :attr:`job` are also directly available as
        attributes/methods of the corresponding :class:`telegram.ext.Job` object.

    Warning:
        This class should not be instantiated manually.
        Use the methods of :class:`telegram.ext.JobQueue` to schedule jobs.

    .. seealso:: :wiki:`Job Queue <Extensions---JobQueue>`

    .. versionchanged:: 20.0

       * Removed argument and attribute ``job_queue``.
       * Renamed ``Job.context`` to :attr:`Job.data`.
       * Removed argument ``job``
       * To use this class, PTB must be installed via
         ``pip install "python-telegram-bot[job-queue]"``.

    Args:
        callback (:term:`coroutine function`): The callback function that should be executed by the
            new job. Callback signature::

                async def callback(context: CallbackContext)

        data (:obj:`object`, optional): Additional data needed for the :paramref:`callback`
            function. Can be accessed through :attr:`Job.data` in the callback. Defaults to
            :obj:`None`.
        name (:obj:`str`, optional): The name of the new job. Defaults to
            :external:obj:`callback.__name__ <definition.__name__>`.
        chat_id (:obj:`int`, optional): Chat id of the chat that this job is associated with.

            .. versionadded:: 20.0
        user_id (:obj:`int`, optional): User id of the user that this job is associated with.

            .. versionadded:: 20.0
    Attributes:
        callback (:term:`coroutine function`): The callback function that should be executed by the
            new job.
        data (:obj:`object`): Optional. Additional data needed for the :attr:`callback` function.
        name (:obj:`str`): Optional. The name of the new job.
        chat_id (:obj:`int`): Optional. Chat id of the chat that this job is associated with.

            .. versionadded:: 20.0
        user_id (:obj:`int`): Optional. User id of the user that this job is associated with.

            .. versionadded:: 20.0
    )_enabledr^   _removedrR   rV   rT   rU   rW   NrY   c                 C   sL   t std|| _|| _|p |j| _|| _|| _d| _d| _	t
dd | _d S )NzWTo use `Job`, PTB must be installed via `pip install "python-telegram-bot[job-queue]"`.FAPSJob)r#   r$   rR   rT   r\   rU   rV   rW   r   r   r   r^   )r'   rR   rT   rU   rV   rW   r(   r(   r)   r*     s    zJob.__init__)itemr"   c              
   C   sH   zt | j|W S  tk
rB } ztd| d|W 5 d}~X Y nX dS )a  Overrides :py:meth:`object.__getattr__` to get specific attribute of the
        :class:`telegram.ext.Job` object or of its attribute :class:`apscheduler.job.Job`,
        if exists.

        Args:
           item (:obj:`str`): The name of the attribute.

        Returns:
            :object: The value of the attribute.

        Raises:
            :exc:`AttributeError`: If the attribute does not exist in both
                :class:`telegram.ext.Job` and :class:`apscheduler.job.Job` objects.
        zDNeither 'telegram.ext.Job' nor 'apscheduler.job.Job' has attribute ''N)getattrrO   AttributeError)r'   r   excr(   r(   r)   __getattr__1  s    
zJob.__getattr__)otherr"   c                 C   s   t || jr| j|jkS dS )aP  Defines equality condition for the :class:`telegram.ext.Job` object.
        Two objects of this class are considered to be equal if their
        :class:`id <apscheduler.job.Job>` are equal.

        Returns:
            :obj:`True` if both objects have :paramref:`id` parameters identical.
            :obj:`False` otherwise.
        F)r3   	__class__id)r'   r   r(   r(   r)   __eq__G  s    	z
Job.__eq__r!   c                 C   s
   t | jS )zBuilds a hash value for this object such that the hash of two objects is
        equal if and only if the objects are equal in terms of :meth:`__eq__`.

        Returns:
            :obj:`int`: The hash value of the object.
        )hashr   r&   r(   r(   r)   __hash__T  s    zJob.__hash__c                 C   s    t | | jj| j| jj| jjdS )a>  Give a string representation of the job in the form
        ``Job[id=..., name=..., callback=..., trigger=...]``.

        As this class doesn't implement :meth:`object.__str__`, the default implementation
        will be used, which is equivalent to :meth:`__repr__`.

        Returns:
            :obj:`str`
        )r   rU   rR   rZ   )r   rO   r   rU   rR   r\   rZ   r&   r(   r(   r)   r,   ]  s    
zJob.__repr__r   c                 C   s   | j S )z:class:`apscheduler.job.Job`: The APS Job this job is a wrapper for.

        .. versionchanged:: 20.0
            This property is now read-only.
        )r^   r&   r(   r(   r)   rO   o  s    zJob.jobc                 C   s   | j S )z3:obj:`bool`: Whether this job is due to be removed.)r   r&   r(   r(   r)   removedx  s    zJob.removedc                 C   s   | j S )z):obj:`bool`: Whether this job is enabled.)r   r&   r(   r(   r)   enabled}  s    zJob.enabled)statusr"   c                 C   s$   |r| j   n
| j   || _d S r6   )rO   resumepauser   )r'   r   r(   r(   r)   r     s    
c                 C   s   | j jS )a  
        :class:`datetime.datetime`: Datetime for the next job execution.
        Datetime is localized according to :attr:`datetime.datetime.tzinfo`.
        If job is removed or already ran it equals to :obj:`None`.

        Warning:
            This attribute is only available, if the :class:`telegram.ext.JobQueue` this job
            belongs to is already started. Otherwise APScheduler raises an :exc:`AttributeError`.
        )rO   Znext_run_timer&   r(   r(   r)   next_t  s    z
Job.next_trM   )aps_jobr"   c                 C   s   |j d }||_|S )a  Provides the :class:`telegram.ext.Job` that is associated with the given APScheduler
        job.

        Tip:
            This method can be useful when using advanced APScheduler features along with
            :class:`telegram.ext.JobQueue`.

        .. versionadded:: 20.4

        Args:
            aps_job (:class:`apscheduler.job.Job`): The APScheduler job

        Returns:
            :class:`telegram.ext.Job`
        r@   )r[   r^   )clsr   Zext_jobr(   r(   r)   r~     s    
zJob.from_aps_jobr-   rH   c                    s   t | |I dH  dS )a  Executes the callback function independently of the jobs schedule. Also calls
        :meth:`telegram.ext.Application.update_persistence`.

        .. versionchanged:: 20.0
            Calls :meth:`telegram.ext.Application.update_persistence`.

        Args:
            application (:class:`telegram.ext.Application`): The application this job is associated
                with.
        N)rz   Zshield_runr.   r(   r(   r)   rP     s    zJob.runc              
      s   zzxz|jj| |}W n@ tk
rX } z"tjd| j|d W Y 
W W d S d }~X Y nX | I d H  | 	|I d H  W nL tk
r } z.|j
|jd || dd| j ddI d H  W 5 d }~X Y nX W 5 |j | d X d S )N)rO   zEError while building CallbackContext for job %s. Job will not be run.)exc_infozJob:z:run:process_errorr   )Z_mark_for_persistence_updateZcontext_typescontextZfrom_job	Exception_LOGGERcriticalr^   Zrefresh_datarR   Zcreate_taskZprocess_errorr   )r'   r+   r   r   r(   r(   r)   r     s$    "zJob._runc                 C   s   | j   d| _dS )z
        Schedules this job for removal from the :class:`JobQueue`. It will be removed without
        executing its callback function again.
        TN)rO   remover   r&   r(   r(   r)   schedule_removal  s    
zJob.schedule_removal)NNNN)r\   r   r   r   r   r   r   r   r   r   rB   r*   r   r   r   r   r,   r   rO   r   r   setterr7   r   classmethodr~   rP   r   r   r(   r(   r(   r)   r     sH   B    	r   )*r   rz   r7   rI   typingr   r   r   r   r   r   r   r	   r1   Zapscheduler.executors.asyncior
   Zapscheduler.schedulers.asyncior   r#   ImportErrorZtelegram._utils.loggingr   Ztelegram._utils.reprr   Ztelegram._utils.typesr   Ztelegram.ext._extbotr   Ztelegram.ext._utils.typesr   r   Zapscheduler.jobr   r   Ztelegram.extr   r   ranger   r\   r   r   r(   r(   r(   r)   <module>   s:   (
     