orionis 0.539.0__py3-none-any.whl → 0.540.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.
Files changed (58) hide show
  1. orionis/console/base/command.py +1 -1
  2. orionis/console/base/scheduler.py +1 -1
  3. orionis/console/contracts/base_command.py +123 -0
  4. orionis/console/contracts/cli_request.py +85 -0
  5. orionis/console/contracts/command.py +90 -108
  6. orionis/console/contracts/event.py +1 -1
  7. orionis/console/contracts/reactor.py +40 -0
  8. orionis/console/core/reactor.py +325 -91
  9. orionis/console/dumper/dump.py +1 -1
  10. orionis/console/dynamic/progress_bar.py +1 -1
  11. orionis/console/{enums → entities}/command.py +3 -0
  12. orionis/console/{enums → entities}/event.py +1 -1
  13. orionis/console/fluent/command.py +216 -0
  14. orionis/console/{tasks → fluent}/event.py +1 -1
  15. orionis/console/kernel.py +28 -11
  16. orionis/console/output/console.py +1 -1
  17. orionis/console/output/executor.py +1 -1
  18. orionis/console/request/cli_request.py +113 -31
  19. orionis/console/tasks/schedule.py +4 -4
  20. orionis/container/container.py +102 -1
  21. orionis/container/contracts/container.py +46 -0
  22. orionis/failure/base/handler.py +6 -6
  23. orionis/failure/catch.py +1 -1
  24. orionis/failure/contracts/handler.py +3 -3
  25. orionis/foundation/application.py +1 -1
  26. orionis/foundation/providers/console_provider.py +1 -1
  27. orionis/foundation/providers/dumper_provider.py +1 -1
  28. orionis/foundation/providers/executor_provider.py +1 -1
  29. orionis/foundation/providers/progress_bar_provider.py +1 -1
  30. orionis/metadata/framework.py +1 -1
  31. orionis/support/facades/application.pyi +5 -0
  32. orionis/support/facades/console.pyi +4 -0
  33. orionis/support/facades/directory.py +0 -1
  34. orionis/support/facades/directory.pyi +4 -0
  35. orionis/support/facades/dumper.pyi +4 -0
  36. orionis/support/facades/executor.pyi +4 -0
  37. orionis/support/facades/inspire.pyi +4 -0
  38. orionis/support/facades/logger.pyi +4 -0
  39. orionis/support/facades/performance_counter.pyi +4 -0
  40. orionis/support/facades/progress_bar.pyi +4 -0
  41. orionis/support/facades/reactor.pyi +97 -0
  42. orionis/support/facades/testing.pyi +4 -0
  43. orionis/test/kernel.py +1 -1
  44. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/METADATA +1 -1
  45. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/RECORD +56 -44
  46. orionis/console/entities/request.py +0 -37
  47. orionis/console/output/contracts/__init__.py +0 -0
  48. /orionis/console/contracts/{scheduler.py → base_scheduler.py} +0 -0
  49. /orionis/console/{output/contracts → contracts}/console.py +0 -0
  50. /orionis/console/{dumper/contracts → contracts}/dump.py +0 -0
  51. /orionis/console/{output/contracts → contracts}/executor.py +0 -0
  52. /orionis/console/{dynamic/contracts → contracts}/progress_bar.py +0 -0
  53. /orionis/console/{dumper/contracts → fluent}/__init__.py +0 -0
  54. /orionis/console/{dynamic/contracts → request}/__init__.py +0 -0
  55. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/WHEEL +0 -0
  56. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/licenses/LICENCE +0 -0
  57. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/top_level.txt +0 -0
  58. {orionis-0.539.0.dist-info → orionis-0.540.0.dist-info}/zip-safe +0 -0
@@ -5,13 +5,15 @@ import re
5
5
  from typing import Any, List, Optional
6
6
  from orionis.console.args.argument import CLIArgument
7
7
  from orionis.console.base.command import BaseCommand
8
- from orionis.console.contracts.command import IBaseCommand
8
+ from orionis.console.contracts.base_command import IBaseCommand
9
+ from orionis.console.contracts.cli_request import ICLIRequest
10
+ from orionis.console.contracts.command import ICommand
9
11
  from orionis.console.contracts.reactor import IReactor
10
- from orionis.console.enums.command import Command
12
+ from orionis.console.entities.command import Command
11
13
  from orionis.console.exceptions import CLIOrionisValueError
