Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
71abbed
Adding timeunit and day support to the jobqueue
Nov 2, 2016
a257901
Adding tests
Nov 2, 2016
a5eedba
Changed the file permission back to 644.
Nov 2, 2016
fe6eca2
Changed AssertEqual argument order to (actual, expectd).
Nov 2, 2016
036feeb
Removed the TimeUnit enum and unit param, instead use datetime.time f…
Nov 2, 2016
7c3c5f0
Removing the TimeUnits enum and unit param in favour of optionally us…
Nov 2, 2016
68e2537
Changing the time units test so it works with datetime.time.
Nov 2, 2016
12e2c24
Removing the TimeUnits enumeration, forgot the remove it in the last …
Nov 2, 2016
9c94fb4
Removed some old docstrings refering to the TimeUnits enum.
Nov 2, 2016
27fb6e8
Removed the old TimeUnits import.
Nov 2, 2016
742add1
Adding some error handling for the 'days' argument (only a 'tuple' wi…
Nov 3, 2016
f7786e8
Writing the error message directly in the exception.
Nov 3, 2016
766e963
Moving a debug statement wrongfully saying a job would be running on …
Nov 3, 2016
2e4b4ef
Writing error messages directly in the exceptions instead of making a…
Nov 3, 2016
f25c182
Replacing datetime.time in favour of datetime.timedelta because of th…
Nov 4, 2016
146ee9b
Adding error handling for the method .
Nov 4, 2016
54f5a7f
Splitting the tests up in multiple ones, no float test because I have…
Nov 4, 2016
b307f3e
Excluding .exrc file.
Nov 5, 2016
4ce188b
Removing \ at EOF of ValueError.
Nov 6, 2016
4bc363e
Replacing Enums with plain new-style classes.
Nov 6, 2016
93625ee
Using numbers.number to check for ints/floats instead of seperate int…
Nov 6, 2016
83efa8a
Fixing typo, number -> Number.
Nov 6, 2016
f886d7c
Changed lower_case Days attributes to UPPER_CASE.
Nov 8, 2016
ce555cc
Different formatting for Days class, removed the get_days function in…
Nov 8, 2016
c4a1cb6
Removed redundant function get_days.
Nov 8, 2016
e5633d1
Edited the docstring for next_t to also take datetime.timedelta.
Nov 8, 2016
f841f04
Removed for-loop in favour of any().
Nov 8, 2016
9c8c513
Changed docstring for interval.
Nov 8, 2016
6638a11
Removed debug print.
Nov 8, 2016
4b2fff2
Changing some docstrings.
Nov 8, 2016
a76d664
Changing some docstrings (again).
Nov 8, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ telegram.webp

# original files from merges
*.orig

# Exclude .exrc file for Vim
.exrc
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The following wonderful people contributed directly or indirectly to this projec
- `Shelomentsev D <https://github.com/shelomentsevd>`_
- `sooyhwang <https://github.com/sooyhwang>`_
- `Valentijn <https://github.com/Faalentijn>`_
- `voider1 <https://github.com/voider1>`_
- `wjt <https://github.com/wjt>`_

Please add yourself here alphabetically when you submit your first pull request.
51 changes: 41 additions & 10 deletions telegram/ext/jobqueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@
import logging
import time
import warnings
import datetime
from numbers import Number
from threading import Thread, Lock, Event
from queue import PriorityQueue, Empty


class Days(object):
MON, TUE, WED, THU, FRI, SAT, SUN = range(7)
EVERY_DAY = tuple(range(7))


class JobQueue(object):
"""This class allows you to periodically perform tasks with the bot.

Expand Down Expand Up @@ -61,14 +68,25 @@ def put(self, job, next_t=None):

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the docstring so it mentions that next_t can also be of type timedelta

Args:
job (telegram.ext.Job): The ``Job`` instance representing the new job
next_t (Optional[float]): Time in seconds in which the job should be executed first.
Defaults to ``job.interval``
next_t (Optional[int, float, datetime.timedelta]): Time in which the job
should be executed first. Defaults to ``job.interval``. ``int`` and ``float``
will be interpreted as seconds.

"""
job.job_queue = self

if next_t is None:
next_t = job.interval
interval = job.interval

if isinstance(interval, Number):
next_t = interval
elif isinstance(interval, datetime.timedelta):
next_t = interval.total_seconds()
else:
raise ValueError("The interval argument should be of type datetime.timedelta,"
" int or float")
elif isinstance(next_t, datetime.timedelta):
next_t = next_t.total_second()

now = time.time()
next_t += now
Expand Down Expand Up @@ -123,11 +141,11 @@ def tick(self):
continue

if job.enabled:
self.logger.debug('Running job %s', job.name)

try:
job.run(self.bot)

current_week_day = datetime.datetime.now().weekday()
if any(day == current_week_day for day in job.days):
self.logger.debug('Running job %s', job.name)
job.run(self.bot)
except:
self.logger.exception('An uncaught error was raised while executing job %s',
job.name)
Expand Down Expand Up @@ -200,6 +218,7 @@ class Job(object):
Attributes:
callback (function):
interval (float):
days: (tuple)
repeat (bool):
name (str):
enabled (bool): Boolean property that decides if this job is currently active
Expand All @@ -208,22 +227,34 @@ class Job(object):
callback (function): The callback function that should be executed by the Job. It should
take two parameters ``bot`` and ``job``, where ``job`` is the ``Job`` instance. It
can be used to terminate the job or modify its interval.
interval (float): The interval in which this job should execute its callback function in
seconds.
interval ([int, float, datetime.timedelta]): The interval in which the job will execute its
callback function. ``int`` and ``float`` will be interpreted as seconds.
repeat (Optional[bool]): If this job should be periodically execute its callback function
(``True``) or only once (``False``). Defaults to ``True``
context (Optional[object]): Additional data needed for the callback function. Can be
accessed through ``job.context`` in the callback. Defaults to ``None``
days (Tuple): Defines on which days the job should be ran.

"""
job_queue = None

def __init__(self, callback, interval, repeat=True, context=None):
def __init__(self, callback, interval, repeat=True, context=None, days=Days.EVERY_DAY):
self.callback = callback
self.interval = interval
self.repeat = repeat
self.context = context

if not isinstance(days, tuple):
raise ValueError("The 'days argument should be of type 'tuple'")

if not all(isinstance(day, int) for day in days):
raise ValueError("The elements of the 'days' argument should be of type 'int'")

if not all(day >= 0 and day <= 6 for day in days):
raise ValueError("The elements of the 'days' argument should be from 0 up to and "
"including 6")

self.days = days
self.name = callback.__name__
self._remove = Event()
self._enabled = Event()
Expand Down
29 changes: 29 additions & 0 deletions tests/test_jobqueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import logging
import sys
import unittest
import datetime
import time
from math import ceil
from time import sleep

from tests.test_updater import MockBot
Expand Down Expand Up @@ -53,11 +56,15 @@ def setUp(self):
self.jq = JobQueue(MockBot('jobqueue_test'))
self.jq.start()
self.result = 0
self.job_time = 0

def tearDown(self):
if self.jq is not None:
self.jq.stop()

def getSeconds(self):
return int(ceil(time.time()))

def job1(self, bot, job):
self.result += 1

Expand All @@ -71,6 +78,9 @@ def job3(self, bot, job):
def job4(self, bot, job):
self.result += job.context

def job5(self, bot, job):
self.job_time = self.getSeconds()

def test_basic(self):
self.jq.put(Job(self.job1, 0.1))
sleep(1.5)
Expand Down Expand Up @@ -169,6 +179,25 @@ def test_inUpdater(self):
finally:
u.stop()

def test_time_unit_int(self):
# Testing seconds in int
seconds_interval = 5
expected_time = self.getSeconds() + seconds_interval

self.jq.put(Job(self.job5, seconds_interval, repeat=False))
sleep(6)
self.assertEqual(self.job_time, expected_time)

def test_time_unit_dt_time(self):
# Testing seconds, minutes and hours as datetime.timedelta object
# This is sufficient to test that it actually works.
interval = datetime.timedelta(seconds=5)
expected_time = self.getSeconds() + interval.total_seconds()

self.jq.put(Job(self.job5, interval, repeat=False))
sleep(6)
self.assertEqual(self.job_time, expected_time)


if __name__ == '__main__':
unittest.main()