orionis 0.468.0__py3-none-any.whl → 0.470.0__py3-none-any.whl

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.
@@ -1,13 +1,703 @@
1
- from apscheduler.schedulers.background import BackgroundScheduler
2
- from apscheduler.schedulers.blocking import BlockingScheduler
3
- from apscheduler.schedulers.asyncio import AsyncIOScheduler
1
+ from typing import Any, List, Optional
2
+ from apscheduler.schedulers.background import BackgroundScheduler as APSBackgroundScheduler
3
+ from apscheduler.schedulers.blocking import BlockingScheduler as APSBlockingScheduler
4
+ from apscheduler.schedulers.asyncio import AsyncIOScheduler as APSAsyncIOScheduler
4
5
  from apscheduler.triggers.cron import CronTrigger
5
6
  from apscheduler.triggers.date import DateTrigger
6
7
  from apscheduler.triggers.interval import IntervalTrigger
8
+ from orionis.console.contracts.reactor import IReactor
7
9
  from datetime import datetime
8
10
  import pytz
11
+ import asyncio
12
+ from typing import Union
13
+ from orionis.console.exceptions import CLIOrionisRuntimeError
14
+ from orionis.app import Orionis
9
15
 
10
- class Schedule:
16
+ class Scheduler():
11
17
 
