schd 0.1.1__tar.gz → 0.1.2__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.
Files changed (33) hide show
  1. schd-0.1.2/PKG-INFO +10 -0
  2. schd-0.1.2/schd/__init__.py +1 -0
  3. schd-0.1.2/schd/cmds/addtrigger.py +34 -0
  4. {schd-0.1.1 → schd-0.1.2}/schd/cmds/schd.py +3 -1
  5. {schd-0.1.1 → schd-0.1.2}/schd/cmds/scsendmail.py +15 -4
  6. {schd-0.1.1 → schd-0.1.2}/schd/config.py +3 -3
  7. {schd-0.1.1 → schd-0.1.2}/schd/scheduler.py +3 -3
  8. {schd-0.1.1 → schd-0.1.2}/schd/schedulers/remote.py +12 -0
  9. schd-0.1.2/schd.egg-info/PKG-INFO +10 -0
  10. {schd-0.1.1 → schd-0.1.2}/schd.egg-info/SOURCES.txt +1 -0
  11. {schd-0.1.1 → schd-0.1.2}/schd.egg-info/entry_points.txt +1 -0
  12. {schd-0.1.1 → schd-0.1.2}/setup.py +1 -1
  13. schd-0.1.1/PKG-INFO +0 -11
  14. schd-0.1.1/schd/__init__.py +0 -1
  15. schd-0.1.1/schd.egg-info/PKG-INFO +0 -11
  16. {schd-0.1.1 → schd-0.1.2}/README.md +0 -0
  17. {schd-0.1.1 → schd-0.1.2}/schd/cmds/__init__.py +0 -0
  18. {schd-0.1.1 → schd-0.1.2}/schd/cmds/base.py +0 -0
  19. {schd-0.1.1 → schd-0.1.2}/schd/cmds/daemon.py +0 -0
  20. {schd-0.1.1 → schd-0.1.2}/schd/cmds/jobs.py +0 -0
  21. {schd-0.1.1 → schd-0.1.2}/schd/cmds/run.py +0 -0
  22. {schd-0.1.1 → schd-0.1.2}/schd/email.py +0 -0
  23. {schd-0.1.1 → schd-0.1.2}/schd/job.py +0 -0
  24. {schd-0.1.1 → schd-0.1.2}/schd/schedulers/__init__.py +0 -0
  25. {schd-0.1.1 → schd-0.1.2}/schd/util.py +0 -0
  26. {schd-0.1.1 → schd-0.1.2}/schd.egg-info/dependency_links.txt +0 -0
  27. {schd-0.1.1 → schd-0.1.2}/schd.egg-info/requires.txt +0 -0
  28. {schd-0.1.1 → schd-0.1.2}/schd.egg-info/top_level.txt +0 -0
  29. {schd-0.1.1 → schd-0.1.2}/setup.cfg +0 -0
  30. {schd-0.1.1 → schd-0.1.2}/tests/test_config.py +0 -0
  31. {schd-0.1.1 → schd-0.1.2}/tests/test_email.py +0 -0
  32. {schd-0.1.1 → schd-0.1.2}/tests/test_scheduler.py +0 -0
  33. {schd-0.1.1 → schd-0.1.2}/tests/test_util.py +0 -0
schd-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 1.0
2
+ Name: schd
3
+ Version: 0.1.2
4
+ Summary: UNKNOWN
5
+ Home-page: https://github.com/kevenli/schd
6
+ Author: UNKNOWN
7
+ Author-email: UNKNOWN
8
+ License: ApacheV2
9
+ Description: UNKNOWN
10
+ Platform: UNKNOWN
@@ -0,0 +1 @@
1
+ __version__ = '0.1.2'
@@ -0,0 +1,34 @@
1
+ import asyncio
2
+ import logging
3
+ import sys
4
+ from .base import CommandBase
5
+ from schd.schedulers.remote import RemoteApiClient
6
+ from schd.config import SchdConfig
7
+
8
+
9
+ class AddTriggerCommand(CommandBase):
10
+ def add_arguments(self, parser):
11
+ parser.add_argument('--base-url', type=str, required=False, help='Base URL of the remote scheduler API')
12
+ parser.add_argument('--worker-name', type=str, required=False, help='Name of the worker to register')
13
+ parser.add_argument('--job-name', type=str, required=True, help='Name of the job to register')
14
+ parser.add_argument('--on-worker-name', type=str, required=False, help='Name of the worker to register')
15
+ parser.add_argument('--on-job-name', type=str, required=True, help='Name of the job to register')
16
+ parser.add_argument('--on-job-status', type=str, required=True, help='Status of the job to register')
17
+
18
+ def run(self, args, config:SchdConfig=None):
19
+ remote_url = args.base_url or config.scheduler_remote_host
20
+ client = RemoteApiClient(remote_url)
21
+ worker_name = args.worker_name or config.worker_name
22
+ job_name = args.job_name
23
+ # if on_worker_name is not provided, use current worker name
24
+ on_worker_name = args.on_worker_name or worker_name
25
+ on_job_name = args.on_job_name
26
+ on_job_status = args.on_job_status
27
+ asyncio.run(client.add_trigger(
28
+ worker_name=worker_name,
29
+ job_name=job_name,
30
+ on_worker_name=on_worker_name,
31
+ on_job_name=on_job_name,
32
+ on_job_status=on_job_status,
33
+ ))
34
+ logging.info(f"Trigger added successfully for job '{job_name}'")
@@ -5,12 +5,14 @@ from schd.config import ConfigFileNotFound, read_config
5
5
  from schd import __version__ as schd_version