12
14
  from orionis.console.exceptions.cli_runtime_error import CLIOrionisRuntimeError
13
- from orionis.console.output.contracts.console import IConsole
14
- from orionis.console.output.contracts.executor import IExecutor
15
+ from orionis.console.contracts.executor import IExecutor
16
+ from orionis.console.request.cli_request import CLIRequest
15
17
  from orionis.foundation.contracts.application import IApplication
16
18
  from orionis.services.introspection.modules.reflection import ReflectionModule
17
19
  from orionis.services.log.contracts.log_service import ILogger
@@ -58,31 +60,181 @@ class Reactor(IReactor):
58
60
  # Initialize the application instance, using provided app or creating new Orionis instance
59
61
  self.__app = app
60
62
 
61
- # Set the project root directory to current working directory for module path resolution
62
- self.__root = self.__app.path('root')
63
-
64
63
  # Initialize the internal command registry as an empty dictionary
65
64
  self.__commands: dict[str, Command] = {}
66
65
 
67
- # Automatically discover and load command classes from the console commands directory
68
- cli_commands_path = (Path(self.__app.path('console')) / 'commands').resolve()
69
- self.__loadCommands(cli_commands_path, self.__root)
70
-
71
- # Load core command classes provided by the Orionis framework
72
- self.__loadCoreCommands()
73
-
74
66
  # Initialize the executor for command output management
75
67
  self.__executer: IExecutor = self.__app.make('x-orionis.console.output.executor')
76
68
 
77
- # Initialize the console for command output
78
- self.__console: IConsole = self.__app.make('x-orionis.console.output.console')
79
-
80
69
  # Initialize the logger service for logging command execution details
81
70
  self.__logger: ILogger = self.__app.make('x-orionis.services.log.log_service')
82
71
 
83
72
  # Initialize the performance counter for measuring command execution time
84
73
  self.__performance_counter: IPerformanceCounter = self.__app.make('x-orionis.support.performance.counter')
85
74
 