12
- def __init__(self):
13
- self.tasks = []
18
+ def __init__(
19
+ self,
20
+ reactor: IReactor
21
+ ) -> None:
22
+ """
23
+ Initialize a new instance of the Scheduler class.
24
+
25
+ This constructor sets up the internal state required for scheduling commands,
26
+ including references to the application instance, APScheduler schedulers, the
27
+ command reactor, and job tracking structures. It also initializes properties
28
+ for managing the current scheduling context.
29
+
30
+ Parameters
31
+ ----------
32
+ reactor : IReactor
33
+ An instance of a class implementing the IReactor interface, used to
34
+ retrieve available commands and execute scheduled jobs.
35
+
36
+ Returns
37
+ -------
38
+ None
39
+ This method does not return any value. It initializes the Scheduler instance.
40
+ """
41
+
42
+ # Store the application instance for configuration access.
43
+ self.__app = Orionis()
44
+
45
+ # Initialize scheduler instances (will be set up later).
46
+ self.__background_scheduler: APSBackgroundScheduler = None
47
+ self.__blocking_scheduler: APSBlockingScheduler = None
48
+ self.__asyncio_scheduler: APSAsyncIOScheduler = None
49
+ self.__initScheduler()
50
+
51
+ # Store the reactor instance for command management.
52
+ self.__reactor = reactor
53
+
54
+ # Retrieve and store all available commands from the reactor.
55
+ self.__available_commands = self.__getCommands()
56
+
57
+ # Dictionary to hold all scheduled jobs and their details.
58
+ self.__jobs: dict = {}
59
+
60
+ # Properties to track the current scheduling context.
61
+ self.__command: str = None # The command signature to be scheduled.
62
+ self.__args: List[str] = None # Arguments for the command.
63
+ self.__purpose: str = None # Purpose or description of the scheduled job.
64
+ self.__type: str = None # Scheduler type (background, blocking, asyncio).
65
+
66
+ def __initScheduler(
67
+ self
68
+ ) -> None:
69
+ """
70
+ Initialize the internal APScheduler instances for background, blocking, and asyncio scheduling.
71
+
72
+ This method creates and configures three types of schedulers:
73
+ - BackgroundScheduler: Runs jobs in the background using threads.
74
+ - BlockingScheduler: Runs jobs in the foreground and blocks the main thread.
75
+ - AsyncIOScheduler: Integrates with asyncio event loops for asynchronous job execution.
76
+
77
+ The timezone for all schedulers is set based on the application's configuration.
78
+
79
+ Returns
80
+ -------
81
+ None
82
+ This method does not return any value. It initializes internal scheduler attributes.
83
+ """
84
+
85
+ # Initialize the BackgroundScheduler with the application's timezone
86
+ self.__background_scheduler = APSBackgroundScheduler(
87
+ timezone=pytz.timezone(self.__app.config('app.timezone', 'UTC'))
88
+ )
89
+
90
+ # Initialize the BlockingScheduler with the application's timezone
91
+ self.__blocking_scheduler = APSBlockingScheduler(
92
+ timezone=pytz.timezone(self.__app.config('app.timezone', 'UTC'))
93
+ )
94
+
95
+ # Initialize the AsyncIOScheduler with the application's timezone
96
+ self.__asyncio_scheduler = APSAsyncIOScheduler(
97
+ timezone=pytz.timezone(self.__app.config('app.timezone', 'UTC'))
98
+ )
99
+
100
+ def __getCommands(
101
+ self
102
+ ) -> dict:
103
+ """
104
+ Retrieve available commands from the reactor and return them as a dictionary.
105
+
106
+ This method queries the reactor for all available jobs/commands, extracting their
107
+ signatures and descriptions. The result is a dictionary where each key is the command
108
+ signature and the value is another dictionary containing the command's signature and
109
+ its description.
110
+
111
+ Returns
112
+ -------
113
+ dict
114
+ A dictionary mapping command signatures to their details. Each value is a dictionary
115
+ with 'signature' and 'description' keys.
116
+ """
117
+
118
+ # Initialize the commands dictionary
119
+ commands = {}
120
+
121
+ # Iterate over all jobs provided by the reactor's info method
122
+ for job in self.__reactor.info():
123
+
124
+ # Store each job's signature and description in the commands dictionary
125
+ commands[job['signature']] = {
126
+ 'signature': job['signature'],
127
+ 'description': job.get('description', '')
128
+ }
129
+
130
+ # Return the commands dictionary
131
+ return commands
132
+
133
+ def background(
134
+ self
135
+ ) -> 'Scheduler':
136
+ """
137
+ Set the scheduler type to 'background' for job scheduling.
138
+
139
+ This method configures the scheduler to use the BackgroundScheduler, which runs jobs in the background using threads.
140
+ It updates the internal type property to indicate that subsequent scheduled jobs should be handled by the background scheduler.
141
+
142
+ Returns
143
+ -------
144
+ Scheduler
145
+ Returns the current instance of the Scheduler to allow method chaining.
146
+ """
147
+
148
+ # Set the scheduler type to 'background'
149
+ self.__type = 'background'
150
+
151
+ # Return self to support method chaining
152
+ return self
153
+
154
+ def blocking(
155
+ self
156
+ ) -> 'Scheduler':
157
+ """
158
+ Set the scheduler type to 'blocking' for job scheduling.
159
+
160
+ This method configures the scheduler to use the BlockingScheduler, which runs jobs in the foreground and blocks the main thread.
161
+ It updates the internal type property so that subsequent scheduled jobs will be handled by the blocking scheduler.
162
+
163
+ Returns
164
+ -------
165
+ Scheduler
166
+ Returns the current instance of the Scheduler to allow method chaining.
167
+ """
168
+
169
+ # Set the scheduler type to 'blocking'
170
+ self.__type = 'blocking'
171
+
172
+ # Return self to support method chaining
173
+ return self
174
+
175
+ def asyncio(
176
+ self
177
+ ) -> 'Scheduler':
178
+ """
179
+ Set the scheduler type to 'asyncio' for job scheduling.
180
+
181
+ This method configures the scheduler to use the AsyncIOScheduler, which integrates with
182
+ asyncio event loops for asynchronous job execution. It updates the internal type property
183
+ so that subsequent scheduled jobs will be handled by the asyncio scheduler.
184
+
185
+ Returns
186
+ -------
187
+ Scheduler
188
+ Returns the current instance of the Scheduler to allow method chaining.
189
+ """
190
+
191
+ # Set the scheduler type to 'asyncio'
192
+ self.__type = 'asyncio'
193
+
194
+ # Return self to support method chaining
195
+ return self
196
+
197
+ def __isAvailable(
198
+ self,
199
+ signature: str
200
+ ) -> bool:
201
+ """
202
+ Check if a command with the given signature is available.
203
+
204
+ This method iterates through the available commands and determines
205
+ whether the provided signature matches any registered command.
206
+
207
+ Parameters
208
+ ----------
209
+ signature : str
210
+ The signature of the command to check for availability.
211
+
212
+ Returns
213
+ -------
214
+ bool
215
+ True if the command with the specified signature exists and is available,
216
+ False otherwise.
217
+ """
218
+
219
+ # Iterate through all available command signatures
220
+ for command in self.__available_commands.keys():
221
+
222
+ # Return True if the signature matches an available command
223
+ if command == signature:
224
+ return True
225
+
226
+ # Return False if the signature is not found among available commands
227
+ return False
228
+
229
+ def __getDescription(
230
+ self,
231
+ signature: str
232
+ ) -> Optional[str]:
233
+ """
234
+ Retrieve the description of a command given its signature.
235
+
236
+ This method looks up the available commands dictionary and returns the description
237
+ associated with the provided command signature. If the signature does not exist,
238
+ it returns None.
239
+
240
+ Parameters
241
+ ----------
242
+ signature : str
243
+ The unique signature identifying the command.
244
+
245
+ Returns
246
+ -------
247
+ Optional[str]
248
+ The description of the command if found; otherwise, None.
249
+ """
250
+
251
+ # Attempt to retrieve the command entry from the available commands dictionary
252
+ command_entry = self.__available_commands.get(signature)
253
+
254
+ # Return the description if the command exists, otherwise return None
255
+ return command_entry['description'] if command_entry else None
256
+
257
+ def __getScheduler(
258
+ self
259
+ ) -> Optional[Union[APSBackgroundScheduler, APSBlockingScheduler, APSAsyncIOScheduler]]:
260
+ """
261
+ Retrieve the appropriate APScheduler instance based on the current scheduler type.
262
+
263
+ This method selects and returns the internal scheduler instance corresponding to the
264
+ type specified by the user (background, blocking, or asyncio). The scheduler type is
265
+ determined by the value of the internal `__type` attribute, which is set using the
266
+ `background()`, `blocking()`, or `asyncio()` methods.
267
+
268
+ Returns
269
+ -------
270
+ Optional[Union[APSBackgroundScheduler, APSBlockingScheduler, APSAsyncIOScheduler]]
271
+ The scheduler instance matching the current type, or None if the type is not set
272
+ or does not match any known scheduler.
273
+ """
274
+
275
+ # Return the BackgroundScheduler if the type is set to 'background'
276
+ if self.__type == 'background':
277
+ return self.__background_scheduler
278
+
279
+ # Return the BlockingScheduler if the type is set to 'blocking'
280
+ elif self.__type == 'blocking':
281
+ return self.__blocking_scheduler
282
+
283
+ # Return the AsyncIOScheduler if the type is set to 'asyncio'
284
+ elif self.__type == 'asyncio':
285
+ return self.__asyncio_scheduler
286
+
287
+ def __reset(
288
+ self
289
+ ) -> None:
290
+ """
291
+ Reset the internal state of the Scheduler instance.
292
+
293
+ This method clears the current command, arguments, purpose, type, trigger,
294
+ start time, and end time attributes, effectively resetting the scheduler's
295
+ configuration to its initial state. This can be useful for preparing the
296
+ scheduler for a new command or job scheduling without retaining any previous
297
+ settings.
298
+
299
+ Returns
300
+ -------
301
+ None
302
+ This method does not return any value. It modifies the internal state of the Scheduler.
303
+ """
304
+
305
+ self.__command = None
306
+ self.__args = None
307
+ self.__purpose = None
308
+ self.__type = None
309
+
310
+ def command(
311
+ self,
312
+ signature: str,
313
+ args: Optional[List[str]] = None
314
+ ) -> 'Scheduler':
315
+ """
316
+ Register a command to be scheduled with the specified signature and optional arguments.
317
+
318
+ This method validates the provided command signature and arguments, checks if the command
319
+ is available in the list of registered commands, and stores the command details internally
320
+ for scheduling. The command's description is also retrieved and stored for reference.
321
+
322
+ Parameters
323
+ ----------
324
+ signature : str
325
+ The unique signature identifying the command to be scheduled. Must be a non-empty string.
326
+ args : Optional[List[str]], optional
327
+ A list of string arguments to be passed to the command. If not provided, an empty list is used.
328
+
329
+ Returns
330
+ -------
331
+ Scheduler
332
+ Returns the current instance of the Scheduler to allow method chaining.
333
+
334
+ Raises
335
+ ------
336
+ ValueError
337
+ If the signature is not a non-empty string, if the arguments are not a list or None,
338
+ or if the command signature is not available among registered commands.
339
+ """
340
+
341
+ # Validate that the command signature is a non-empty string
342
+ if not isinstance(signature, str) or not signature.strip():
343
+ raise ValueError("Command signature must be a non-empty string.")
344
+
345
+ # Ensure that arguments are either a list of strings or None
346
+ if args is not None and not isinstance(args, list):
347
+ raise ValueError("Arguments must be a list of strings or None.")
348
+
349
+ # Check if the command is available in the registered commands
350
+ if not self.__isAvailable(signature):
351
+ raise ValueError(f"The command '{signature}' is not available or does not exist.")
352
+
353
+ # Store the command signature
354
+ self.__command = signature
355
+
356
+ # If purpose is not already set, retrieve and set the command's description
357
+ if self.__purpose is None:
358
+ self.__purpose = self.__getDescription(signature)
359
+
360
+ # Store the provided arguments or default to an empty list
361
+ self.__args = args if args is not None else []
362
+
363
+ # Return self to support method chaining
364
+ return self
365
+
366
+ def purpose(
367
+ self,
368
+ purpose: str
369
+ ) -> 'Scheduler':
370
+ """
371
+ Set the purpose or description for the scheduled command.
372
+
373
+ This method assigns a human-readable purpose or description to the command
374
+ that is being scheduled. The purpose must be a non-empty string. This can
375
+ be useful for documentation, logging, or displaying information about the
376
+ scheduled job.
377
+
378
+ Parameters
379
+ ----------
380
+ purpose : str
381
+ The purpose or description to associate with the scheduled command.
382
+ Must be a non-empty string.
383
+
384
+ Returns
385
+ -------
386
+ Scheduler
387
+ Returns the current instance of the Scheduler to allow method chaining.
388
+
389
+ Raises
390
+ ------
391
+ ValueError
392
+ If the provided purpose is not a non-empty string.
393
+ """
394
+
395
+ # Validate that the purpose is a non-empty string
396
+ if not isinstance(purpose, str) or not purpose.strip():
397
+ raise ValueError("The purpose must be a non-empty string.")
398
+
399
+ # Set the internal purpose attribute
400
+ self.__purpose = purpose
401
+
402
+ # Return self to support method chaining
403
+ return self
404
+
405
+ def onceAt(
406
+ self,
407
+ date: datetime
408
+ ) -> bool:
409
+ """
410
+ Schedule a command to run once at a specific date and time.
411
+
412
+ This method schedules the currently registered command to execute exactly once at the
413
+ specified datetime. If no scheduler type has been set, it defaults to using the background
414
+ scheduler. The job is registered internally and added to the appropriate APScheduler instance.
415
+
416
+ Parameters
417
+ ----------
418
+ date : datetime.datetime
419
+ The date and time at which the command should be executed. Must be a valid `datetime` instance.
420
+
421
+ Returns
422
+ -------
423
+ bool
424
+ Returns True if the job was successfully scheduled.
425
+
426
+ Raises
427
+ ------
428
+ CLIOrionisRuntimeError
429
+ If the provided date is not a `datetime` instance, if the scheduler type is not defined,
430
+ or if there is an error while scheduling the job.
431
+ """
432
+
433
+ try:
434
+
435
+ # Ensure the provided date is a valid datetime instance.
436
+ if not isinstance(date, datetime):
437
+ raise CLIOrionisRuntimeError(
438
+ "The date must be an instance of datetime."
439
+ )
440
+
441
+ # If no scheduler type is set, default to background scheduler.
442
+ if self.__type is None:
443
+ self.background()
444
+
445
+ # Register the job details internally.
446
+ self.__jobs[self.__command] = {
447
+ 'signature': self.__command,
448
+ 'args': self.__args,
449
+ 'purpose': self.__purpose,
450
+ 'type': self.__type,
451
+ 'trigger': 'once_at',
452
+ 'start_at': date.strftime('%Y-%m-%d %H:%M:%S'),
453
+ 'end_at': date.strftime('%Y-%m-%d %H:%M:%S')
454
+ }
455
+
456
+ # Retrieve the appropriate scheduler instance.
457
+ scheduler = self.__getScheduler()
458
+
459
+ # Raise an error if the scheduler is not defined.
460
+ if scheduler is None:
461
+ raise CLIOrionisRuntimeError("No scheduler type has been defined.")
462
+
463
+ # Add the job to the scheduler.
464
+ scheduler.add_job(
465
+ func= lambda command=self.__command, args=list(self.__args): self.__reactor.call(
466
+ command,
467
+ args
468
+ ),
469
+ trigger=DateTrigger(
470
+ run_date=date
471
+ ),
472
+ id=self.__command,
473
+ name=self.__command,
474
+ replace_existing=True
475
+ )
476
+
477
+ # Reset the internal state for future scheduling.
478
+ self.__reset()
479
+
480
+ # Return True to indicate successful scheduling.
481
+ return True
482
+
483
+ except Exception as e:
484
+
485
+ # Reraise known CLIOrionisRuntimeError exceptions.
486
+ if isinstance(e, CLIOrionisRuntimeError):
487
+ raise e
488
+
489
+ # Wrap and raise any other exceptions as CLIOrionisRuntimeError.
490
+ raise CLIOrionisRuntimeError(f"Error scheduling the job: {str(e)}")
491
+
492
+ def start(self) -> None:
493
+ """
494
+ Start all internal APScheduler instances (AsyncIO, Background, and Blocking).
495
+
496
+ This method initiates the three scheduler types managed by this Scheduler instance:
497
+ - AsyncIOScheduler: Integrates with asyncio event loops for asynchronous job execution.
498
+ - BackgroundScheduler: Runs jobs in the background using threads.
499
+ - BlockingScheduler: Runs jobs in the foreground and blocks the main thread.
500
+
501
+ Each scheduler is started, allowing scheduled jobs to be executed according to their triggers.
502
+
503
+ Returns
504
+ -------
505
+ None
506
+ This method does not return any value. It starts all configured schedulers.
507
+ """
508
+
509
+ # Start the AsyncIOScheduler to handle asynchronous jobs.
510
+ # Only start if there's an event loop running or we can create one
511
+ try:
512
+ asyncio.get_running_loop()
513
+ self.__asyncio_scheduler.start()
514
+ except RuntimeError:
515
+ # No event loop is running, AsyncIOScheduler won't be started
516
+ # This is normal for non-asyncio environments
517
+ pass
518
+
519
+ # Start the BackgroundScheduler to handle background jobs.
520
+ self.__background_scheduler.start()
521
+
522
+ # Start the BlockingScheduler to handle blocking jobs.
523
+ self.__blocking_scheduler.start()
524
+
525
+ def shutdown(self, wait=True) -> None:
526
+ """
527
+ Shut down all internal APScheduler instances (AsyncIO, Background, and Blocking).
528
+
529
+ This method gracefully stops the three scheduler types managed by this Scheduler instance:
530
+ - AsyncIOScheduler: Handles asynchronous job execution.
531
+ - BackgroundScheduler: Runs jobs in the background using threads.
532
+ - BlockingScheduler: Runs jobs in the foreground and blocks the main thread.
533
+
534
+ Parameters
535
+ ----------
536
+ wait : bool, optional
537
+ If True, the method will wait until all currently executing jobs are completed before shutting down the schedulers.
538
+ If False, the schedulers will be shut down immediately without waiting for running jobs to finish. Default is True.
539
+
540
+ Returns
541
+ -------
542
+ None
543
+ This method does not return any value. It shuts down all configured schedulers.
544
+ """
545
+
546
+ # Validate that the wait parameter is a boolean.
547
+ if not isinstance(wait, bool):
548
+ raise ValueError("The 'wait' parameter must be a boolean value.")
549
+
550
+ # Shut down the AsyncIOScheduler, waiting for jobs if specified.
551
+ try:
552
+ if self.__asyncio_scheduler.running:
553
+ self.__asyncio_scheduler.shutdown(wait=wait)
554
+ except Exception:
555
+ # AsyncIOScheduler may not be running or may have issues in shutdown
556
+ pass
557
+
558
+ # Shut down the BackgroundScheduler, waiting for jobs if specified.
559
+ if self.__background_scheduler.running:
560
+ self.__background_scheduler.shutdown(wait=wait)
561
+
562
+ # Shut down the BlockingScheduler, waiting for jobs if specified.
563
+ if self.__blocking_scheduler.running:
564
+ self.__blocking_scheduler.shutdown(wait=wait)
565
+
566
+ def remove(self, signature:str) -> None:
567
+ """
568
+ Remove a scheduled job from all internal APScheduler instances.
569
+
570
+ This method attempts to remove a job with the specified job ID from each of the
571
+ managed schedulers: AsyncIOScheduler, BackgroundScheduler, and BlockingScheduler.
572
+ If the job does not exist in a particular scheduler, that scheduler will ignore
573
+ the removal request without raising an error.
574
+
575
+ Parameters
576
+ ----------
577
+ signature : str
578
+ The unique identifier of the job to be removed from the schedulers.
579
+
580
+ Returns
581
+ -------
582
+ None
583
+ This method does not return any value. It removes the job from all schedulers if present.
584
+ """
585
+
586
+ # Validate that the job signature is a non-empty string.
587
+ if not isinstance(signature, str) or not signature.strip():
588
+ raise ValueError("Job signature must be a non-empty string.")
589
+
590
+ # Remove the job from the AsyncIOScheduler, if it exists.
591
+ try:
592
+ self.__asyncio_scheduler.remove_job(signature)
593
+ except Exception:
594
+ # Job may not exist in this scheduler, continue with others
595
+ pass
596
+
597
+ # Remove the job from the BackgroundScheduler, if it exists.
598
+ try:
599
+ self.__background_scheduler.remove_job(signature)
600
+ except Exception:
601
+ # Job may not exist in this scheduler, continue with others
602
+ pass
603
+
604
+ # Remove the job from the BlockingScheduler, if it exists.
605
+ try:
606
+ self.__blocking_scheduler.remove_job(signature)
607
+ except Exception:
608
+ # Job may not exist in this scheduler, ignore
609
+ pass
610
+
611
+ def jobs(self) -> dict:
612
+ """
613
+ Retrieve all scheduled jobs currently managed by the Scheduler.
614
+
615
+ This method returns a dictionary containing information about all jobs that have been
616
+ registered and scheduled through this Scheduler instance. Each entry in the dictionary
617
+ represents a scheduled job, where the key is the command signature and the value is a
618
+ dictionary with details such as the signature, arguments, purpose, type, trigger, start time,
619
+ and end time.
620
+
621
+ Returns
622
+ -------
623
+ dict
624
+ A dictionary mapping command signatures to their corresponding job details. Each value
625
+ is a dictionary containing information about the scheduled job.
626
+ """
627
+
628
+ # Return the internal dictionary holding all scheduled jobs and their details.
629
+ return self.__jobs
630
+
631
+ def start_asyncio_scheduler(self) -> bool:
632
+ """
633
+ Start the AsyncIOScheduler specifically.
634
+
635
+ This method attempts to start only the AsyncIOScheduler. It's useful when you need
636
+ to start the asyncio scheduler separately or when working in an asyncio environment.
637
+
638
+ Returns
639
+ -------
640
+ bool
641
+ True if the AsyncIOScheduler was started successfully, False otherwise.
642
+ """
643
+
644
+ try:
645
+ # Check if we're in an asyncio environment
646
+ asyncio.get_running_loop()
647
+ if not self.__asyncio_scheduler.running:
648
+ self.__asyncio_scheduler.start()
649
+ return True
650
+ except RuntimeError:
651
+ # No event loop is running
652
+ return False
653
+ except Exception:
654
+ # Other errors
655
+ return False
656
+
657
+ async def start_asyncio_scheduler_async(self) -> bool:
658
+ """
659
+ Start the AsyncIOScheduler in an async context.
660
+
661
+ This method is designed to be called from async functions and ensures
662
+ the AsyncIOScheduler is properly started within an asyncio event loop.
663
+
664
+ Returns
665
+ -------
666
+ bool
667
+ True if the AsyncIOScheduler was started successfully, False otherwise.
668
+ """
669
+
670
+ try:
671
+ if not self.__asyncio_scheduler.running:
672
+ self.__asyncio_scheduler.start()
673
+ return True
674
+ except Exception:
675
+ return False
676
+
677
+ def is_asyncio_scheduler_running(self) -> bool:
678
+ """
679
+ Check if the AsyncIOScheduler is currently running.
680
+
681
+ Returns
682
+ -------
683
+ bool
684
+ True if the AsyncIOScheduler is running, False otherwise.
685
+ """
686
+
687
+ return self.__asyncio_scheduler.running if self.__asyncio_scheduler else False
688
+
689
+ def get_scheduler_status(self) -> dict:
690
+ """
691
+ Get the status of all schedulers.
692
+
693
+ Returns
694
+ -------
695
+ dict
696
+ A dictionary with the running status of each scheduler type.
697
+ """
698
+
699
+ return {
700
+ 'asyncio': self.__asyncio_scheduler.running if self.__asyncio_scheduler else False,
701
+ 'background': self.__background_scheduler.running if self.__background_scheduler else False,
702
+ 'blocking': self.__blocking_scheduler.running if self.__blocking_scheduler else False
703
+ }
@@ -103,6 +103,7 @@ class App(BaseEntity):
103
103
  )
