schd 0.1.0__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.0 → schd-0.1.2}/schd/cmds/daemon.py +3 -5
  5. {schd-0.1.0 → schd-0.1.2}/schd/cmds/schd.py +3 -1
  6. {schd-0.1.0 → schd-0.1.2}/schd/cmds/scsendmail.py +15 -4
  7. {schd-0.1.0 → schd-0.1.2}/schd/config.py +3 -3
  8. {schd-0.1.0 → schd-0.1.2}/schd/scheduler.py +8 -8
  9. {schd-0.1.0 → schd-0.1.2}/schd/schedulers/remote.py +12 -0
  10. schd-0.1.2/schd.egg-info/PKG-INFO +10 -0
  11. {schd-0.1.0 → schd-0.1.2}/schd.egg-info/SOURCES.txt +1 -0
  12. {schd-0.1.0 → schd-0.1.2}/schd.egg-info/entry_points.txt +1 -0
  13. {schd-0.1.0 → schd-0.1.2}/setup.py +1 -1
  14. schd-0.1.0/PKG-INFO +0 -11
  15. schd-0.1.0/schd/__init__.py +0 -1
  16. schd-0.1.0/schd.egg-info/PKG-INFO +0 -11
  17. {schd-0.1.0 → schd-0.1.2}/README.md +0 -0
  18. {schd-0.1.0 → schd-0.1.2}/schd/cmds/__init__.py +0 -0
  19. {schd-0.1.0 → schd-0.1.2}/schd/cmds/base.py +0 -0
  20. {schd-0.1.0 → schd-0.1.2}/schd/cmds/jobs.py +0 -0
  21. {schd-0.1.0 → schd-0.1.2}/schd/cmds/run.py +0 -0
  22. {schd-0.1.0 → schd-0.1.2}/schd/email.py +0 -0
  23. {schd-0.1.0 → schd-0.1.2}/schd/job.py +0 -0
  24. {schd-0.1.0 → schd-0.1.2}/schd/schedulers/__init__.py +0 -0
  25. {schd-0.1.0 → schd-0.1.2}/schd/util.py +0 -0
  26. {schd-0.1.0 → schd-0.1.2}/schd.egg-info/dependency_links.txt +0 -0
  27. {schd-0.1.0 → schd-0.1.2}/schd.egg-info/requires.txt +0 -0
  28. {schd-0.1.0 → schd-0.1.2}/schd.egg-info/top_level.txt +0 -0
  29. {schd-0.1.0 → schd-0.1.2}/setup.cfg +0 -0
  30. {schd-0.1.0 → schd-0.1.2}/tests/test_config.py +0 -0
  31. {schd-0.1.0 → schd-0.1.2}/tests/test_email.py +0 -0
  32. {schd-0.1.0 → schd-0.1.2}/tests/test_scheduler.py +0 -0
  33. {schd-0.1.0 → 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}'")
@@ -8,12 +8,10 @@ from schd import __version__ as schd_version
8
8
 
9
9
  class DaemonCommand(CommandBase):
10
10
  def add_arguments(self, parser):
11
- parser.add_argument('--config', '-c')
12
11
  parser.add_argument('--logfile')
13
12
 
14
- def run(self, args):
15
- config_file = args.config
16
- print(f'starting schd, {schd_version}, config_file={config_file}')
13
+ def run(self, args, config):
14
+ print(f'starting schd, {schd_version}')
17
15
 
18
16
  if args.logfile:
19
17
  log_stream = open(args.logfile, 'a', encoding='utf8')
@@ -23,4 +21,4 @@ class DaemonCommand(CommandBase):
23
21
  log_stream = sys.stdout
24
22
 
25
23
  logging.basicConfig(level=logging.INFO, format='%(asctime)s %(name)s %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', stream=log_stream)
26
- asyncio.run(run_daemon(config_file))
24
+ asyncio.run(run_daemon(config))
@@ -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)
@@ -280,8 +280,7 @@ def build_scheduler(config:SchdConfig):
280
280
  return scheduler
281
281
 
282
282
 
283
- async def run_daemon(config_file=None):
284
- config = read_config(config_file=config_file)
283
+ async def run_daemon(config):
285
284
  scheduler = build_scheduler(config)
286
285
  await scheduler.init()
287
286
 
@@ -329,11 +328,12 @@ async def main():
329
328
  parser.add_argument('--logfile')
330
329
  parser.add_argument('--config', '-c')
331
330
  args = parser.parse_args()
332
- config_file = args.config
333
331
 
334
332
  logging.basicConfig(level=logging.DEBUG)
335
333
 
336
- print(f'starting schd, {schd_version}, config_file={config_file}')
334
+ config = read_config(args.config)
335
+ print(f'starting schd, {schd_version}')
336
+
337
337
 
338
338
  if args.logfile:
339
339
  log_stream = open(args.logfile, 'a', encoding='utf8')
@@ -343,7 +343,7 @@ async def main():
343
343
  log_stream = sys.stdout
344
344
 
345
345
  logging.basicConfig(level=logging.INFO, format='%(asctime)s %(name)s - %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S', stream=log_stream)
346
- await run_daemon(config_file)
346
+ await run_daemon(config)
347
347
 
348
348
 
349
349
  if __name__ == '__main__':
@@ -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.0",
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.0/PKG-INFO DELETED
@@ -1,11 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: schd
3
- Version: 0.1.0
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.0'
@@ -1,11 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: schd
3
- Version: 0.1.0
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