75
+ # List to hold fluent command definitions
76
+ self.__fluent_commands: List[ICommand] = []
77
+
78
+ # Flag to indicate whether commands have been loaded
79
+ self.__load_commands: bool = False
80
+
81
+ def __loadCommands(self) -> None:
82
+ """
83
+ Loads all available commands for the console application.
84
+
85
+ This method orchestrates the loading of both custom user-defined commands and
86
+ core framework commands into the reactor's internal command registry. It implements
87
+ a lazy loading pattern using an internal flag to ensure commands are loaded only
88
+ once during the reactor instance's lifetime, preventing duplicate registrations
89
+ and improving performance on subsequent calls.
90
+
91
+ The loading process follows a specific order: custom commands are loaded first,
92
+ followed by core framework commands. This ensures that custom commands can
93
+ potentially override core commands if they share the same signature, giving
94
+ users the flexibility to customize framework behavior.
95
+
96
+ Returns
97
+ -------
98
+ None
99
+ This method does not return any value. All discovered commands are
100
+ registered internally in the reactor's command registry and become
101
+ available for execution through the `call` and `callAsync` methods.
102
+
103
+ Notes
104
+ -----
105
+ - Commands are loaded only once per reactor instance to prevent duplicates
106
+ - Custom commands are loaded before core commands to allow potential overrides
107
+ - The internal `__load_commands` flag tracks whether commands have been loaded
108
+ - Both loading methods handle their own error handling and validation
109
+ """
110
+ # Check if commands have already been loaded to prevent duplicate loading
111
+ if not self.__load_commands:
112
+
113
+ # Load custom user-defined commands from the project's commands directory
114
+ self.__loadCustomCommands()
115
+
116
+ # Load core framework commands that are bundled with Orionis
117
+ self.__loadCoreCommands()
118
+
119
+ # Load commands defined using the fluent interface
120
+ self.__loadFluentCommands()
121
+
122
+ # Set the flag to indicate that commands have been successfully loaded
123
+ self.__load_commands = True
124
+
125
+ def __loadFluentCommands(self) -> None:
126
+ """
127
+ Loads and registers commands defined using the fluent interface.
128
+
129
+ This method iterates through all commands that have been defined using the
130
+ fluent interface pattern and registers them in the reactor's internal command
131
+ registry. Each fluent command is validated for structure and metadata before
132
+ being added to ensure proper integration and discoverability.
133
+
134
+ Returns
135
+ -------
136
+ None
137
+ This method does not return any value. All fluent commands are
138
+ registered internally in the reactor's command registry for later lookup
139
+ and execution.
140
+ """
141
+
142
+ # Import library for dynamic module importing
143
+ import importlib
144
+
145
+ # Get the routes directory path from the application instance
146
+ routes_path = self.__app.path('routes')
147
+
148
+ # Check if routes directory exists
149
+ if not os.path.exists(routes_path):
150
+ return
151
+
152
+ # Get the project root directory for module path resolution
153
+ root_path = self.__app.getBasePath()
154
+
155
+ # List all .py files in the routes directory and subdirectories
156
+ for current_directory, _, files in os.walk(routes_path):
157
+ for file in files:
158
+
159
+ # Only process Python files
160
+ if file.endswith('.py'):
161
+ file_path = os.path.join(current_directory, file)
162
+
163
+ # Read file content to check for 'Reactor.command'
164
+ try:
165
+
166
+ with open(file_path, 'r', encoding='utf-8') as f:
167
+ content = f.read()
168
+
169
+ # Check if the file contains 'Reactor.command'
170
+ if 'Reactor.command' in content:
171
+
172
+ # Sanitize the module path for import
173
+ pre_module = current_directory.replace(root_path, '')\
174
+ .replace(os.sep, '.')\
175
+ .lstrip('.')
176
+
177
+ # Remove virtual environment paths
178
+ pre_module = re.sub(r'[^.]*\.(?:Lib|lib)\.(?:python[^.]*\.)?site-packages\.?', '', pre_module)
179
+ pre_module = re.sub(r'\.?v?env\.?', '', pre_module)
180
+ pre_module = re.sub(r'\.+', '.', pre_module).strip('.')
181
+
182
+ # Skip if module name is empty after cleaning
183
+ if not pre_module:
184
+ continue
185
+
186
+ # Create the reflection module path
187
+ module_name = f"{pre_module}.{file[:-3]}"
188
+
189
+ try:
190
+
191
+ # Import the module natively using importlib
192
+ importlib.import_module(module_name)
193
+
194
+ except Exception as e:
195
+
196
+ # Raise a runtime error if module import fails
197
+ raise CLIOrionisRuntimeError(
198
+ f"Failed to import module '{module_name}' from file '{file_path}': {e}"
199
+ ) from e
200
+
201
+ except Exception as e:
202
+
203
+ # Raise a runtime error if file reading fails
204
+ raise CLIOrionisRuntimeError(
205
+ f"Failed to read file '{file_path}' for fluent command loading: {e}"
206
+ ) from e
207
+
208
+ # Iterate through all fluent command definitions
209
+ for f_command in self.__fluent_commands:
210
+
211
+ signature, command_entity = f_command.get()
212
+
213
+ # Build the arguments dictionary from the CLIArgument instances
214
+ required_args: List[CLIArgument] = command_entity.args
215
+
216
+ # Create an ArgumentParser instance to handle the command arguments
217
+ arg_parser = argparse.ArgumentParser(
218
+ usage=f"python -B reactor {signature} [options]",
219
+ description=f"Command [{signature}] : {command_entity.description}",
220
+ formatter_class=argparse.RawTextHelpFormatter,
221
+ add_help=True,
222
+ allow_abbrev=False,
223
+ exit_on_error=True,
224
+ prog=signature
225
+ )
226
+ for arg in required_args:
227
+ arg.addToParser(arg_parser)
228
+
229
+ self.__commands[signature] = Command(
230
+ obj=command_entity.obj,
231
+ method=command_entity.method,
232
+ timestamps=command_entity.timestamps,
233
+ signature=signature,
234
+ description=command_entity.description,
235
+ args=arg_parser
236
+ )
237
+
86
238
  def __loadCoreCommands(self) -> None:
87
239
  """
88
240
  Loads and registers core command classes provided by the Orionis framework.
@@ -141,13 +293,14 @@ class Reactor(IReactor):
141
293
  # Register the command in the internal registry with all its metadata
142
294
  self.__commands[signature] = Command(
143
295
  obj=obj,
296
+ method='handle',
144
297
  timestamps=timestamp,
145
298
  signature=signature,
146
299
  description=description,
147
300
  args=args
148
301
  )
149
302
 
150
- def __loadCommands(self, commands_path: str, root_path: str) -> None:
303
+ def __loadCustomCommands(self) -> None:
151
304
  """