6
6
  from .daemon import DaemonCommand
7
7
  from .run import RunCommand
8
+ from .addtrigger import AddTriggerCommand
8
9
 
9
10
 
10
11
  commands = {
11
12
  'daemon': DaemonCommand(),
12
13
  'run': RunCommand(),
13
14
  'jobs': JobsCommand(),
15
+ 'addtrigger': AddTriggerCommand(),
14
16
  }
15
17
 
16
18
  def main():
@@ -18,7 +20,7 @@ def main():
18
20
  parser = argparse.ArgumentParser('schd')
19
21
  parser.add_argument('--version', action='store_true', default=False)
20
22
  parser.add_argument('--config')
21
- sub_command_parsers = parser.add_subparsers(dest='cmd')
23
+ sub_command_parsers = parser.add_subparsers(dest='cmd', help='sub commands')
22
24
 
23
25
  for cmd, cmd_obj in commands.items():
24
26
  sub_command_parser = sub_command_parsers.add_parser(cmd)
@@ -53,11 +53,22 @@ def main():
53
53
  sys.exit(1)
54
54
 
55
55
  # Load config from environment or config file
56
- schd_config = read_config(args.config)
57
- logging.debug(schd_config.email)
58
- service = EmailService.from_config(schd_config.email)
56
+ try:
57
+ schd_config = read_config(args.config)
58
+ email_config = schd_config.email
59
+ except ConfigFileNotFound:
60
+ if args.config:
61
+ print(f"Config file not found: {args.config}", file=sys.stderr)
62
+ return sys.exit(1)
63
+
64
+ logging.warning("No config file found, using default email config")
65
+ # Use default email config if no config file is provided
66
+ email_config = EmailConfig.from_dict({})
67
+
68
+ logging.debug(email_config)
69
+ service = EmailService.from_config(email_config)
59
70
 
60
- to_emails = parse_recipients(args.recipients)
71
+ to_emails = parse_recipients(args.recipients) or [email_config.to_addr]
61
72
  cc_emails = parse_recipients(args.cc)
62
73
  bcc_emails = parse_recipients(args.bcc)
63
74
  attachments = args.attachments or []
@@ -120,9 +120,9 @@ class JobConfig(ConfigValue):
120
120
  @dataclass
121
121
  class SchdConfig(ConfigValue):
122
122
  jobs: Dict[str, JobConfig] = field(default_factory=dict)
123
- scheduler_cls: str = 'LocalScheduler'
124
- scheduler_remote_host: Optional[str] = None
125
- worker_name: str = 'local'
123
+ scheduler_cls: str = field(metadata={'env_var': 'SCHD_SCHEDULER_CLS'}, default='LocalScheduler')
124
+ scheduler_remote_host: Optional[str] = field(metadata={'env_var': 'SCHD_SCHEDULER_REMOTE_HOST'}, default=None)
125
+ worker_name: str = field(metadata={'env_var': 'SCHD_WORKER_NAME'}, default='local')
126
126
  email: EmailConfig = field(default_factory=lambda: EmailConfig.from_dict({}))
127
127
 
128
128
  def __getitem__(self,key):
@@ -262,16 +262,16 @@ class LocalScheduler:
262
262
 
263
263
 