104
104
 
105
105
  timezone: str = field(
106
+ # default_factory = lambda: Env.get('APP_TIMEZONE', 'UTC'),
106
107
  default_factory = lambda: Env.get('APP_TIMEZONE', 'UTC'),
107
108
  metadata = {
108
109
  "description": "The timezone of the application. Defaults to 'UTC'.",
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.468.0"
8
+ VERSION = "0.470.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.468.0
3
+ Version: 0.470.0
4
4
  Summary: Orionis Framework – Elegant, Fast, and Powerful.
5
5
  Home-page: https://github.com/orionis-framework/framework
6
6
  Author: Raul Mauricio Uñate Castro
@@ -45,7 +45,7 @@ orionis/console/output/contracts/executor.py,sha256=7l3kwnvv6GlH9EYk0v94YE1olex_
45
45
  orionis/console/output/enums/__init__.py,sha256=LAaAxg-DpArCjf_jqZ0_9s3p8899gntDYkSU_ppTdC8,66
46
46
  orionis/console/output/enums/styles.py,sha256=6a4oQCOBOKMh2ARdeq5GlIskJ3wjiylYmh66tUKKmpQ,4053
47
47
  orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- orionis/console/tasks/schedule.py,sha256=vtWUIMYoSA9lSiVjSkhuknKo-Zii63RL4BEeHe-zngg,465
48
+ orionis/console/tasks/schedule.py,sha256=ANRuPRRd-znbMD5fcPNgKAv69XOECWod7mugF5_dt0U,26636
49
49
  orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  orionis/container/container.py,sha256=MmvFm0Y-x667mIYPunmBnHzQHBsWJObT5_zuWrgqaWU,80528
51
51
  orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -83,7 +83,7 @@ orionis/foundation/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
83
83
  orionis/foundation/config/startup.py,sha256=vbzduprRCNyYeR2nnMaqc1uKXw6PTzAY2jVfXNQKN8I,9691
84
84
  orionis/foundation/config/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
85
  orionis/foundation/config/app/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
- orionis/foundation/config/app/entities/app.py,sha256=TVom0M_wRpw2Jqan8E_JgQAruSifRyRhVh8xD7GJmvI,10202
86
+ orionis/foundation/config/app/entities/app.py,sha256=K2dbHhxRNtp454-M5pGBzSpLOBu8tLaDv_iwxuwbR3g,10271
87
87
  orionis/foundation/config/app/enums/__init__.py,sha256=L0csn3OmlPT4Y4WhTSI2uQRua0Z367MxNs12AcSHsV4,120
88
88
  orionis/foundation/config/app/enums/ciphers.py,sha256=N9qdLw47ug9FslHFckP8Sz7MfDN74zujZLh37mtLzW8,1249
89
89
  orionis/foundation/config/app/enums/environments.py,sha256=W81oUasW__nRDiyhScMfaBpQ65RXkAAvRGd4ShDFTvE,409
@@ -190,7 +190,7 @@ orionis/foundation/providers/reactor_provider.py,sha256=P0KQcp4AFKTrD6BStGfCTqhG
190
190
  orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
191
191
  orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
192
192
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
193
- orionis/metadata/framework.py,sha256=y8zYrSr2J93iX-mXugOlY-VvgCRyEaEoXNQoSIfvqOA,4109
193
+ orionis/metadata/framework.py,sha256=GN5YICH6x7kPf0sNqbd0Rcqz3V2YozrT9UqvC6NtpzQ,4109
194
194
  orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
195
195
  orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
196
196
  orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -356,7 +356,7 @@ orionis/test/validators/web_report.py,sha256=n9BfzOZz6aEiNTypXcwuWbFRG0OdHNSmCNu
356
356
  orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnIfJYgc,1206
357
357
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
358
358
  orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
359
- orionis-0.468.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
359
+ orionis-0.470.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
360
360
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
361
361
  tests/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
362
362
  tests/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -499,8 +499,8 @@ tests/testing/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
499
499
  tests/testing/validators/test_testing_validators.py,sha256=WPo5GxTP6xE-Dw3X1vZoqOMpb6HhokjNSbgDsDRDvy4,16588
500
500
  tests/testing/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
501
501
  tests/testing/view/test_render.py,sha256=tnnMBwS0iKUIbogLvu-7Rii50G6Koddp3XT4wgdFEYM,1050
502
- orionis-0.468.0.dist-info/METADATA,sha256=u92htNWIwtYydVacPKdIMkMNxmWNdmDdiziM4KkKKEY,4801
503
- orionis-0.468.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
504
- orionis-0.468.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
505
- orionis-0.468.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
506
- orionis-0.468.0.dist-info/RECORD,,
502
+ orionis-0.470.0.dist-info/METADATA,sha256=EoWf7FtN4Tx2TZUaF82iMV6_fJSz5qV4PKPmvEc6tH4,4801
503
+ orionis-0.470.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
504
+ orionis-0.470.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
505
+ orionis-0.470.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
506
+ orionis-0.470.0.dist-info/RECORD,,