-
Notifications
You must be signed in to change notification settings - Fork 55
Feature/task scheduling decorators #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a4ed451
2c63075
c7cb539
49efe3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from pytz import utc | ||
from apscheduler.schedulers.background import BackgroundScheduler | ||
|
||
""" | ||
An instance of the BackgroundScheduler class from the APScheduler library. | ||
""" | ||
|
||
scheduler = BackgroundScheduler() | ||
scheduler.configure(timezone=utc) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
from enum import Enum | ||
from apscheduler.triggers.cron import CronTrigger | ||
|
||
class CronExpression(Enum): | ||
""" | ||
Enum that contains cron expressions. | ||
A cron expression is a string representing a set of times, using 6 space-separated fields. | ||
Fields: | ||
- second (0-59) | ||
- minute (0-59) | ||
- hour (0-23) | ||
- day of month (1-31) | ||
- month (1-12) | ||
- day of week (0-6) (Sunday to Saturday) | ||
- year (optional) | ||
- timezone (optional) | ||
""" | ||
EVERY_SECOND = CronTrigger(second="*") | ||
EVERY_5_SECONDS = CronTrigger(second="*/5") | ||
EVERY_10_SECONDS = CronTrigger(second="*/10") | ||
EVERY_30_SECONDS = CronTrigger(second="*/30") | ||
EVERY_MINUTE = CronTrigger(minute="*/1") | ||
EVERY_5_MINUTES = CronTrigger(minute="*/5") | ||
EVERY_10_MINUTES = CronTrigger(minute="*/10") | ||
EVERY_30_MINUTES = CronTrigger(minute="*/30") | ||
EVERY_HOUR = CronTrigger(minute=0, hour="0-23/1") | ||
EVERY_2_HOURS = CronTrigger(minute=0, hour="0-23/2") | ||
EVERY_3_HOURS = CronTrigger(minute=0, hour="0-23/3") | ||
EVERY_4_HOURS = CronTrigger(minute=0, hour="0-23/4") | ||
EVERY_5_HOURS = CronTrigger(minute=0, hour="0-23/5") | ||
EVERY_6_HOURS = CronTrigger(minute=0, hour="0-23/6") | ||
EVERY_7_HOURS = CronTrigger(minute=0, hour="0-23/7") | ||
EVERY_8_HOURS = CronTrigger(minute=0, hour="0-23/8") | ||
EVERY_9_HOURS = CronTrigger(minute=0, hour="0-23/9") | ||
EVERY_10_HOURS = CronTrigger(minute=0, hour="0-23/10") | ||
EVERY_11_HOURS = CronTrigger(minute=0, hour="0-23/11") | ||
EVERY_12_HOURS = CronTrigger(minute=0, hour="0-23/12") | ||
EVERY_DAY_AT_1AM = CronTrigger(minute=0, hour=1) | ||
EVERY_DAY_AT_2AM = CronTrigger(minute=0, hour=2) | ||
EVERY_DAY_AT_3AM = CronTrigger(minute=0, hour=3) | ||
EVERY_DAY_AT_4AM = CronTrigger(minute=0, hour=4) | ||
EVERY_DAY_AT_5AM = CronTrigger(minute=0, hour=5) | ||
EVERY_DAY_AT_6AM = CronTrigger(minute=0, hour=6) | ||
EVERY_DAY_AT_7AM = CronTrigger(minute=0, hour=7) | ||
EVERY_DAY_AT_8AM = CronTrigger(minute=0, hour=8) | ||
EVERY_DAY_AT_9AM = CronTrigger(minute=0, hour=9) | ||
EVERY_DAY_AT_10AM = CronTrigger(minute=0, hour=10) | ||
EVERY_DAY_AT_11AM = CronTrigger(minute=0, hour=11) | ||
EVERY_DAY_AT_NOON = CronTrigger(minute=0, hour=12) | ||
EVERY_DAY_AT_1PM = CronTrigger(minute=0, hour=13) | ||
EVERY_DAY_AT_2PM = CronTrigger(minute=0, hour=14) | ||
EVERY_DAY_AT_3PM = CronTrigger(minute=0, hour=15) | ||
EVERY_DAY_AT_4PM = CronTrigger(minute=0, hour=16) | ||
EVERY_DAY_AT_5PM = CronTrigger(minute=0, hour=17) | ||
EVERY_DAY_AT_6PM = CronTrigger(minute=0, hour=18) | ||
EVERY_DAY_AT_7PM = CronTrigger(minute=0, hour=19) | ||
EVERY_DAY_AT_8PM = CronTrigger(minute=0, hour=20) | ||
EVERY_DAY_AT_9PM = CronTrigger(minute=0, hour=21) | ||
EVERY_DAY_AT_10PM = CronTrigger(minute=0, hour=22) | ||
EVERY_DAY_AT_11PM = CronTrigger(minute=0, hour=23) | ||
EVERY_DAY_AT_MIDNIGHT = CronTrigger(minute=0, hour=0) | ||
EVERY_WEEK = CronTrigger(minute=0, hour=0, day_of_week=0) | ||
EVERY_WEEKDAY = CronTrigger(minute=0, hour=0, day_of_week="1-5") | ||
EVERY_WEEKEND = CronTrigger(minute=0, hour=0, day_of_week="6,0") | ||
EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT = CronTrigger(minute=0, hour=0, day=1) | ||
EVERY_1ST_DAY_OF_MONTH_AT_NOON = CronTrigger(minute=0, hour=12, day=1) | ||
EVERY_2ND_HOUR = CronTrigger(minute=0, hour="*/2") | ||
EVERY_2ND_HOUR_FROM_1AM_THROUGH_11PM = CronTrigger(minute=0, hour="1-23/2") | ||
EVERY_2ND_MONTH = CronTrigger(minute=0, hour=0, day=1, month="*/2") | ||
EVERY_QUARTER = CronTrigger(minute=0, hour=0, day=1, month="*/3") | ||
EVERY_6_MONTHS = CronTrigger(minute=0, hour=0, day=1, month="*/6") | ||
EVERY_YEAR = CronTrigger(minute=0, hour=0, day=1, month=1) | ||
EVERY_30_MINUTES_BETWEEN_9AM_AND_5PM = CronTrigger(minute="*/30", hour="9-17") | ||
EVERY_30_MINUTES_BETWEEN_9AM_AND_6PM = CronTrigger(minute="*/30", hour="9-18") | ||
EVERY_30_MINUTES_BETWEEN_10AM_AND_7PM = CronTrigger(minute="*/30", hour="10-19") | ||
MONDAY_TO_FRIDAY_AT_1AM = CronTrigger(minute=0, hour=1, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_2AM = CronTrigger(minute=0, hour=2, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_3AM = CronTrigger(minute=0, hour=3, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_4AM = CronTrigger(minute=0, hour=4, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_5AM = CronTrigger(minute=0, hour=5, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_6AM = CronTrigger(minute=0, hour=6, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_7AM = CronTrigger(minute=0, hour=7, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_8AM = CronTrigger(minute=0, hour=8, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_9AM = CronTrigger(minute=0, hour=9, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_09_30AM = CronTrigger(minute=30, hour=9, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_10AM = CronTrigger(minute=0, hour=10, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_11AM = CronTrigger(minute=0, hour=11, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_11_30AM = CronTrigger(minute=30, hour=11, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_12PM = CronTrigger(minute=0, hour=12, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_1PM = CronTrigger(minute=0, hour=13, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_2PM = CronTrigger(minute=0, hour=14, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_3PM = CronTrigger(minute=0, hour=15, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_4PM = CronTrigger(minute=0, hour=16, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_5PM = CronTrigger(minute=0, hour=17, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_6PM = CronTrigger(minute=0, hour=18, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_7PM = CronTrigger(minute=0, hour=19, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_8PM = CronTrigger(minute=0, hour=20, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_9PM = CronTrigger(minute=0, hour=21, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_10PM = CronTrigger(minute=0, hour=22, day_of_week="1-5") | ||
MONDAY_TO_FRIDAY_AT_11PM = CronTrigger(minute=0, hour=23, day_of_week="1-5") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from enum import Enum | ||
|
||
class SchedulerTypes(Enum): | ||
""" | ||
An enumeration of scheduler types. | ||
""" | ||
CRON = 'cron', | ||
DATE = 'date' | ||
INTERVAL = 'interval', | ||
Comment on lines
+7
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are trailing commas after 'cron' and 'interval' in the SchedulerTypes enum, which is inconsistent with the 'date' entry. Finding type: |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
from typing import Optional, Callable, Type | ||
|
||
from nest.core.apscheduler import scheduler | ||
|
||
|
||
from nest.core.apscheduler.enums.cron_expression import CronExpression | ||
from nest.core.apscheduler.enums.scheduler_type import SchedulerType | ||
|
||
def Cron(expression: CronExpression = CronExpression.EVERY_MINUTE) -> Callable: | ||
""" | ||
Decorator that schedules a function to run at a specific time. | ||
|
||
Args: | ||
expression (CronExpression): A cron expression. | ||
|
||
Returns: | ||
function: The decorated function. | ||
""" | ||
def decorated(func: Callable) -> Callable: | ||
def wrapper(*args, **kwargs): | ||
""" | ||
Wrapper function that schedules the function to run at a specific time. | ||
""" | ||
try: | ||
if not isinstance(expression, CronExpression): | ||
raise ValueError("Invalid cron expression.") | ||
scheduler.add_job( | ||
func, | ||
trigger = expression.value, | ||
id = func.__name__, | ||
) | ||
except Exception as e: | ||
raise ValueError(f"Invalid cron expression: {e}") | ||
|
||
|
||
return wrapper | ||
|
||
return decorated | ||
Comment on lines
+9
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Cron decorator function contains nested try-except blocks and conditionals that can be simplified. The type checking can be moved to a separate function for better readability. Finding type: |
||
|
||
def Interval(seconds: Optional[int] = 10, minutes: Optional[int] = None, hours: Optional[int] = None, days: Optional[int] = None) -> Callable: | ||
""" | ||
Decorator that schedules a function to run at a specific interval. | ||
|
||
Args: | ||
seconds (int): The number of seconds between each run. | ||
minutes (int): The number of minutes between each run. | ||
hours (int): The number of hours between each run. | ||
days (int): The number of days between each run. | ||
|
||
Returns: | ||
function: The decorated function. | ||
""" | ||
def decorated(func: Callable) -> Callable: | ||
def wrapper(*args, **kwargs): | ||
""" | ||
Wrapper function that schedules the function to run at a specific interval. | ||
""" | ||
try: | ||
scheduler.add_job( | ||
func, | ||
trigger = SchedulerType.INTERVAL.value, | ||
seconds = seconds, | ||
minutes = minutes, | ||
hours = hours, | ||
days = days, | ||
id = func.__name__ | ||
) | ||
except Exception as e: | ||
raise ValueError(f"Invalid interval: {e}") | ||
|
||
return wrapper | ||
|
||
return decorated |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,10 @@ dependencies = [ | |
"pydantic<2.0.0", | ||
"sqlalchemy == 2.0.19", | ||
"alembic == 1.7.5", | ||
"APScheduler >= "3.10.4", | ||
"pytz >= "2024.2", | ||
"six >= "1.16.0", | ||
Comment on lines
+36
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are typos in the version specifications for APScheduler, pytz, and tzlocal. The quotation marks are incorrectly placed. Finding type: |
||
"tzlocal >= "5.2", | ||
] | ||
|
||
[tool.setuptools.dynamic] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CronExpression enum contains many repetitive entries that could be generated programmatically. This would make the code more concise and easier to maintain.
Finding type:
Conciseness