264
264
  def build_scheduler(config:SchdConfig):
265
- scheduler_cls = os.environ.get('SCHD_SCHEDULER_CLS') or config.scheduler_cls
265
+ scheduler_cls = config.scheduler_cls
266
266
 
267
267
  if scheduler_cls == 'LocalScheduler':
268
268
  scheduler = LocalScheduler(config)
269
269
  elif scheduler_cls == 'RemoteScheduler':
270
270
  logger.info('scheduler_cls: %s', scheduler_cls)
271
- scheduler_remote_host = os.environ.get('SCHD_SCHEDULER_REMOTE_HOST') or config.scheduler_remote_host
271
+ scheduler_remote_host = config.scheduler_remote_host
272
272
  assert scheduler_remote_host, 'scheduler_remote_host cannot be none'
273
273
  logger.info('scheduler_remote_host: %s ', scheduler_remote_host)
274
- worker_name = os.environ.get('SCHD_WORKER_NAME') or config.worker_name
274
+ worker_name = config.worker_name
275
275
  assert worker_name, 'worker_name cannot be none'
276
276
  logger.info('worker_name: %s ', worker_name)
277
277
  scheduler = RemoteScheduler(worker_name=worker_name, remote_host=scheduler_remote_host)
@@ -79,6 +79,18 @@ class RemoteApiClient:
79
79
  logger.info("Status: %d", resp.status)
80
80
  logger.info("Response: %s", await resp.text())
81
81
 
82
+ async def add_trigger(self, worker_name, job_name, on_job_name, on_worker_name=None, on_job_status='ALL'):
83
+ url = urljoin(self._base_url, f'/api/workers/{worker_name}/jobs/{job_name}/triggers')
84
+ async with aiohttp.ClientSession() as session:
85
+ post_data={
86
+ 'on_job_name': on_job_name,
87
+ 'on_worker_name': on_worker_name,
88
+ 'on_job_status': on_job_status
89
+ }
90
+ async with session.post(url, json=post_data) as response:
91
+ response.raise_for_status()
92
+ result = await response.json()
93
+ return result
82
94
 
83
95
  class RemoteScheduler:
84
96
  def __init__(self, worker_name:str, remote_host:str):
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 1.0
2
+ Name: schd
3
+ Version: 0.1.2
4
+ Summary: UNKNOWN
5
+ Home-page: https://github.com/kevenli/schd
6
+ Author: UNKNOWN
7
+ Author-email: UNKNOWN
8
+ License: ApacheV2
9
+ Description: UNKNOWN
10
+ Platform: UNKNOWN
@@ -14,6 +14,7 @@ schd.egg-info/entry_points.txt
14
14
  schd.egg-info/requires.txt
15
15
  schd.egg-info/top_level.txt
16
16
  schd/cmds/__init__.py
17
+ schd/cmds/addtrigger.py
17
18
  schd/cmds/base.py
18
19
  schd/cmds/daemon.py
19
20
  schd/cmds/jobs.py
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
2
  schd = schd.cmds.schd:main
3
3
  scsendmail = schd.cmds.scsendmail:main
4
+
@@ -7,7 +7,7 @@ def read_requirements():
7
7
 
8
8
  setup(
9
9
  name="schd",
10
- version="0.1.1",
10
+ version="0.1.2",
11
11
  url="https://github.com/kevenli/schd",
12
12
  packages=find_packages(exclude=('tests', 'tests.*')),
13
13
  install_requires=['apscheduler<4.0', 'pyaml', 'aiohttp'],
schd-0.1.1/PKG-INFO DELETED
@@ -1,11 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: schd
3
- Version: 0.1.1
4
- Home-page: https://github.com/kevenli/schd
5
- License: ApacheV2
6
- Requires-Dist: apscheduler<4.0
7
- Requires-Dist: pyaml
8
- Requires-Dist: aiohttp
9
- Dynamic: home-page
10
- Dynamic: license
11
- Dynamic: requires-dist
@@ -1 +0,0 @@
1
- __version__ = '0.1.1'
@@ -1,11 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: schd
3
- Version: 0.1.1
4
- Home-page: https://github.com/kevenli/schd
5
- License: ApacheV2
6
- Requires-Dist: apscheduler<4.0
7
- Requires-Dist: pyaml
8
- Requires-Dist: aiohttp
9
- Dynamic: home-page
10
- Dynamic: license
11
- Dynamic: requires-dist
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes