dl2-tasks 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Datalys2 Tasks Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: dl2-tasks
3
+ Version: 0.1.0
4
+ Summary: A lightweight local task orchestration system built on windows task scheduler
5
+ Author-email: Datalys2 Team <kameron@example.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Datalys2 Tasks Contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/yourusername/datalys2-tasks
29
+ Project-URL: Documentation, https://github.com/yourusername/datalys2-tasks/blob/main/DOCUMENTATION.md
30
+ Project-URL: Repository, https://github.com/yourusername/datalys2-tasks.git
31
+ Keywords: windows,task scheduler,automation,scheduling,cron
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Operating System :: Microsoft :: Windows
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.8
38
+ Classifier: Programming Language :: Python :: 3.9
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Topic :: System :: Systems Administration
42
+ Requires-Python: >=3.8
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: fastapi>=0.100.0
46
+ Requires-Dist: uvicorn>=0.20.0
47
+ Requires-Dist: pydantic>=2.0.0
48
+ Requires-Dist: requests>=2.28.0
49
+ Requires-Dist: sqlalchemy>=2.0.0
50
+ Dynamic: license-file
51
+
52
+ # Datalys2 Tasks
53
+
54
+ **A lightweight, local task orchestration system built for Windows.**
55
+
56
+ `dl2-tasks` (Datalys2 Tasks) is a robust wrapper around the native **Windows Task Scheduler**. It provides a modern Python interface for scheduling, managing, and monitoring background tasks without the need for a heavy, always-on server process.
57
+
58
+ ## 🌟 Features
59
+
60
+ - **No Background Process Required:** Leverages Windows' built-in `schtasks.exe`.
61
+ - **Self-Scheduling Scripts:** Add `schedule_me()` to your script, run it once, and it's scheduled forever.
62
+ - **Lightweight:** Minimal dependencies.
63
+ - **Robust:** If Python crashes, the scheduler remains.
64
+
65
+ ## 📦 Installation
66
+
67
+ ```bash
68
+ pip install dl2-tasks
69
+ ```
70
+
71
+ ## 🚀 Quick Start
72
+
73
+ ### Auto-Scheduling (The "Magic" Way)
74
+
75
+ The easiest way to use Datalys2 Tasks is to let your scripts schedule themselves.
76
+
77
+ 1. Create `my_task.py`:
78
+
79
+ ```python
80
+ import datetime
81
+ from datalys2_tasks.scheduler.autorun import schedule_me
82
+
83
+ def job():
84
+ with open("log.txt", "a") as f:
85
+ f.write(f"Ran at {datetime.datetime.now()}\n")
86
+
87
+ if __name__ == "__main__":
88
+ # Registers this script to run everyday at 08:00
89
+ schedule_me("MyDailyLog", frequency="DAILY", at="08:00")
90
+
91
+ job()
92
+ ```
93
+
94
+ 2. Run it once manually:
95
+ ```bash
96
+ python my_task.py
97
+ ```
98
+
99
+ 3. That's it! Windows will now run this script every day at 08:00.
100
+
101
+ ### CLI Management
102
+
103
+ You can also manage tasks via the command line.
104
+
105
+ - **List tasks:** `datalys2-server schedule list`
106
+ - **Add a task:** `datalys2-server schedule add "Backup" "C:\scripts\backup.py" --schedule DAILY --time 02:00`
107
+ - **Run manually:** `datalys2-server schedule run "Backup"`
108
+
109
+ ## 🖥️ Optional Dashboard
110
+
111
+ Includes a local dashboard for viewing task status.
112
+
113
+ ```bash
114
+ datalys2-server start
115
+ ```
116
+ *Opens http://localhost:8000/dashboard*
117
+
118
+ ---
119
+
120
+ For full details, see the documentation.
@@ -0,0 +1,69 @@
1
+ # Datalys2 Tasks
2
+
3
+ **A lightweight, local task orchestration system built for Windows.**
4
+
5
+ `dl2-tasks` (Datalys2 Tasks) is a robust wrapper around the native **Windows Task Scheduler**. It provides a modern Python interface for scheduling, managing, and monitoring background tasks without the need for a heavy, always-on server process.
6
+
7
+ ## 🌟 Features
8
+
9
+ - **No Background Process Required:** Leverages Windows' built-in `schtasks.exe`.
10
+ - **Self-Scheduling Scripts:** Add `schedule_me()` to your script, run it once, and it's scheduled forever.
11
+ - **Lightweight:** Minimal dependencies.
12
+ - **Robust:** If Python crashes, the scheduler remains.
13
+
14
+ ## 📦 Installation
15
+
16
+ ```bash
17
+ pip install dl2-tasks
18
+ ```
19
+
20
+ ## 🚀 Quick Start
21
+
22
+ ### Auto-Scheduling (The "Magic" Way)
23
+
24
+ The easiest way to use Datalys2 Tasks is to let your scripts schedule themselves.
25
+
26
+ 1. Create `my_task.py`:
27
+
28
+ ```python
29
+ import datetime
30
+ from datalys2_tasks.scheduler.autorun import schedule_me
31
+
32
+ def job():
33
+ with open("log.txt", "a") as f:
34
+ f.write(f"Ran at {datetime.datetime.now()}\n")
35
+
36
+ if __name__ == "__main__":
37
+ # Registers this script to run everyday at 08:00
38
+ schedule_me("MyDailyLog", frequency="DAILY", at="08:00")
39
+
40
+ job()
41
+ ```
42
+
43
+ 2. Run it once manually:
44
+ ```bash
45
+ python my_task.py
46
+ ```
47
+
48
+ 3. That's it! Windows will now run this script every day at 08:00.
49
+
50
+ ### CLI Management
51
+
52
+ You can also manage tasks via the command line.
53
+
54
+ - **List tasks:** `datalys2-server schedule list`
55
+ - **Add a task:** `datalys2-server schedule add "Backup" "C:\scripts\backup.py" --schedule DAILY --time 02:00`
56
+ - **Run manually:** `datalys2-server schedule run "Backup"`
57
+
58
+ ## 🖥️ Optional Dashboard
59
+
60
+ Includes a local dashboard for viewing task status.
61
+
62
+ ```bash
63
+ datalys2-server start
64
+ ```
65
+ *Opens http://localhost:8000/dashboard*
66
+
67
+ ---
68
+
69
+ For full details, see the documentation.
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dl2-tasks"
7
+ version = "0.1.0"
8
+ description = "A lightweight local task orchestration system built on windows task scheduler"
9
+ readme = "README.md"
10
+ authors = [
11
+ {name = "Datalys2 Team", email = "kameron@example.com"}
12
+ ]
13
+ license = {file = "LICENSE"}
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: Microsoft :: Windows",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.8",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Topic :: System :: Systems Administration",
25
+ ]
26
+ keywords = ["windows", "task scheduler", "automation", "scheduling", "cron"]
27
+ requires-python = ">=3.8"
28
+ dependencies = [
29
+ "fastapi>=0.100.0",
30
+ "uvicorn>=0.20.0",
31
+ "pydantic>=2.0.0",
32
+ "requests>=2.28.0",
33
+ "sqlalchemy>=2.0.0"
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/yourusername/datalys2-tasks"
38
+ Documentation = "https://github.com/yourusername/datalys2-tasks/blob/main/DOCUMENTATION.md"
39
+ Repository = "https://github.com/yourusername/datalys2-tasks.git"
40
+
41
+
42
+ [project.scripts]
43
+ datalys2-server = "datalys2_tasks.cli:main"
44
+
45
+ [tool.setuptools.packages.find]
46
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,107 @@
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+ from .server.app import start_server
5
+ from .server.startup import install_service, remove_service
6
+ from .scheduler.windows import WindowsTaskScheduler
7
+
8
+ def main():
9
+ parser = argparse.ArgumentParser(description="Datalys2 Tasks Server & Scheduler CLI")
10
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
11
+
12
+ # --- Server Commands ---
13
+ # Start Server
14
+ subparsers.add_parser("start", help="Start the Task Server immediately")
15
+
16
+ # Install Service
17
+ subparsers.add_parser("install", help="Register server as a Windows startup task")
18
+
19
+ # Remove Service
20
+ subparsers.add_parser("remove", help="Remove the Windows startup task")
21
+
22
+ # --- Scheduler Commands ---
23
+ sched_parser = subparsers.add_parser("schedule", help="Manage Windows Scheduled Tasks direct execution mode")
24
+ sched_subs = sched_parser.add_subparsers(dest="sched_command", help="Scheduler actions")
25
+
26
+ # Schedule: Create/Add
27
+ add_p = sched_subs.add_parser("add", help="Create a new scheduled task")
28
+ add_p.add_argument("name", help="Unique name for the task")
29
+ add_p.add_argument("script", help="Path to the Python script to execute")
30
+ add_p.add_argument("--schedule", default="DAILY", choices=["DAILY", "HOURLY", "MINUTE", "ONCE", "ONLOGON"], help="Schedule type")
31
+ add_p.add_argument("--time", help="Start time (HH:mm)")
32
+ add_p.add_argument("--interval", type=int, help="Interval (minutes) if schedule is MINUTE or modifier for others")
33
+ add_p.add_argument("--force", action="store_true", help="Overwrite existing task")
34
+ add_p.add_argument("--args", nargs="*", help="Arguments to pass to the script")
35
+
36
+ # Schedule: List
37
+ list_p = sched_subs.add_parser("list", help="List scheduled tasks")
38
+ list_p.add_argument("--pattern", default="*", help="Filter tasks by name (substring)")
39
+
40
+ # Schedule: Delete
41
+ del_p = sched_subs.add_parser("remove", help="Delete a scheduled task")
42
+ del_p.add_argument("name", help="Name of the task to delete")
43
+
44
+ # Schedule: Run (Manual)
45
+ run_p = sched_subs.add_parser("run", help="Manually run a scheduled task now")
46
+ run_p.add_argument("name", help="Name of the task to run")
47
+
48
+
49
+ args = parser.parse_args()
50
+
51
+ if args.command == "start":
52
+ print("Starting Datalys2 Server...")
53
+ start_server()
54
+ elif args.command == "install":
55
+ install_service()
56
+ elif args.command == "remove":
57
+ remove_service()
58
+ elif args.command == "schedule":
59
+ scheduler = WindowsTaskScheduler()
60
+
61
+ if args.sched_command == "add":
62
+ success = scheduler.create_task(
63
+ task_name=args.name,
64
+ script_path=args.script,
65
+ schedule=args.schedule,
66
+ start_time=args.time,
67
+ interval_minutes=args.interval,
68
+ args=args.args,
69
+ force=args.force
70
+ )
71
+ if success:
72
+ print(f"Task '{args.name}' scheduled successfully.")
73
+ else:
74
+ sys.exit(1)
75
+
76
+ elif args.sched_command == "list":
77
+ tasks = scheduler.list_tasks(pattern=args.pattern)
78
+ if not tasks:
79
+ print("No matching tasks found.")
80
+ else:
81
+ print(f"{'Task Name':<40} {'Next Run Time':<25} {'Status':<15}")
82
+ print("-" * 80)
83
+ for t in tasks:
84
+ name = t.get('TaskName', 'N/A').replace('\\', '') # Cleanup backslashes often returned by schtasks
85
+ next_run = t.get('Next Run Time', 'N/A')
86
+ status = t.get('Status', 'N/A')
87
+ print(f"{name:<40} {next_run:<25} {status:<15}")
88
+
89
+ elif args.sched_command == "remove":
90
+ if scheduler.delete_task(args.name):
91
+ print(f"Task '{args.name}' deleted.")
92
+ else:
93
+ sys.exit(1)
94
+
95
+ elif args.sched_command == "run":
96
+ if scheduler.run_task(args.name):
97
+ print(f"Task '{args.name}' triggered.")
98
+ else:
99
+ sys.exit(1)
100
+ else:
101
+ sched_parser.print_help()
102
+
103
+ else:
104
+ parser.print_help()
105
+
106
+ if __name__ == "__main__":
107
+ main()
@@ -0,0 +1 @@
1
+ # Client decorators
@@ -0,0 +1,116 @@
1
+ import functools
2
+ import inspect
3
+ import os
4
+ import sys
5
+ from typing import Optional, List, Union, Callable
6
+ from ..core.config import settings
7
+ from ..scheduler.windows import WindowsTaskScheduler
8
+ from ..server.database import SessionLocal, ScheduledTaskDB, init_db
9
+
10
+ class TaskWrapper:
11
+ def __init__(self, func, task_name: Optional[str] = None):
12
+ self.func = func
13
+ self.default_task_name = task_name or func.__name__
14
+ functools.update_wrapper(self, func)
15
+
16
+ # Determine the absolute path of the module defining the function
17
+ module = inspect.getmodule(func)
18
+
19
+ # Safely get __file__, defaulting to None if it doesn't exist
20
+ module_file = getattr(module, '__file__', None) if module else None
21
+
22
+ if module_file:
23
+ self.module_path = os.path.abspath(module_file)
24
+ else:
25
+ # Fallback (might fail in interactive shells)
26
+ self.module_path = os.path.abspath(sys.argv[0])
27
+
28
+ def __call__(self, *args, **kwargs):
29
+ """Allow normal local execution."""
30
+ return self.func(*args, **kwargs)
31
+
32
+ def schedule_run(
33
+ self,
34
+ task_name: Optional[str] = None,
35
+ schedule: str = "DAILY",
36
+ start_time: Optional[str] = None,
37
+ interval: Optional[int] = None,
38
+ force: bool = False,
39
+ cli_args: Optional[List[str]] = None
40
+ ) -> bool:
41
+ """
42
+ Register this function's script as a Windows Scheduled Task.
43
+
44
+ Args:
45
+ task_name (str, optional): Unique identifier for the Windows Task Scheduler.
46
+ Defaults to the name provided in @task decorator or function name.
47
+ schedule (str): Frequency ('DAILY', 'HOURLY', 'minute', 'ONCE', 'ONLOGON').
48
+ start_time (str): Time to start (HH:mm).
49
+ interval (int): Interval in minutes (if applicable).
50
+ force (bool): Overwrite existing task.
51
+ cli_args (List[str]): Command line arguments to pass to the script execution.
52
+
53
+ Returns:
54
+ bool: Success status.
55
+ """
56
+ final_task_name = task_name or self.default_task_name
57
+
58
+ scheduler = WindowsTaskScheduler()
59
+ print(f"Scheduling script: {self.module_path} as '{final_task_name}'")
60
+ success = scheduler.create_task(
61
+ task_name=final_task_name,
62
+ script_path=self.module_path,
63
+ schedule=schedule,
64
+ start_time=start_time,
65
+ interval_minutes=interval,
66
+ args=cli_args,
67
+ force=force
68
+ )
69
+
70
+ if success:
71
+ # Save to SQLite DB in %APPDATA%
72
+ try:
73
+ # Ensure DB tables exist (idempotent)
74
+ init_db()
75
+
76
+ db = SessionLocal()
77
+ # Check if exists to update or create
78
+ existing = db.query(ScheduledTaskDB).filter(ScheduledTaskDB.task_name == final_task_name).first()
79
+ if existing:
80
+ existing.script_path = self.module_path
81
+ existing.schedule_type = schedule
82
+ existing.schedule_time = start_time
83
+ existing.interval_minutes = interval
84
+ existing.description = f"Scheduled via decorator from {self.func.__name__}"
85
+ else:
86
+ new_task = ScheduledTaskDB(
87
+ task_name=final_task_name,
88
+ script_path=self.module_path,
89
+ schedule_type=schedule,
90
+ schedule_time=start_time,
91
+ interval_minutes=interval,
92
+ description=f"Scheduled via decorator from {self.func.__name__}"
93
+ )
94
+ db.add(new_task)
95
+
96
+ db.commit()
97
+ db.close()
98
+ print("Task registration saved to local database.")
99
+ except Exception as e:
100
+ print(f"Warning: Failed to save task to local database: {e}")
101
+
102
+ return success
103
+
104
+ def task(func: Union[Callable, None] = None, *, name: Optional[str] = None):
105
+ """
106
+ Decorator to wrap a function as a Datalys2 task.
107
+ Usage:
108
+ @task
109
+ def my_func(): ...
110
+
111
+ @task(name="MyCustomTask")
112
+ def my_func(): ...
113
+ """
114
+ if func is None:
115
+ return functools.partial(task, name=name)
116
+ return TaskWrapper(func, task_name=name)
@@ -0,0 +1 @@
1
+ # Core shared modules
@@ -0,0 +1,27 @@
1
+ from pydantic import BaseModel
2
+ import os
3
+ import json
4
+
5
+ class Settings(BaseModel):
6
+ server_host: str = "127.0.0.1"
7
+ server_port: int = 8000
8
+ database_url: str = "" # Set in __init__ or defaulting
9
+
10
+ def __init__(self, **data):
11
+ super().__init__(**data)
12
+ if not self.database_url:
13
+ app_data = os.getenv('APPDATA') or os.path.expanduser('~')
14
+ app_dir = os.path.join(app_data, 'datalys2-tasks')
15
+ os.makedirs(app_dir, exist_ok=True)
16
+ db_path = os.path.join(app_dir, 'datalys2.db')
17
+ self.database_url = f"sqlite:///{db_path}"
18
+
19
+ @classmethod
20
+ def load(cls, config_path: str = "datalys_config.json") -> "Settings":
21
+ if os.path.exists(config_path):
22
+ with open(config_path, "r") as f:
23
+ data = json.load(f)
24
+ return cls(**data)
25
+ return cls()
26
+
27
+ settings = Settings.load()
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+ from typing import List, Optional, Any, Dict
3
+ from pydantic import BaseModel
4
+ from datetime import datetime
5
+
6
+ # Future models can be added here
7
+
@@ -0,0 +1 @@
1
+ from .windows import WindowsTaskScheduler
@@ -0,0 +1,139 @@
1
+ import sys
2
+ import os
3
+ import logging
4
+ from typing import Optional, List
5
+ from .windows import WindowsTaskScheduler
6
+
7
+ # Use a logger instead of print where appropriate, but fallback to print for visibility in CLI usage
8
+ logger = logging.getLogger("datalys2.autorun")
9
+
10
+ def schedule_me(
11
+ name: str,
12
+ frequency: str = "DAILY",
13
+ at: Optional[str] = None,
14
+ interval: Optional[int] = None,
15
+ args: Optional[List[str]] = None,
16
+ overwrite: bool = False
17
+ ) -> bool:
18
+ """
19
+ Automatically schedules the current script as a Windows Task.
20
+
21
+ This function is designed to be the "one-line" setup for your periodic tasks.
22
+ It checks if the task is already scheduled (by name). If not, it creates it.
23
+ If it is, it does nothing (unless `overwrite=True`).
24
+
25
+ It is best placed at the very top of your main execution block.
26
+
27
+ Example:
28
+ >>> if __name__ == "__main__":
29
+ ... from datalys2_tasks.scheduler import autorun
30
+ ... # Run this script every day at 08:30 AM
31
+ ... autorun.schedule_me("daily-report-job", at="08:30")
32
+ ... # ... Rest of your script logic
33
+
34
+ Args:
35
+ name (str):
36
+ A unique name for this task. It will be stored in the Windows Task Scheduler
37
+ under the '\\datalys2\\' folder.
38
+ Example: "sales-report-generator"
39
+
40
+ frequency (str, optional):
41
+ How often the task should run.
42
+ Options:
43
+ - "DAILY": Runs once every day (default).
44
+ - "ONCE": Runs a single time (useful for deferred tasks).
45
+ - "ONLOGON": Runs when the user logs in.
46
+ - "MINUTE": Runs every `interval` minutes.
47
+ - "HOURLY": Runs every hour.
48
+ Defaults to "DAILY".
49
+
50
+ at (str, optional):
51
+ The start time for the schedule in "HH:MM" 24-hour format.
52
+ Required for "DAILY" and "ONCE" if you want a specific time.
53
+ If None, defaults to current time.
54
+ Example: "14:00" for 2:00 PM.
55
+
56
+ interval (int, optional):
57
+ Used when frequency is "MINUTE". Specifies the number of minutes between runs.
58
+ Example: 15 (run every 15 minutes).
59
+
60
+ args (List[str], optional):
61
+ A list of command-line arguments to pass to the script when the scheduler runs it.
62
+ Example: ["--mode", "production", "--verbose"]
63
+
64
+ overwrite (bool, optional):
65
+ If True, forces the task to be updated in the Windows Task Scheduler even if it
66
+ already exists. Use this if you've changed the schedule or arguments.
67
+ Defaults to False (safe mode).
68
+
69
+ Returns:
70
+ bool: True if the task is successfully scheduled (or was already there).
71
+ False if something went wrong during scheduling.
72
+ """
73
+
74
+ # 1. Normalize inputs
75
+ frequency = frequency.upper()
76
+
77
+ # 2. Initialize Scheduler Interface
78
+ scheduler = WindowsTaskScheduler()
79
+
80
+ # 3. Check for existing task
81
+ # The scheduler handles the folder prefix (e.g. \\datalys2\\) internal to query_task
82
+ print(f"✨ [Datalys2] Checking status for task: '{name}'")
83
+ existing_task = scheduler.query_task(name)
84
+
85
+ if existing_task and not overwrite:
86
+ print(f"✅ [Datalys2] Task '{name}' is already scheduled. Continuing execution...")
87
+ return True
88
+
89
+ # 4. Prepare Context
90
+ # We need the absolute path to this script so the scheduler knows what to run.
91
+ # Note: This relies on sys.argv[0] being the script path.
92
+ script_path = os.path.abspath(sys.argv[0])
93
+
94
+ action_verb = "Updating" if existing_task else "Registering"
95
+ print(f"⚙️ [Datalys2] {action_verb} '{name}' to run {frequency}...")
96
+ if at:
97
+ print(f" 🕒 Time: {at}")
98
+ if interval:
99
+ print(f" ⏱️ Interval: {interval} minutes")
100
+
101
+ # 5. Execute Creation/Update
102
+ success = scheduler.create_task(
103
+ task_name=name,
104
+ script_path=script_path,
105
+ schedule=frequency,
106
+ start_time=at,
107
+ interval_minutes=interval,
108
+ args=args,
109
+ force=True # We force here because we've already decided to update/create
110
+ )
111
+
112
+ if success:
113
+ print(f"🚀 [Datalys2] Success! '{name}' is scheduled.")
114
+ else:
115
+ print(f"❌ [Datalys2] Failed to schedule '{name}'. Check permissions or logs.")
116
+
117
+ return success
118
+
119
+ # Alias for backward compatibility
120
+ def ensure_task(
121
+ task_name: str,
122
+ schedule: str = "DAILY",
123
+ start_time: Optional[str] = None,
124
+ interval_minutes: Optional[int] = None,
125
+ script_args: Optional[List[str]] = None,
126
+ force_update: bool = False
127
+ ) -> bool:
128
+ """
129
+ Deprecated alias for `schedule_me`.
130
+ Please use `datalys2_tasks.scheduler.autorun.schedule_me` instead.
131
+ """
132
+ return schedule_me(
133
+ name=task_name,
134
+ frequency=schedule,
135
+ at=start_time,
136
+ interval=interval_minutes,
137
+ args=script_args,
138
+ overwrite=force_update
139
+ )