orionis 0.475.0__py3-none-any.whl → 0.476.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,57 +1,110 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import List, Optional
2
+ from typing import Any, List, Optional
3
3
 
4
4
  class IReactor(ABC):
5
5
 
6
+ @abstractmethod
7
+ def info(self) -> List[dict]:
8
+ """
9
+ Retrieves a list of all registered commands with their metadata.
10
+
11
+ This method returns a list of dictionaries, each containing information about
12
+ a registered command, including its signature, description, and whether it has
13
+ timestamps enabled. This is useful for introspection and displaying available
14
+ commands to the user.
15
+
16
+ Returns
17
+ -------
18
+ List[dict]
19
+ A list of dictionaries representing the registered commands, where each dictionary
20
+ contains the command's signature, description, and timestamps status.
21
+ """
22
+ pass
23
+
6
24
  @abstractmethod
7
25
  def call(
8
26
  self,
9
27
  signature: str,
10
28
  args: Optional[List[str]] = None
11
- ):
29
+ ) -> Optional[Any]:
12
30
  """
13
- Executes a command by its signature with optional command-line arguments.
31
+ Executes a registered command synchronously by its signature, optionally passing command-line arguments.
14
32
 
15
- This method retrieves a registered command by its signature, validates any provided
16
- arguments against the command's argument parser, and executes the command's handle
17
- method with the parsed arguments and application context.
33
+ This method retrieves a command from the internal registry using its unique signature,
34
+ validates and parses any provided arguments using the command's argument parser,
35
+ and then executes the command's `handle` method synchronously. It manages execution timing,
36
+ logging, and error handling, and returns any output produced by the command.
18
37
 
19
38
  Parameters
20
39
  ----------
21
40
  signature : str
22
41
  The unique signature identifier of the command to execute.
23
42
  args : Optional[List[str]], default None
24
- Command-line arguments to pass to the command. If None, no arguments are provided.
43
+ List of command-line arguments to pass to the command. If None, no arguments are provided.
25
44
 
26
45
  Returns
27
46
  -------
28
- None
29
- This method does not return any value. The command's handle method is called
30
- directly for execution.
47
+ Optional[Any]
48
+ The output produced by the command's `handle` method if execution is successful.
49
+ Returns None if the command does not produce a result or if an error occurs.
31
50
 
32
51
  Raises
33
52
  ------
34
- ValueError
53
+ CLIOrionisValueError
35
54
  If the command with the specified signature is not found in the registry.
36
55
  SystemExit
37
- If argument parsing fails due to invalid arguments provided.
56
+ If argument parsing fails due to invalid arguments provided (raised by argparse).
57
+ Exception
58
+ Propagates any exception raised during command execution after logging and error output.
59
+
60
+ Notes
61
+ -----
62
+ - Logs execution start, completion, and errors with timestamps if enabled.
63
+ - Handles argument parsing and injects parsed arguments into the command instance.
64
+ - All exceptions are logged and displayed in the console.
38
65
  """
39
66
  pass
40
67
 
41
68
  @abstractmethod
42
- def info(self) -> List[dict]:
69
+ async def callAsync(
70
+ self,
71
+ signature: str,
72
+ args: Optional[List[str]] = None
73
+ ) -> Optional[Any]:
43
74
  """
44
- Retrieves a list of all registered commands with their metadata.
75
+ Executes a registered command asynchronously by its signature, optionally passing command-line arguments.
45
76
 
46
- This method returns a list of dictionaries, each containing information about
47
- a registered command, including its signature, description, and whether it has
48
- timestamps enabled. This is useful for introspection and displaying available
49
- commands to the user.
77
+ This method locates a command in the internal registry using its unique signature,
78
+ validates and parses any provided arguments using the command's argument parser,
79
+ and then executes the command's `handle` method asynchronously. It manages execution timing,
80
+ logging, and error handling, and returns any output produced by the command.
81
+
82
+ Parameters
83
+ ----------
84
+ signature : str
85
+ The unique signature identifier of the command to execute.
86
+ args : Optional[List[str]], default None
87
+ List of command-line arguments to pass to the command. If None, no arguments are provided.
50
88
 
51
89
  Returns
52
90
  -------
53
- List[dict]
54
- A list of dictionaries representing the registered commands, where each dictionary
55
- contains the command's signature, description, and timestamps status.
91
+ Optional[Any]
92
+ The output produced by the command's `handle` method if execution is successful.
93
+ Returns None if the command does not produce a result or if an error occurs.
94
+
95
+ Raises
96
+ ------
97
+ CLIOrionisValueError
98
+ If the command with the specified signature is not found in the registry.
99
+ SystemExit
100
+ If argument parsing fails due to invalid arguments provided (raised by argparse).
101
+ Exception
102
+ Propagates any exception raised during command execution after logging and error output.
103
+
104
+ Notes
105
+ -----
106
+ - Logs execution start, completion, and errors with timestamps if enabled.
107
+ - Handles argument parsing and injects parsed arguments into the command instance.
108
+ - All exceptions are logged and displayed in the console.
56
109
  """
57
110
  pass
@@ -1,19 +1,21 @@
1
1
  import argparse
2
2
  import os
3
3
  import re
4
- import time
5
4
  from pathlib import Path
6
- from typing import List, Optional
5
+ from typing import Any, List, Optional
7
6
  from orionis.app import Orionis
8
7
  from orionis.console.args.argument import CLIArgument
9
8
  from orionis.console.base.command import BaseCommand
10
9
  from orionis.console.base.contracts.command import IBaseCommand
11
10
  from orionis.console.contracts.reactor import IReactor
11
+ from orionis.console.enums.command import Command
12
+ from orionis.console.exceptions import CLIOrionisValueError
12
13
  from orionis.console.output.contracts.console import IConsole
13
14
  from orionis.console.output.contracts.executor import IExecutor
14
15
  from orionis.foundation.contracts.application import IApplication
15
16
  from orionis.services.introspection.modules.reflection import ReflectionModule