152
305
  Loads command classes from Python files in the specified commands directory.
153
306
 
@@ -156,13 +309,6 @@ class Reactor(IReactor):
156
309
  sanitization to handle virtual environment paths and validates command structure
157
310
  before registration.
158
311
 
159
- Parameters
160
- ----------
161
- commands_path : str
162
- The absolute path to the directory containing command modules to load.
163
- root_path : str
164
- The root path of the project, used for module path normalization.
165
-
166
312
  Returns
167
313
  -------
168
314
  None
@@ -177,6 +323,10 @@ class Reactor(IReactor):
177
323
  - Each discovered command class undergoes structure validation via __ensureStructure
178
324
  """
179
325
 
326
+ # Ensure the provided commands_path is a valid directory
327
+ commands_path = (Path(self.__app.path('console')) / 'commands').resolve()
328
+ root_path = self.__app.getBasePath()
329
+
180
330
  # Iterate through the command path and load command modules
181
331
  for current_directory, _, files in os.walk(commands_path):
182
332
  for file in files:
@@ -222,6 +372,7 @@ class Reactor(IReactor):
222
372
  # Add the command to the internal registry
223
373
  self.__commands[signature] = Command(
224
374
  obj=obj,
375
+ method='handle',
225
376
  timestamps=timestamp,
226
377
  signature=signature,
227
378
  description=description,
@@ -477,6 +628,60 @@ class Reactor(IReactor):
477
628
  # Return an empty dictionary if no arguments were parsed
478
629
  return {}
479
630
 
631
+ def command(
632
+ self,
633
+ signature: str,
634
+ handler: Any
635
+ ) -> ICommand:
636
+ """
637
+ Define a new command using a fluent interface.
638
+
639
+ This method allows defining a new command with a specified signature and handler
640
+ function using a fluent interface pattern. The command can be further configured
641
+ by chaining additional method calls to set properties such as timestamps,
642
+ description, and arguments.
643
+
644
+ Parameters
645
+ ----------
646
+ signature : str
647
+ The unique signature identifier for the command. Must follow naming conventions
648
+ (alphanumeric characters, underscores, colons, cannot start/end with underscore
649
+ or colon, cannot start with a number).
650
+ handler : Any
651
+ The function or callable that will be executed when the command is invoked.
652
+ This should be a valid function that accepts parameters matching the command's
653
+ defined arguments.
654
+
655
+ Returns
656
+ -------
657
+ ICommand
658
+ Returns an instance of ICommand that allows further configuration of the command
659
+ through method chaining.
660
+
661
+ Raises
662
+ ------
663
+ TypeError
664
+ If the signature is not a string or if the handler is not callable.
665
+ ValueError
666
+ If the signature does not meet the required naming conventions.
667
+ """
668
+
669
+ # Import the FluentCommand class here to avoid circular imports
670
+ from orionis.console.fluent.command import Command as FluentCommand
671
+
672
+ # Create a new FluentCommand instance with the provided signature and handler
673
+ f_command = FluentCommand(
674
+ signature=signature,
675
+ concrete=handler[0],
676
+ method=handler[1] if len(handler) > 1 else 'handle'
677
+ )
678
+
679
+ # Append the new command to the internal list of fluent commands
680
+ self.__fluent_commands.append(f_command)
681
+
682
+ # Return the newly created command for further configuration
683
+ return self.__fluent_commands[-1]
684
+
480
685
  def info(self) -> List[dict]:
481
686
  """
482
687
  Retrieves a list of all registered commands with their metadata.
@@ -493,6 +698,9 @@ class Reactor(IReactor):
493
698
  contains the command's signature, description, and timestamps status.
494
699
  """
495
700
 
701
+ # Ensure commands are loaded before retrieving information
702
+ self.__loadCommands()
703
+
496
704
  # Prepare a list to hold command information
497
705
  commands_info = []
498
706
 
@@ -558,51 +766,64 @@ class Reactor(IReactor):
558
766
  - All exceptions are logged and displayed in the console.
559
767
  """
560
768
 
561
- # Retrieve the command from the registry by its signature
562
- command: Command = self.__commands.get(signature)
563
- if command is None:
564
- raise CLIOrionisValueError(f"Command '{signature}' not found.")
769
+ # Scope Request instances to this command execution context
770
+ with self.__app.createContext():
771
+
772
+ # Ensure commands are loaded before attempting to execute
773
+ self.__loadCommands()
565
774
 
566
- # Start execution timer for performance measurement
567
- self.__performance_counter.start()
775
+ # Retrieve the command from the registry by its signature
776
+ command: Command = self.__commands.get(signature)
777
+ if command is None:
778
+ raise CLIOrionisValueError(f"Command '{signature}' not found.")
568
779
 
569
- # Log the command execution start with RUNNING state if timestamps are enabled
570
- if command.timestamps:
571
- self.__executer.running(program=signature)
780
+ # Start execution timer for performance measurement
781
+ self.__performance_counter.start()
572
782
 
573
- try:
574
- # Instantiate the command class using the application container
575
- command_instance: IBaseCommand = self.__app.make(command.obj)
783
+ # Log the command execution start with RUNNING state if timestamps are enabled
784
+ if command.timestamps:
785
+ self.__executer.running(program=signature)
576
786
 
577
- # Inject parsed arguments into the command instance
578
- command_instance._args = self.__parseArgs(command, args)
787
+ try:
788
+ # Instantiate the command class using the application container
789
+ command_instance: IBaseCommand = self.__app.make(command.obj)
579
790
 
580
- # Execute the command's handle method and capture its output
581
- output = self.__app.call(command_instance, 'handle')
791
+ # Inject parsed arguments into the command instance
792
+ _args = self.__parseArgs(command, args)
793
+ command_instance._args = _args.copy()
582
794
 
583
- # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
584
- elapsed_time = round(self.__performance_counter.stop(), 2)
585
- if command.timestamps:
586
- self.__executer.done(program=signature, time=f"{elapsed_time}s")
795
+ # Inject a scoped CLIRequest instance into the application container for the command's context
796
+ self.__app.scopedInstance(ICLIRequest, CLIRequest(
797
+ command=signature,
798
+ args=_args.copy()
799
+ ))
587
800
 
588
- # Log successful execution in the logger service
589
- self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
801
+ # Execute the command's handle method and capture its output
802
+ output = self.__app.call(command_instance, command.method)
590
803
 
591
- # Return the output produced by the command, if any
592
- return output
804
+ # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
805
+ elapsed_time = round(self.__performance_counter.stop(), 2)
806
+ if command.timestamps:
807
+ self.__executer.done(program=signature, time=f"{elapsed_time}s")
593
808
 
594
- except Exception as e:
809
+ # Log successful execution in the logger service
810
+ self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
595
811
 
596
- # Log the error in the logger service
597
- self.__logger.error(f"Command '{signature}' execution failed: {e}")
812
+ # Return the output produced by the command, if any
813
+ return output
598
814
 
599
- # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
600
- elapsed_time = round(self.__performance_counter.stop(), 2)
601
- if command.timestamps:
602
- self.__executer.fail(program=signature, time=f"{elapsed_time}s")
815
+ except Exception as e:
603
816
 
604
- # Propagate the exception after logging
605
- raise
817
+ # Log the error in the logger service
818
+ self.__logger.error(f"Command '{signature}' execution failed: {e}")
819
+
820
+ # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
821
+ elapsed_time = round(self.__performance_counter.stop(), 2)
822
+ if command.timestamps:
823
+ self.__executer.fail(program=signature, time=f"{elapsed_time}s")
824
+
825
+ # Propagate the exception after logging
826
+ raise
606
827
 
607
828
  async def callAsync(
608
829
  self,
@@ -646,48 +867,61 @@ class Reactor(IReactor):
646
867
  - All exceptions are logged and displayed in the console.
647
868
  """
648
869
 
649
- # Retrieve the command from the registry by its signature
650
- command: Command = self.__commands.get(signature)
651
- if command is None:
652
- raise CLIOrionisValueError(f"Command '{signature}' not found.")
870
+ # Scope Request instances to this command execution context
871
+ with self.__app.createContext():
653
872
 
654
- # Start execution timer for performance measurement
655
- self.__performance_counter.start()
873
+ # Ensure commands are loaded before attempting to execute
874
+ self.__loadCommands()
656
875
 
657
- # Log the command execution start with RUNNING state if timestamps are enabled
658
- if command.timestamps:
659
- self.__executer.running(program=signature)
876
+ # Retrieve the command from the registry by its signature
877
+ command: Command = self.__commands.get(signature)
878
+ if command is None:
879
+ raise CLIOrionisValueError(f"Command '{signature}' not found.")
660
880
 
661
- try:
662
- # Instantiate the command class using the application container
663
- command_instance: IBaseCommand = self.__app.make(command.obj)
881
+ # Start execution timer for performance measurement
882
+ self.__performance_counter.start()
664
883
 
665
- # Inject parsed arguments into the command instance
666
- command_instance._args = self.__parseArgs(command, args)
884
+ # Log the command execution start with RUNNING state if timestamps are enabled
885
+ if command.timestamps:
886
+ self.__executer.running(program=signature)
667
887
 
668
- # Execute the command's handle method asynchronously and capture its output
669
- output = await self.__app.callAsync(command_instance, 'handle')
888
+ try:
889
+ # Instantiate the command class using the application container
890
+ command_instance: IBaseCommand = self.__app.make(command.obj)
670
891
 
671
- # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
672
- elapsed_time = round(self.__performance_counter.stop(), 2)
673
- if command.timestamps:
674
- self.__executer.done(program=signature, time=f"{elapsed_time}s")
892
+ # Inject parsed arguments into the command instance
893
+ _args = self.__parseArgs(command, args)
894
+ command_instance._args = _args.copy()
675
895
 
676
- # Log successful execution in the logger service
677
- self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
896
+ # Inject a scoped CLIRequest instance into the application container for the command's context
897
+ self.__app.scopedInstance(ICLIRequest, CLIRequest(
898
+ command=signature,
899
+ args=_args.copy()
900
+ ))
678
901
 
679
- # Return the output produced by the command, if any
680
- return output
902
+ # Execute the command's handle method asynchronously and capture its output
903
+ output = await self.__app.callAsync(command_instance, 'handle')
681
904
 
682
- except Exception as e:
905
+ # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
906
+ elapsed_time = round(self.__performance_counter.stop(), 2)
907
+ if command.timestamps:
908
+ self.__executer.done(program=signature, time=f"{elapsed_time}s")
683
909
 
684
- # Log the error in the logger service
685
- self.__logger.error(f"Command '{signature}' execution failed: {e}")
910
+ # Log successful execution in the logger service
911
+ self.__logger.info(f"Command '{signature}' executed successfully in ({elapsed_time}) seconds.")
686
912
 
687
- # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
688
- elapsed_time = round(self.__performance_counter.stop(), 2)
689
- if command.timestamps:
690
- self.__executer.fail(program=signature, time=f"{elapsed_time}s")
913
+ # Return the output produced by the command, if any
914
+ return output
915
+
916
+ except Exception as e:
917
+
918
+ # Log the error in the logger service
919
+ self.__logger.error(f"Command '{signature}' execution failed: {e}")
920
+
921
+ # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
922
+ elapsed_time = round(self.__performance_counter.stop(), 2)
923
+ if command.timestamps:
924
+ self.__executer.fail(program=signature, time=f"{elapsed_time}s")
691
925
 
692
- # Propagate the exception after logging
693
- raise
926
+ # Propagate the exception after logging
927
+ raise
@@ -9,7 +9,7 @@ from rich.panel import Panel
9
9
  from rich.syntax import Syntax
10
10
  from rich.table import Table
11
11
  from rich.traceback import install
12
- from orionis.console.dumper.contracts.dump import IDebug
12
+ from orionis.console.contracts.dump import IDebug
13
13
 
14
14
  class Debug(IDebug):
15
15
 
@@ -1,5 +1,5 @@
1
1
  import sys
2
- from orionis.console.dynamic.contracts.progress_bar import IProgressBar
2
+ from orionis.console.contracts.progress_bar import IProgressBar
3
3
 
4
4
  class ProgressBar(IProgressBar):
5
5
  """
@@ -30,6 +30,9 @@ class Command(BaseEntity):
30
30
  # The type or class associated with the command
31
31
  obj: Type
32
32
 
33
+ # The method name to be invoked on the object
34
+ method: str = 'hanldle'
35
+
33
36
  # Indicates if timestamps are enabled for this command
34
37
  timestamps: bool
35
38
 
@@ -31,7 +31,7 @@ class Event:
31
31
  details : Optional[str]
32
32
  Additional details or metadata about the event. Can be None if not specified.
33
33
  listener : Optional[IScheduleEventListener]
34
- An optional listener object that implements the IScheduleEventListener interface.
34
+ An optional listener object that implements the IScheduleEventListener interface.
35
35
  This listener can handle event-specific logic. Defaults to None.
36
36
  """
37
37