16
17
  from orionis.services.log.contracts.log_service import ILogger
18
+ from orionis.support.performance.contracts.counter import IPerformanceCounter
17
19
 
18
20
  class Reactor(IReactor):
19
21
 
@@ -60,7 +62,7 @@ class Reactor(IReactor):
60
62
  self.__root: str = str(Path.cwd())
61
63
 
62
64
  # Initialize the internal command registry as an empty dictionary
63
- self.__commands: dict = {}
65
+ self.__commands: dict[str, Command] = {}
64
66
 
65
67
  # Automatically discover and load command classes from the console commands directory
66
68
  self.__loadCommands(str(self.__app.path('console_commands')), self.__root)
@@ -77,6 +79,9 @@ class Reactor(IReactor):
77
79
  # Initialize the logger service for logging command execution details
78
80
  self.__logger: ILogger = self.__app.make('x-orionis.services.log.log_service')
79
81
 
82
+ # Initialize the performance counter for measuring command execution time
83
+ self.__performance_counter: IPerformanceCounter = self.__app.make('x-orionis.support.performance.counter')
84
+
80
85
  def __loadCoreCommands(self) -> None:
81
86
  """
82
87
  Loads and registers core command classes provided by the Orionis framework.
@@ -127,13 +132,13 @@ class Reactor(IReactor):
127
132
  args = self.__ensureArguments(obj)
128
133
 
129
134
  # Register the command in the internal registry with all its metadata
130
- self.__commands[signature] = {
131
- "class": obj,
132
- "timestamps": timestamp,
133
- "signature": signature,
134
- "description": description,
135
- "args": args
136
- }
135
+ self.__commands[signature] = Command(
136
+ obj=obj,
137
+ timestamps=timestamp,
138
+ signature=signature,
139
+ description=description,
140
+ args=args
141
+ )
137
142
 
138
143
  def __loadCommands(self, commands_path: str, root_path: str) -> None:
139
144
  """
@@ -208,13 +213,13 @@ class Reactor(IReactor):
208
213
  args = self.__ensureArguments(obj)
209
214
 
210
215
  # Add the command to the internal registry
211
- self.__commands[signature] = {
212
- "class": obj,
213
- "timestamps": timestamp,
214
- "signature": signature,
215
- "description": description,
216
- "args": args
217
- }
216
+ self.__commands[signature] = Command(
217
+ obj=obj,
218
+ timestamps=timestamp,
219
+ signature=signature,
220
+ description=description,
221
+ args=args
222
+ )
218
223
 
219
224
  def __ensureTimestamps(self, obj: IBaseCommand) -> bool:
220
225
  """
@@ -403,6 +408,61 @@ class Reactor(IReactor):
403
408
  # Return the configured ArgumentParser
404
409
  return arg_parser
405
410
 
411
+ def __parseArgs(
412
+ self,
413
+ command: Command,
414
+ args: Optional[List[str]] = None
415
+ ) -> dict:
416
+ """
417
+ Parses command-line arguments for a given command using its internal ArgumentParser.
418
+
419
+ This method takes a command object and an optional list of command-line arguments,
420
+ and parses them into a dictionary of argument names and values. If the command
421
+ defines an ArgumentParser (i.e., expects arguments), the arguments are parsed
422
+ accordingly. If no arguments are expected or provided, an empty dictionary is returned.
423
+
424
+ Parameters
425
+ ----------
426
+ command : Command
427
+ The command object containing the argument parser and metadata.
428
+ args : Optional[List[str]], default None
429
+ A list of command-line arguments to parse. If None, an empty list is used.
430
+
431
+ Returns
432
+ -------
433
+ dict
434
+ A dictionary containing the parsed argument names and their corresponding values.
435
+ Returns an empty dictionary if no arguments are expected or provided.
436
+
437
+ Raises
438
+ ------
439
+ SystemExit
440
+ Raised by argparse if argument parsing fails or if help is requested.
441
+ """
442
+
443
+ # Initialize parsed_args to None
444
+ parsed_args = None
445
+
446
+ # If the command expects arguments, parse them using its ArgumentParser
447
+ if command.args is not None and isinstance(command.args, argparse.ArgumentParser):
448
+ if args is None:
449
+ args = []
450
+ try:
451
+ # Parse the provided arguments using the command's ArgumentParser
452
+ parsed_args = command.args.parse_args(args)
453
+ except SystemExit:
454
+ # Allow argparse to handle help/error messages and exit
455
+ raise
456
+
457
+ # Convert the parsed arguments to a dictionary and return
458
+ if isinstance(parsed_args, argparse.Namespace):
459
+ return vars(parsed_args)
460
+ elif isinstance(parsed_args, dict):
461
+ return parsed_args
462
+ else:
463
+ # Return an empty dictionary if no arguments were parsed
464
+ return {}
465
+
406
466
  def info(self) -> List[dict]:
407
467
  """
408
468
  Retrieves a list of all registered commands with their metadata.
@@ -426,8 +486,8 @@ class Reactor(IReactor):
426
486
  for command in self.__commands.values():
427
487
 
428
488
  # Extract command metadata
429
- signature:str = command.get("signature")
430
- description:str = command.get("description", "")
489
+ signature:str = command.signature
490
+ description:str = command.description
431
491
 
432
492
  # Skip internal commands (those with double underscores)
433
493
  if signature.startswith('__') and signature.endswith('__'):
@@ -446,103 +506,179 @@ class Reactor(IReactor):
446
506
  self,
447
507
  signature: str,
448
508
  args: Optional[List[str]] = None
449
- ):
509
+ ) -> Optional[Any]:
450
510
  """
451
- Executes a command by its signature with optional command-line arguments.
511
+ Executes a registered command synchronously by its signature, optionally passing command-line arguments.
452
512
 
453
- This method retrieves a registered command by its signature, validates any provided
454
- arguments against the command's argument parser, and executes the command's handle
455
- method with the parsed arguments and application context.
513
+ This method retrieves a command from the internal registry using its unique signature,
514
+ validates and parses any provided arguments using the command's argument parser,
515
+ and then executes the command's `handle` method synchronously. It manages execution timing,
516
+ logging, and error handling, and returns any output produced by the command.
456
517
 
457
518
  Parameters
458
519
  ----------
459
520
  signature : str
460
521
  The unique signature identifier of the command to execute.
461
522
  args : Optional[List[str]], default None
462
- Command-line arguments to pass to the command. If None, no arguments are provided.
523
+ List of command-line arguments to pass to the command. If None, no arguments are provided.
463
524
 
464
525
  Returns
465
526
  -------
466
- None
467
- This method does not return any value. The command's handle method is called
468
- directly for execution.
527
+ Optional[Any]
528
+ The output produced by the command's `handle` method if execution is successful.
529
+ Returns None if the command does not produce a result or if an error occurs.
469
530
 
470
531
  Raises
471
532
  ------
472
- ValueError
533
+ CLIOrionisValueError
473
534
  If the command with the specified signature is not found in the registry.
474
535
  SystemExit
475
- If argument parsing fails due to invalid arguments provided.
536
+ If argument parsing fails due to invalid arguments provided (raised by argparse).
537
+ Exception
538
+ Propagates any exception raised during command execution after logging and error output.
539
+
540
+ Notes
541
+ -----
542
+ - Logs execution start, completion, and errors with timestamps if enabled.
543
+ - Handles argument parsing and injects parsed arguments into the command instance.
544
+ - All exceptions are logged and displayed in the console.
476
545
  """
477
546
 
478
- # Retrieve the command from the registry
479
- command: dict = self.__commands.get(signature)
547
+ # Retrieve the command from the registry by its signature
548
+ command: Command = self.__commands.get(signature)
480
549
  if command is None:
481
- raise ValueError(f"Command '{signature}' not found.")
550
+ raise CLIOrionisValueError(f"Command '{signature}' not found.")
482
551
 
483
- # Start execution timer
484
- start_time = time.perf_counter()
552
+ # Start execution timer for performance measurement
553
+ self.__performance_counter.start()
485
554
 
486
- # Get command details
487
- command_class = command.get("class")
488
- arg_parser: Optional[argparse.ArgumentParser] = command.get("args")
489
- timestamps: bool = command.get("timestamps")
555
+ # Log the command execution start with RUNNING state if timestamps are enabled
556
+ if command.timestamps:
557
+ self.__executer.running(program=signature)
490
558
 
491
- # Initialize parsed arguments
492
- parsed_args = None
559
+ try:
560
+ # Instantiate the command class using the application container
561
+ command_instance: IBaseCommand = self.__app.make(command.obj)
493
562
 
494
- # If the command has arguments and args were provided, validate them
495
- if arg_parser is not None and isinstance(arg_parser, argparse.ArgumentParser):
496
- if args is None:
497
- args = []
498
- try:
499
- # Parse the provided arguments using the command's ArgumentParser
500
- parsed_args = arg_parser.parse_args(args)
501
- except SystemExit:
502
- # Re-raise SystemExit to allow argparse to handle help/error messages
503
- raise
563
+ # Inject parsed arguments into the command instance
564
+ command_instance._args = self.__parseArgs(command, args)
504
565
 
505
- # Log the command execution start with RUNNING state
506
- if timestamps:
566
+ # Execute the command's handle method and capture its output
567
+ output = self.__app.call(command_instance, 'handle')
568
+
569
+ # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
570
+ elapsed_time = round(self.__performance_counter.stop(), 2)
571
+ if command.timestamps:
572
+ self.__executer.done(program=signature, time=f"{elapsed_time}s")
573
+
574
+ # Log successful execution in the logger service
575
+ self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
576
+
577
+ # Return the output produced by the command, if any
578
+ return output
579
+
580
+ except Exception as e:
581
+ # Display the error message in the console (without timestamp)
582
+ self.__console.error(f"An error occurred while executing command '{signature}': {e}", timestamp=False)
583
+
584
+ # Log the error in the logger service
585
+ self.__logger.error(f"Command '{signature}' execution failed: {e}")
586
+
587
+ # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
588
+ elapsed_time = round(self.__performance_counter.stop(), 2)
589
+ if command.timestamps:
590
+ self.__executer.fail(program=signature, time=f"{elapsed_time}s")
591
+
592
+ # Propagate the exception after logging
593
+ raise
594
+
595
+ async def callAsync(
596
+ self,
597
+ signature: str,
598
+ args: Optional[List[str]] = None
599
+ ) -> Optional[Any]:
600
+ """
601
+ Executes a registered command asynchronously by its signature, optionally passing command-line arguments.
602
+
603
+ This method locates a command in the internal registry using its unique signature,
604
+ validates and parses any provided arguments using the command's argument parser,
605
+ and then executes the command's `handle` method asynchronously. It manages execution timing,
606
+ logging, and error handling, and returns any output produced by the command.
607
+
608
+ Parameters
609
+ ----------
610
+ signature : str
611
+ The unique signature identifier of the command to execute.
612
+ args : Optional[List[str]], default None
613
+ List of command-line arguments to pass to the command. If None, no arguments are provided.
614
+
615
+ Returns
616
+ -------
617
+ Optional[Any]
618
+ The output produced by the command's `handle` method if execution is successful.
619
+ Returns None if the command does not produce a result or if an error occurs.
620
+
621
+ Raises
622
+ ------
623
+ CLIOrionisValueError
624
+ If the command with the specified signature is not found in the registry.
625
+ SystemExit
626
+ If argument parsing fails due to invalid arguments provided (raised by argparse).
627
+ Exception
628
+ Propagates any exception raised during command execution after logging and error output.
629
+
630
+ Notes
631
+ -----
632
+ - Logs execution start, completion, and errors with timestamps if enabled.
633
+ - Handles argument parsing and injects parsed arguments into the command instance.
634
+ - All exceptions are logged and displayed in the console.
635
+ """
636
+
637
+ # Retrieve the command from the registry by its signature
638
+ command: Command = self.__commands.get(signature)
639
+ if command is None:
640
+ raise CLIOrionisValueError(f"Command '{signature}' not found.")
641
+
642
+ # Start execution timer for performance measurement
643
+ self.__performance_counter.start()
644
+
645
+ # Log the command execution start with RUNNING state if timestamps are enabled
646
+ if command.timestamps:
507
647
  self.__executer.running(program=signature)
508
648
 
509
649
  try:
650
+ # Instantiate the command class using the application container
651
+ command_instance: IBaseCommand = self.__app.make(command.obj)
510
652
 
511
- # Create an instance of the command class and execute it
512
- command_instance: IBaseCommand = self.__app.make(command_class)
653
+ # Inject parsed arguments into the command instance
654
+ command_instance._args = self.__parseArgs(command, args)
513
655
 
514
- # If arguments were parsed, set them on the command instance
515
- if isinstance(parsed_args, argparse.Namespace):
516
- command_instance._args = vars(parsed_args)
517
- elif isinstance(parsed_args, dict):
518
- command_instance._args = parsed_args
519
- else:
520
- command_instance._args = {}
656
+ # Execute the command's handle method asynchronously and capture its output
657
+ output = await self.__app.callAsync(command_instance, 'handle')
521
658
 
522
- # Call the handle method of the command instance
523
- output = self.__app.call(command_instance, 'handle')
524
-
525
- # Log the command execution completion with DONE state
526
- elapsed_time = round(time.perf_counter() - start_time, 2)
527
- if timestamps:
659
+ # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
660
+ elapsed_time = round(self.__performance_counter.stop(), 2)
661
+ if command.timestamps:
528
662
  self.__executer.done(program=signature, time=f"{elapsed_time}s")
529
663
 
530
- # Log the command execution success
664
+ # Log successful execution in the logger service
531
665
  self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
532
666
 
533
- # If the command has a return value or output, return it
534
- if output is not None:
535
- return output
667
+ # Return the output produced by the command, if any
668
+ return output
536
669
 
537
670
  except Exception as e:
538
671
 
539
- # Display the error message in the console
672
+ # Display the error message in the console (without timestamp)
540
673
  self.__console.error(f"An error occurred while executing command '{signature}': {e}", timestamp=False)
541
674
 
542
675
  # Log the error in the logger service
543
676
  self.__logger.error(f"Command '{signature}' execution failed: {e}")
544
677
 
545
- # Log the command execution failure with ERROR state
546
- elapsed_time = round(time.perf_counter() - start_time, 2)
547
- if timestamps:
548
- self.__executer.fail(program=signature, time=f"{elapsed_time}s")
678
+ # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
679
+ elapsed_time = round(self.__performance_counter.stop(), 2)
680
+ if command.timestamps:
681
+ self.__executer.fail(program=signature, time=f"{elapsed_time}s")
682
+
683
+ # Propagate the exception after logging
684
+ raise
File without changes
@@ -0,0 +1,43 @@
1
+ import argparse
2
+ from dataclasses import dataclass
3
+ from typing import Type, Optional
4
+ from orionis.support.entities.base import BaseEntity
5
+
6
+ @dataclass(kw_only=True)
7
+ class Command(BaseEntity):
8
+ """
9
+ Represents a console command and its associated metadata.
10
+
11
+ Parameters
12
+ ----------
13
+ obj : Type
14
+ The type or class associated with the command.
15
+ timestamps : bool
16
+ Whether timestamps are enabled for this command.
17
+ signature : str
18
+ The signature string representing the command usage.
19
+ description : str
20
+ A brief description of what the command does.
21
+ args : Optional[argparse.ArgumentParser], optional
22
+ Optional argument parser for command-line arguments.
23
+
24
+ Returns
25
+ -------
26
+ Command
27
+ An instance of the Command class containing metadata and configuration for a console command.
28
+ """
29
+
30
+ # The type or class associated with the command
31
+ obj: Type
32
+
33
+ # Indicates if timestamps are enabled for this command
34
+ timestamps: bool
35
+
36
+ # The command usage signature
37
+ signature: str
38
+
39
+ # Description of the command's purpose
40
+ description: str
41
+
42
+ # Optional argument parser for command-line arguments
43
+ args: Optional[argparse.ArgumentParser] = None
@@ -0,0 +1,42 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Optional
3
+ from orionis.support.entities.base import BaseEntity
4
+
5
+ @dataclass(kw_only=True)
6
+ class Task(BaseEntity):
7
+ """
8
+ Represents a task entity containing metadata for execution and description.
9
+
10
+ Parameters
11
+ ----------
12
+ signature : str
13
+ The unique identifier or signature of the task.
14
+ args : Optional[List[str]], optional
15
+ List of arguments required by the task, by default None.
16
+ purpose : str, optional
17
+ Brief description of the task's purpose, by default None.
18
+ trigger : str, optional
19
+ Event or condition that triggers the task, by default None.
20
+ details : str, optional
21
+ Additional details or information about the task, by default None.
22
+
23
+ Returns
24
+ -------
25
+ Task
26
+ An instance of the Task class with the specified metadata.
27
+ """
28
+
29
+ # Unique identifier for the task
30
+ signature: str
31
+
32
+ # List of arguments required by the task (optional)
33
+ args: Optional[List[str]] = None
34
+
35
+ # Brief description of the task's purpose (optional)
36
+ purpose: str = None
37
+
38
+ # Event or condition that triggers the task (optional)
39
+ trigger: str = None
40
+
41
+ # Additional details or information about the task (optional)
42
+ details: str = None
@@ -9,7 +9,9 @@ from apscheduler.triggers.date import DateTrigger
9
9
  from apscheduler.triggers.interval import IntervalTrigger
10
10
  from orionis.app import Orionis
11
11
  from orionis.console.contracts.reactor import IReactor
12
+ from orionis.console.enums.task import Task
12
13
  from orionis.console.exceptions import CLIOrionisRuntimeError
14
+ from orionis.console.exceptions.cli_orionis_value_error import CLIOrionisValueError
13
15
  from orionis.services.log.contracts.log_service import ILogger
14
16
 
15
17
  class Scheduler():
@@ -316,14 +318,13 @@ class Scheduler():
316
318
  )
317
319
 
318
320
  # Register the job details internally.
319
- self.__jobs[self.__command] = {
320
- 'signature': self.__command,
321
- 'args': self.__args,
322
- 'purpose': self.__purpose,
323
- 'trigger': 'once_at',
324
- 'start_at': date.strftime('%Y-%m-%d %H:%M:%S'),
325
- 'end_at': date.strftime('%Y-%m-%d %H:%M:%S')
326
- }
321
+ self.__jobs[self.__command] = Task(
322
+ signature=self.__command,
323
+ args=self.__args,
324
+ purpose=self.__purpose,
325
+ trigger='once_at',
326
+ details=f"Date: {date.strftime('%Y-%m-%d %H:%M:%S')}, Timezone: {str(date.tzinfo) if date.tzinfo else 'UTC'}"
327
+ )
327
328
 
328
329
  # Add the job to the scheduler.
329
330
  self.__scheduler.add_job(
@@ -359,6 +360,74 @@ class Scheduler():
359
360
  # Wrap and raise any other exceptions as CLIOrionisRuntimeError.
360
361
  raise CLIOrionisRuntimeError(f"Error scheduling the job: {str(e)}")
361
362
 
363
+ def everySeconds(
364
+ self,
365
+ seconds: int
366
+ ) -> 'Scheduler':
367
+ """
368
+ Schedule a command to run at regular intervals in seconds.
369
+
370
+ This method sets the interval for the currently registered command to execute
371
+ every specified number of seconds. The job is registered internally and added
372
+ to the scheduler instance.
373
+
374
+ Parameters
375
+ ----------
376
+ seconds : int
377
+ The interval in seconds at which the command should be executed. Must be a positive integer.
378
+
379
+ Returns
380
+ -------
381
+ Scheduler
382
+ Returns the current instance of the Scheduler to allow method chaining.
383
+
384
+ Raises
385
+ ------
386
+ ValueError
387
+ If the provided seconds is not a positive integer.
388
+ """
389
+
390
+ try:
391
+
392
+ # Validate that the seconds parameter is a positive integer.
393
+ if not isinstance(seconds, int) or seconds <= 0:
394
+ raise CLIOrionisValueError("The interval must be a positive integer.")
395
+
396
+ # Store the interval in the jobs dictionary.
397
+ self.__jobs[self.__command] = Task(
398
+ signature=self.__command,
399
+ args=self.__args,
400
+ purpose=self.__purpose,
401
+ trigger='every_seconds',
402
+ details=f"Interval: {seconds} seconds"
403
+ )
404
+
405
+ # Add the job to the scheduler with an interval trigger.
406
+ self.__scheduler.add_job(
407
+ func=lambda command=self.__command, args=list(self.__args): self.__reactor.call(
408
+ command,
409
+ args
410
+ ),
411
+ trigger=IntervalTrigger(
412
+ seconds=seconds
413
+ ),
414
+ id=self.__command,
415
+ name=self.__command,
416
+ replace_existing=True
417
+ )
418
+
419
+ # Return self to support method chaining.
420
+ return self
421
+
422
+ except Exception as e:
423
+
424
+ # Reraise known CLIOrionisValueError exceptions.
425
+ if isinstance(e, CLIOrionisValueError):
426
+ raise e
427
+
428
+ # Wrap and raise any other exceptions as CLIOrionisRuntimeError.
429
+ raise CLIOrionisRuntimeError(f"Error scheduling the job: {str(e)}")
430
+
362
431
  async def start(self) -> None:
363
432
  """
364
433
  Start the AsyncIO scheduler instance and keep it running.
@@ -419,4 +419,33 @@ class IContainer(ABC):
419
419
  Any
420
420
  The result of the method call.
421
421
  """
422
- pass
422
+ pass
423
+
424
+ @abstractmethod
425
+ async def callAsync(
426
+ self,
427
+ instance: Any,
428
+ method_name: str,
429
+ *args,
430
+ **kwargs
431
+ ) -> Any:
432
+ """
433
+ Async version of call for when you're in an async context and need to await the result.
434
+
435
+ Parameters
436
+ ----------
437
+ instance : Any
438
+ The instance on which to call the method.
439
+ method_name : str
440
+ The name of the method to call.
441
+ *args : tuple
442
+ Positional arguments to pass to the method.
443
+ **kwargs : dict
444
+ Keyword arguments to pass to the method.
445
+
446
+ Returns
447
+ -------
448
+ Any
449
+ The result of the method call, properly awaited if async.
450
+ """
451
+ pass
@@ -180,6 +180,7 @@ class Application(Container, IApplication):
180
180
  from orionis.foundation.providers.inspirational_provider import InspirationalProvider
181
181
  from orionis.foundation.providers.executor_provider import ConsoleExecuteProvider
182
182
  from orionis.foundation.providers.reactor_provider import ReactorProvider
183
+ from orionis.foundation.providers.performance_counter_provider import PerformanceCounterProvider
183
184
 
184
185
  # Core framework providers
185
186
  core_providers = [
@@ -191,7 +192,8 @@ class Application(Container, IApplication):
191
192
  TestingProvider,
192
193
  InspirationalProvider,
193
194
  ConsoleExecuteProvider,
194
- ReactorProvider
195
+ ReactorProvider,
196
+ PerformanceCounterProvider
195
197
  ]
196
198
 
197
199
  # Register each core provider
@@ -0,0 +1,64 @@
1
+ from orionis.container.providers.service_provider import ServiceProvider
2
+ from orionis.support.performance.contracts.counter import IPerformanceCounter
3
+ from orionis.support.performance.counter import PerformanceCounter
4
+
5
+ class PerformanceCounterProvider(ServiceProvider):
6
+
7
+ def register(self) -> None:
8
+ """
9
+ Registers the performance counter service as a transient dependency in the application container.
10
+
11
+ This method binds the `IPerformanceCounter` interface contract to the `PerformanceCounter`
12
+ concrete implementation within the application's dependency injection container. The binding
13
+ is configured with a transient lifetime, ensuring that each resolution of the service yields
14
+ a new instance of `PerformanceCounter`. This approach is suitable for scenarios requiring
15
+ independent timing or measurement operations across different parts of the application.
16
+
17
+ Additionally, an alias `"x-orionis.support.performance.counter"` is assigned to this binding,
18
+ allowing for alternative resolution or referencing of the service.
19
+
20
+ Parameters
21
+ ----------
22
+ None
23
+
24
+ Returns
25
+ -------
26
+ None
27
+ This method performs service registration as a side effect and does not return any value.
28
+
29
+ Notes
30
+ -----
31
+ - The transient lifetime ensures isolation between different consumers of the service.
32
+ - The alias facilitates flexible service resolution by name.
33
+ """
34
+
35
+ # Register the IPerformanceCounter interface to the PerformanceCounter implementation
36
+ # with a transient lifetime and assign an alias for alternative resolution.
37
+ self.app.transient(IPerformanceCounter, PerformanceCounter, alias="x-orionis.support.performance.counter")
38
+
39
+ def boot(self) -> None:
40
+ """
41
+ Performs initialization and configuration tasks for the performance counter provider during the application's bootstrapping phase.
42
+
43
+ This method is automatically invoked when the provider is loaded by the application. It is intended for setting up or registering
44
+ any performance counters or related resources required by the application. By default, this implementation does not perform any
45
+ actions, but it can be extended in subclasses to include custom initialization logic as needed.
46
+
47
+ Parameters
48
+ ----------
49
+ None
50
+
51
+ Returns
52
+ -------
53
+ None
54
+ This method does not return any value. It executes initialization logic as a side effect.
55
+
56
+ Notes
57
+ -----
58
+ - Override this method in subclasses to implement custom bootstrapping behavior for performance counters.
59
+ - This method is part of the provider lifecycle and is called after service registration.
60
+ """
61
+
62
+ # No initialization logic is required by default.
63
+ # Override this method in subclasses to perform custom setup.
64
+ pass
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.475.0"
8
+ VERSION = "0.476.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
File without changes
File without changes
@@ -0,0 +1,40 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class IPerformanceCounter(ABC):
4
+ """
5
+ A class for measuring the elapsed time between two points in code execution.
6
+
7
+ This class provides methods to start and stop a high-resolution performance counter,
8
+ allowing users to measure the duration of specific code segments with precision.
9
+ """
10
+
11
+ @abstractmethod
12
+ def start(self) -> float:
13
+ """
14
+ Start the performance counter.
15
+
16
+ Records the current high-resolution time as the start time using
17
+ `time.perf_counter()`. This marks the beginning of the interval to be measured.
18
+
19
+ Returns
20
+ -------
21
+ float
22
+ The timestamp (in fractional seconds) at which the counter was started.
23
+ """
24
+ pass
25
+
26
+ @abstractmethod
27
+ def stop(self) -> float:
28
+ """
29
+ Stop the performance counter and calculate the elapsed time.
30
+
31
+ Records the current high-resolution time as the end time and computes
32
+ the elapsed time since `start()` was called. The elapsed time is the
33
+ difference between the end and start timestamps.
34
+
35
+ Returns
36
+ -------
37
+ float
38
+ The elapsed time in seconds (as a float) between when `start()` and `stop()` were called.
39
+ """
40
+ pass
@@ -0,0 +1,87 @@
1
+ import time
2
+ from orionis.support.performance.contracts.counter import IPerformanceCounter
3
+
4
+ class PerformanceCounter(IPerformanceCounter):
5
+ """
6
+ A class for measuring the elapsed time between two points in code execution.
7
+
8
+ This class provides methods to start and stop a high-resolution performance counter,
9
+ allowing users to measure the duration of specific code segments with precision.
10
+
11
+ Attributes
12
+ ----------
13
+ __start_time : float or None
14
+ The timestamp when the counter was started.
15
+ __end_time : float or None
16
+ The timestamp when the counter was stopped.
17
+
18
+ Methods
19
+ -------
20
+ start()
21
+ Starts the performance counter.
22
+ stop()
23
+ Stops the performance counter and returns the elapsed time.
24
+
25
+ Notes
26
+ -----
27
+ The counter uses `time.perf_counter()` for high-resolution timing.
28
+ """
29
+
30
+ def __init__(self):
31
+ """
32
+ Initialize a new PerformanceCounter instance.
33
+
34
+ This constructor sets the internal start and end time attributes to None,
35
+ preparing the counter for use. The counter can then be started and stopped
36
+ to measure elapsed time between two points in code execution.
37
+
38
+ Attributes
39
+ ----------
40
+ __start_time : float or None
41
+ The timestamp when the counter is started, or None if not started.
42
+ __end_time : float or None
43
+ The timestamp when the counter is stopped, or None if not stopped.
44
+ """
45
+
46
+ # Time when the counter is started; initialized to None
47
+ self.__start_time = None
48
+
49
+ # Time when the counter is stopped; initialized to None
50
+ self.__end_time = None
51
+
52
+ def start(self) -> float:
53
+ """
54
+ Start the performance counter.
55
+
56
+ Records the current high-resolution time as the start time using
57
+ `time.perf_counter()`. This marks the beginning of the interval to be measured.
58
+
59
+ Returns
60
+ -------
61
+ float
62
+ The timestamp (in fractional seconds) at which the counter was started.
63
+ """
64
+
65
+ # Record the current time as the start time
66
+ self.__start_time = time.perf_counter()
67
+ return self.__start_time
68
+
69
+ def stop(self) -> float:
70
+ """
71
+ Stop the performance counter and calculate the elapsed time.
72
+
73
+ Records the current high-resolution time as the end time and computes
74
+ the elapsed time since `start()` was called. The elapsed time is the
75
+ difference between the end and start timestamps.
76
+
77
+ Returns
78
+ -------
79
+ float
80
+ The elapsed time in seconds (as a float) between when `start()` and `stop()` were called.
81
+ """
82
+
83
+ # Record the current time as the end time
84
+ self.__end_time = time.perf_counter()
85
+
86
+ # Calculate and return the elapsed time
87
+ return self.__end_time - self.__start_time
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.475.0
3
+ Version: 0.476.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
@@ -19,10 +19,10 @@ orionis/console/commands/version.py,sha256=SUuNDJ40f2uq69OQUmPQXJKaa9Bm_iVRDPmBd
19
19
  orionis/console/commands/workflow.py,sha256=NYOmjTSvm2o6AE4h9LSTZMFSYPQreNmEJtronyOxaYk,2451
20
20
  orionis/console/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  orionis/console/contracts/kernel.py,sha256=mh4LlhEYHh3FuGZZQ0GBhD6ZLa5YQvaNj2r01IIHI5Y,826
22
- orionis/console/contracts/reactor.py,sha256=GGhWSNYBE6E_W3HNEi4kjiDwqohsa-nnwJfoC1nJPM8,1998
22
+ orionis/console/contracts/reactor.py,sha256=Xeq7Zrw6WE5MV_XOQfiQEchAFbb6-0TjLpjWOxYW--g,4554
23
23
  orionis/console/contracts/schedule.py,sha256=A7yYPjPmRizDHOR9k4qvY3NuRPrWBmNuQs6ENGXWtBs,70
24
24
  orionis/console/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- orionis/console/core/reactor.py,sha256=A0koFZaizrK9R1jlFbx9zdf9UZ4tBxSRJY04hcGzbsQ,23571
25
+ orionis/console/core/reactor.py,sha256=Hd7T-jNG_tzhpJXRztjDSKCtm7-3LOh5lcQ__cIchMk,30172
26
26
  orionis/console/dumper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  orionis/console/dumper/dump.py,sha256=CATERiQ6XuIrKQsDaWcVxzTtlAJI9qLJX44fQxEX8ws,22443
28
28
  orionis/console/dumper/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -31,6 +31,9 @@ orionis/console/dynamic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
31
31
  orionis/console/dynamic/progress_bar.py,sha256=iK1kAf9vJIgk6BbdlGvlJkGc1m7Ck4euNqQpg5aarW8,2880
32
32
  orionis/console/dynamic/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  orionis/console/dynamic/contracts/progress_bar.py,sha256=NYebL2h-vg2t2H6IhJjuC37gglRkpT-MW71wbJtpLNg,1784
34
+ orionis/console/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
+ orionis/console/enums/command.py,sha256=lCfVp2vnDojJN2gjdVxE_XU3mRjZZgOIxPfBVQYo9w4,1278
36
+ orionis/console/enums/task.py,sha256=1oRR_VKfzsojCxxywYAMhpPvZQ8kSEEdXeXvCOfAXmg,1322
34
37
  orionis/console/exceptions/__init__.py,sha256=0qlHNuHMVZO87M-rP8lThUUyljRM1jSFNikaxSCjSbw,366
35
38
  orionis/console/exceptions/cli_exception.py,sha256=HsZ_vSeNiJWQ0gznVFNcIdhM0Bj_vkSRVBJs0wMjEKY,1141
36
39
  orionis/console/exceptions/cli_orionis_value_error.py,sha256=RQP0HRwxDG8hxFOT1kUoZ1Ab1CZ1KLoSIl5yqlmgG4M,1147
@@ -45,14 +48,14 @@ orionis/console/output/contracts/executor.py,sha256=7l3kwnvv6GlH9EYk0v94YE1olex_
45
48
  orionis/console/output/enums/__init__.py,sha256=LAaAxg-DpArCjf_jqZ0_9s3p8899gntDYkSU_ppTdC8,66
46
49
  orionis/console/output/enums/styles.py,sha256=6a4oQCOBOKMh2ARdeq5GlIskJ3wjiylYmh66tUKKmpQ,4053
47
50
  orionis/console/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- orionis/console/tasks/schedule.py,sha256=w3S4uZUg6i0EMze4P1B761pl57da2ZdWJFj_SEasarI,18939
51
+ orionis/console/tasks/schedule.py,sha256=DFso4ia8G3me2H1tOX366dXhucIKd-LRH8c-kfJ8fhA,21395
49
52
  orionis/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
53
  orionis/container/container.py,sha256=p7kJ-hwnDattTWCArt0ypol4bW3M334hIZ2FAQhID-w,87570
51
54
  orionis/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
55
  orionis/container/context/manager.py,sha256=I08K_jKXSKmrq18Pv33qYyMKIlAovVOwIgmfiVm-J7c,2971
53
56
  orionis/container/context/scope.py,sha256=p_oCzR7dDz-5ZAd16ab4vfLc3gBf34CaN0f4iR9D0bQ,1155
54
57
  orionis/container/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- orionis/container/contracts/container.py,sha256=JUj5LuJBzSWCsv4tRNreUBXPGCMyK79ITx-RM_rKxTA,13442
58
+ orionis/container/contracts/container.py,sha256=l-wVi6KMLL4I55JSHnNqykiaZSZO9ea6BDSzCKsysak,14217
56
59
  orionis/container/contracts/service_provider.py,sha256=TJtwFoPYvw3hvBSfIEO3-httq8iszaRQh1IjCKfDyVM,1016
57
60
  orionis/container/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
61
  orionis/container/entities/binding.py,sha256=sY0ioHbRcjp9TSQjfrFHxkO3vRn_VOrbHK62_QEGe1U,3717
@@ -78,7 +81,7 @@ orionis/container/validators/is_subclass.py,sha256=4sBaGLoRs8nUhuWjlP0VJqyTwVHYq
78
81
  orionis/container/validators/is_valid_alias.py,sha256=4uAYcq8xov7jZbXnpKpjNkxcZtlTNnL5RRctVPMwJes,1424
79
82
  orionis/container/validators/lifetime.py,sha256=IQ43fDNrxYHMlZH2zlYDJnlkLO_eS4U7Fs3UJgQBidI,1844
80
83
  orionis/foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
- orionis/foundation/application.py,sha256=yZ1C92A2bTtWK4RUd9RSACLVQVBPjd6zElTt6_kjV6k,77026
84
+ orionis/foundation/application.py,sha256=fKKT4K_DBPEKTMZaeRfBpK_DsaWvEt_dVhA-yu1Wyfo,77173
82
85
  orionis/foundation/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
86
  orionis/foundation/config/startup.py,sha256=vbzduprRCNyYeR2nnMaqc1uKXw6PTzAY2jVfXNQKN8I,9691
84
87
  orionis/foundation/config/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -185,12 +188,13 @@ orionis/foundation/providers/dumper_provider.py,sha256=nKHjLDClCo-KnPloh6EYVySjg
185
188
  orionis/foundation/providers/executor_provider.py,sha256=kwkH8YWEXoEoP51akJXQJ0U25rhlOLxnfE0s9fALr0I,3478
186
189
  orionis/foundation/providers/inspirational_provider.py,sha256=uq2o0uLd5p6PR99uH4cJAcc6NnU6nIOwe0ZIdzZcF4Q,3726
187
190
  orionis/foundation/providers/logger_provider.py,sha256=rs8UpaD_vSp3qNli0u9A4eRum3q3F0KEM0V6yhcl2GU,3417
191
+ orionis/foundation/providers/performance_counter_provider.py,sha256=7y10Vaqx7GemGh2wCaww8XmdvFQXLXm9_E4GjpdNXcA,3010
188
192
  orionis/foundation/providers/progress_bar_provider.py,sha256=X4Ke7mPr0MgVp6WDNaQ3bI3Z_LOS8qE-wid0MQErKms,3367
189
193
  orionis/foundation/providers/reactor_provider.py,sha256=P0KQcp4AFKTrD6BStGfCTqhGUlpKgsrZTZZKSqyGJQg,3662
190
194
  orionis/foundation/providers/testing_provider.py,sha256=SrJRpdvcblx9WvX7x9Y3zc7OQfiTf7la0HAJrm2ESlE,3725
191
195
  orionis/foundation/providers/workers_provider.py,sha256=oa_2NIDH6UxZrtuGkkoo_zEoNIMGgJ46vg5CCgAm7wI,3926
192
196
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
193
- orionis/metadata/framework.py,sha256=qz9zbmqbECbLlCEBY3fkC_rY-M5Uq_tCpC6o2gCl-Xk,4109
197
+ orionis/metadata/framework.py,sha256=gRPC1m0TsT2mlxRIwLsH98soldLLTqKMGuFn_WPQlw4,4109
194
198
  orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
195
199
  orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
196
200
  orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -300,6 +304,10 @@ orionis/support/formatter/exceptions/contracts/parser.py,sha256=onLMtggihUGPhCav
300
304
  orionis/support/patterns/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
301
305
  orionis/support/patterns/singleton/__init__.py,sha256=BIyMYL5yXpzv_F-jsSEtoKYseGlM8jdJT8hwGuXZZl8,62
302
306
  orionis/support/patterns/singleton/meta.py,sha256=TmrE-QlkglBChD4bmMgQRGT3nli6Kf6UvDl1tiEjQ_o,3801
307
+ orionis/support/performance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
308
+ orionis/support/performance/counter.py,sha256=eTr1VoFy1Jiqc4lmyhrYGTe2ge-Vpl1zuzYt_3nMTP8,2947
309
+ orionis/support/performance/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
310
+ orionis/support/performance/contracts/counter.py,sha256=uDBFk4YswAI4O72t2lc2H8Ck86WU4tp8p4gPXg-r3mw,1317
303
311
  orionis/support/standard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
304
312
  orionis/support/standard/std.py,sha256=zwXOellgGy9LTmeAK-rCIr7CgKYg5iQijMjdwmMblFA,3800
305
313
  orionis/support/standard/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -356,7 +364,7 @@ orionis/test/validators/web_report.py,sha256=n9BfzOZz6aEiNTypXcwuWbFRG0OdHNSmCNu
356
364
  orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnIfJYgc,1206
357
365
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
358
366
  orionis/test/view/render.py,sha256=f-zNhtKSg9R5Njqujbg2l2amAs2-mRVESneLIkWOZjU,4082
359
- orionis-0.475.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
367
+ orionis-0.476.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
360
368
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
361
369
  tests/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
362
370
  tests/container/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -503,8 +511,8 @@ tests/testing/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
503
511
  tests/testing/validators/test_testing_validators.py,sha256=WPo5GxTP6xE-Dw3X1vZoqOMpb6HhokjNSbgDsDRDvy4,16588
504
512
  tests/testing/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
505
513
  tests/testing/view/test_render.py,sha256=tnnMBwS0iKUIbogLvu-7Rii50G6Koddp3XT4wgdFEYM,1050
506
- orionis-0.475.0.dist-info/METADATA,sha256=HbxMijbYojBubd7QWnfKhzuXEW7GKsIy_mm1STUHVqc,4801
507
- orionis-0.475.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
508
- orionis-0.475.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
509
- orionis-0.475.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
510
- orionis-0.475.0.dist-info/RECORD,,
514
+ orionis-0.476.0.dist-info/METADATA,sha256=JiWk4nLrJ8sXSpioU4N90qBnNS8z5MjfihB57lQVLfs,4801
515
+ orionis-0.476.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
516
+ orionis-0.476.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
517
+ orionis-0.476.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
518
+ orionis-0.476.0.dist-info/RECORD,,