orionis 0.641.0__py3-none-any.whl → 0.643.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,3 +1,5 @@
1
+ from typing import List
2
+ from orionis.console.args.argument import CLIArgument
1
3
  from orionis.console.base.command import BaseCommand
2
4
  from orionis.console.exceptions import CLIOrionisRuntimeError
3
5
  from rich.console import Console
@@ -30,6 +32,29 @@ class VersionCommand(BaseCommand):
30
32
  # Command description
31
33
  description: str = "Displays the current Orionis framework version and metadata, including author, Python requirements, documentation, and repository links."
32
34
 
35
+ async def options(self) -> List[CLIArgument]:
36
+ """
37
+ Defines the command-line options available for the `make:command` command.
38
+
39
+ This method specifies the arguments that can be passed to the command when it is invoked
40
+ from the CLI. It includes both required and optional arguments, each represented as a
41
+ `CLIArgument` instance.
42
+
43
+ Returns
44
+ -------
45
+ List[CLIArgument]
46
+ A list of `CLIArgument` objects representing the available command-line options.
47
+ """
48
+
49
+ return [
50
+ CLIArgument(
51
+ flags=["--without-console"],
52
+ type=bool,
53
+ help="Return only the version string, without console output.",
54
+ required=False
55
+ )
56
+ ]
57
+
33
58
  def handle(self, console: Console) -> str:
34
59
  """
35
60
  Executes the version command to display the current Orionis framework version and metadata.
@@ -55,6 +80,10 @@ class VersionCommand(BaseCommand):
55
80
  """
56
81
  try:
57
82
 
83
+ # If the --without-console flag is set, return just the version string
84
+ if self.argument("without_console", False):
85
+ return framework.VERSION
86
+
58
87
  # Compose the main information strings using framework metadata
59
88
  title = f"[bold yellow]{framework.NAME.capitalize()} Framework[/bold yellow] [white]v{framework.VERSION}[/white]"
60
89
  author = f"[bold]Author:[/bold] {framework.AUTHOR} | [bold]Email:[/bold] {framework.AUTHOR_EMAIL}"
@@ -970,7 +970,8 @@ class Reactor(IReactor):
970
970
  output = await self.__app.callAsync(command_instance, 'handle')
971
971
 
972
972
  # Calculate elapsed time and log completion with DONE state if command.timestamps are enabled
973
- elapsed_time = round(self.__performance_counter.stop(), 2)
973
+ self.__performance_counter.stop()
974
+ elapsed_time = round(self.__performance_counter.getSeconds(), 2)
974
975
  if command.timestamps:
975
976
  self.__executer.done(program=signature, time=f"{elapsed_time}s")
976
977
 
@@ -986,7 +987,8 @@ class Reactor(IReactor):
986
987
  self.__logger.error(f"Command '{signature}' execution failed: {e}")
987
988
 
988
989
  # Calculate elapsed time and log failure with ERROR state if command.timestamps are enabled
989
- elapsed_time = round(self.__performance_counter.stop(), 2)
990
+ self.__performance_counter.stop()
991
+ elapsed_time = round(self.__performance_counter.getSeconds(), 2)
990
992
  if command.timestamps:
991
993
  self.__executer.fail(program=signature, time=f"{elapsed_time}s")
992
994
 
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.641.0"
8
+ VERSION = "0.643.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -279,7 +279,7 @@ class ReflectionInstance(IReflectionInstance):
279
279
  bool
280
280
  True if the attribute exists
281
281
  """
282
- return name in self.getAttributes()
282
+ return name in self.getAttributes() or hasattr(self._instance, name)
283
283
 
284
284
  def getAttribute(self, name: str, default: Any = None) -> Any:
285
285
  """
@@ -90,6 +90,12 @@ class UnitTest(IUnitTest):
90
90
  # Suppress overly verbose asyncio logging during test execution
91
91
  logging.getLogger("asyncio").setLevel(logging.ERROR)
92
92
 
93
+ # List of common setup/teardown methods to inspect for debug calls
94
+ self.__commonMethods = [
95
+ 'setUp', 'tearDown', 'onSetup', 'onTeardown',
96
+ 'asyncSetUp', 'asyncTearDown', 'onAsyncSetup', 'onAsyncTeardown'
97
+ ]
98
+
93
99
  # Store the application instance for dependency injection and configuration access
94
100
  self.__app: IApplication = app
95
101
 
@@ -649,9 +655,8 @@ class UnitTest(IUnitTest):
649
655
  # Gather method names to inspect: main test method and common setup/teardown hooks
650
656
  rf_instance = ReflectionInstance(test_case)
651
657
  method_name = rf_instance.getAttribute("_testMethodName")
652
- extra_methods = ["setUp", "tearDown", "onSetup", "onTeardown"]
653
658
  method_names_to_check = [method_name] if method_name else []
654
- method_names_to_check += [m for m in extra_methods if rf_instance.hasMethod(m)]
659
+ method_names_to_check += [m for m in self.__commonMethods if rf_instance.hasMethod(m)]
655
660
 
656
661
  # Inspect each method's source code for debug keywords
657
662
  for mname in method_names_to_check:
@@ -877,10 +882,10 @@ class UnitTest(IUnitTest):
877
882
  """
878
883
  Inject dependencies into a single test case if required, returning a TestSuite containing the resolved test case.
879
884
 
880
- This method uses reflection to inspect the test method for dependency requirements. If dependencies are resolved,
881
- it injects them into the test method. Supports both synchronous and asynchronous test methods: async methods are
882
- wrapped to run in an event loop. If dependencies cannot be resolved, the original test case is returned as-is
883
- within a TestSuite.
885
+ This method uses reflection to inspect the test method and common setup/teardown methods for dependency requirements.
886
+ If dependencies are resolved, it injects them into the test method. Supports both synchronous and asynchronous test
887
+ methods: async methods are wrapped to run in an event loop. If dependencies cannot be resolved or an error occurs,
888
+ the original test case is returned as-is within a TestSuite.
884
889
 
885
890
  Parameters
886
891
  ----------
@@ -904,71 +909,87 @@ class UnitTest(IUnitTest):
904
909
  - If dependencies are resolved, injects them into the test method.
905
910
  - Supports async test methods by running them in an event loop.
906
911
  - If dependencies are unresolved or an error occurs, the original test case is returned.
912
+ - The return value is always a unittest.TestSuite containing either the dependency-injected test case or the original test case.
907
913
  """
908
914
 
909
915
  # Create a new TestSuite to hold the resolved test case
910
916
  suite = unittest.TestSuite()
911
917
 
912
918
  try:
913
-
914
919
  # Use reflection to inspect the test case for dependency requirements
915
920
  rf_instance = ReflectionInstance(test_case)
916
- method_name = rf_instance.getAttribute("_testMethodName", None)
917
921
 
918
- # If no method name is found, return the original test case
919
- if not method_name:
922
+ # If reflection fails or method name is missing, return the original test case
923
+ if not rf_instance.hasAttribute("_testMethodName"):
920
924
  return test_case
921
925
 
922
- # Get the method dependencies using the dependency injection system
923
- dependencies = rf_instance.getMethodDependencies(method_name)
926
+ # Iterate over the main test method and common setup/teardown methods
927
+ for method_name in [
928
+ rf_instance.getAttribute("_testMethodName"),
929
+ *self.__commonMethods
930
+ ]:
924
931
 
925
- # If there are unresolved dependencies, return the original test case
926
- if dependencies.unresolved:
927
- return test_case
932
+ # Skip if the method does not exist on the class
933
+ if not method_name or not rf_instance.hasMethod(method_name):
934
+ continue
928
935
 
929
- # If dependencies are resolved, inject them into the test method
930
- if dependencies.resolved:
936
+ # Obtain the dependencies of the method
937
+ dependencies = rf_instance.getMethodDependencies(method_name)
931
938
 
932
- # Get the test case class
933
- test_cls = rf_instance.getClass()
939
+ # Skip if the method has unresolved dependencies
940
+ if dependencies.unresolved:
941
+ continue
934
942
 
935
- # Create a ReflectionConcrete instance for the test case class
936
- rf_concrete = ReflectionConcrete(test_cls)
943
+ # If dependencies are resolved, inject them into the test method
944
+ if dependencies.resolved:
937
945
 
938
- # Get the original test method
939
- original_method = rf_concrete.getAttribute(method_name)
946
+ # Get the test case class
947
+ test_cls = rf_instance.getClass()
940
948
 
941
- # Resolve the actual arguments to inject
942
- resolved_args = self.__app.resolveDependencyArguments(
943
- rf_instance.getClassName(),
944
- dependencies
945
- )
949
+ # Create a ReflectionConcrete instance for the test case class
950
+ rf_concrete = ReflectionConcrete(test_cls)
946
951
 
947
- # If the test method is asynchronous, wrap it to run in an event loop
948
- if asyncio.iscoroutinefunction(original_method):
952
+ # Get the original test method
953
+ original_method = rf_concrete.getAttribute(method_name)
949
954
 
950
- # Define an async wrapper to inject dependencies
951
- async def async_wrapper(self_instance):
952
- return await original_method(self_instance, **resolved_args)
955
+ # Resolve the actual arguments to inject
956
+ resolved_args = self.__app.resolveDependencyArguments(
957
+ rf_instance.getClassName(),
958
+ dependencies
959
+ )
953
960
 
954
- # Wrap with a sync function for unittest compatibility
955
- def sync_wrapper(self_instance):
956
- return asyncio.run(async_wrapper(self_instance))
961
+ # If the test method is asynchronous, wrap it to run in an event loop
962
+ if asyncio.iscoroutinefunction(original_method):
957
963
 
958
- # Bind the wrapped method to the test case instance
959
- bound_method = sync_wrapper.__get__(test_case, test_cls)
964
+ # Define an async wrapper to inject dependencies
965
+ async def async_wrapper(self_instance):
966
+ return await original_method(self_instance, **resolved_args)
960
967
 
961
- else:
968
+ # Wrap with a sync function for unittest compatibility
969
+ def sync_wrapper(self_instance):
970
+ try:
971
+ loop = asyncio.get_running_loop()
972
+ except RuntimeError:
973
+ loop = None
974
+ if loop and loop.is_running():
975
+ return loop.create_task(async_wrapper(self_instance))
976
+ else:
977
+ return asyncio.run(async_wrapper(self_instance))
978
+
979
+ # Bind the wrapped method to the test case instance
980
+ bound_method = sync_wrapper.__get__(test_case, test_cls)
962
981
 
963
- # For synchronous methods, inject dependencies directly
964
- def wrapper(self_instance):
965
- return original_method(self_instance, **resolved_args)
982
+ else:
983
+
984
+ # For synchronous methods, inject dependencies directly
985
+ def wrapper(self_instance):
986
+ return original_method(self_instance, **resolved_args)
966
987
 
967
- # Bind the wrapped method to the test case instance
968
- bound_method = wrapper.__get__(test_case, test_cls)
988
+ # Bind the wrapped method to the test case instance
989
+ bound_method = wrapper.__get__(test_case, test_cls)
969
990
 
970
- # Replace the test method with the dependency-injected version
971
- rf_instance.setMethod(method_name, bound_method)
991
+ # Replace the test method with the dependency-injected version
992
+ rf_instance.setMethod(method_name, bound_method)
972
993
 
973
994
  # Add the (possibly resolved) test case to the suite
974
995
  suite.addTest(rf_instance.getInstance())
@@ -977,7 +998,6 @@ class UnitTest(IUnitTest):
977
998
  return suite
978
999
 
979
1000
  except Exception:
980
-
981
1001
  # On error, return the original test case
982
1002
  return test_case
983
1003
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionis
3
- Version: 0.641.0
3
+ Version: 0.643.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
@@ -17,7 +17,7 @@ orionis/console/commands/make_command.py,sha256=EbTicRHGf7uZ78MSDwZpQMDTB0MvwATc
17
17
  orionis/console/commands/scheduler_list.py,sha256=Wtjy73fpcjI6GGsJg6BHWVUXItzHbY1QLEhryXpCLcs,4770
18
18
  orionis/console/commands/scheduler_work.py,sha256=iPTgP7gOmTPr__TltYQWiqbDXbCP2njuO_2fCzwmMuc,5778
19
19
  orionis/console/commands/test.py,sha256=LXtl918TmYhg0sjBiCfbsvaXUmCLqwCXTazmy7AJhlE,2445
20
- orionis/console/commands/version.py,sha256=0EEFOzzUMzH7DOULKmkHkDLt4D8k938FIkkV3iBQ-t8,3694
20
+ orionis/console/commands/version.py,sha256=u5_8CfnEVdS3VSME8rbP6o3Z0XFZ30nSz8uHdahBAoY,4766
21
21
  orionis/console/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  orionis/console/contracts/base_command.py,sha256=UlDN41Ts0ulxM-B2kgeKNr9_gNv_0LCth_pon1os-8U,7617
23
23
  orionis/console/contracts/base_scheduler.py,sha256=RSxEW57MoMU3pXfliIrQw9WuMk95p-xHXi1yACp1qsU,7728
@@ -33,7 +33,7 @@ orionis/console/contracts/reactor.py,sha256=iT6ShoCutAWEeJzOf_PK7CGXi9TgrOD5tewH
33
33
  orionis/console/contracts/schedule.py,sha256=xtXgp4BPhvhg3YSM4mrIdbyoBdr4OJBi1gBM_kJN5UQ,13694
34
34
  orionis/console/contracts/schedule_event_listener.py,sha256=h06qsBxuEMD3KLSyu0JXdUDHlQW19BX9lA09Qrh2QXg,3818
35
35
  orionis/console/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- orionis/console/core/reactor.py,sha256=1pog0n0T-CKzFZlGO_2E0cwNv1dprPVFnxsLzUZZE3c,43930
36
+ orionis/console/core/reactor.py,sha256=x_bRFLBq5MiKZdlMG1gZR1GCZgFkUDnG5l_nh2YKiR8,44044
37
37
  orionis/console/dumper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  orionis/console/dumper/debug.py,sha256=p8uflSXeDJDrVM9mZY4JMYEus73Z6TsLnQQtgP0QUak,22427
39
39
  orionis/console/dynamic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -217,7 +217,7 @@ orionis/foundation/providers/scheduler_provider.py,sha256=IrPQJwvQVLRm5Qnz0Cxon4
217
217
  orionis/foundation/providers/testing_provider.py,sha256=eI1p2lUlxl25b5Z487O4nmqLE31CTDb4c3Q21xFadkE,1615
218
218
  orionis/foundation/providers/workers_provider.py,sha256=GdHENYV_yGyqmHJHn0DCyWmWId5xWjD48e6Zq2PGCWY,1674
219
219
  orionis/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
- orionis/metadata/framework.py,sha256=9JycIg_bqAbqiI4dgYCq__3Cn982ZTvVjr8asLkzHdA,4089
220
+ orionis/metadata/framework.py,sha256=eMaGl9vrCG8j8pnG9UGVptLGI-FoeB4-1fD9cCIkSis,4089
221
221
  orionis/metadata/package.py,sha256=k7Yriyp5aUcR-iR8SK2ec_lf0_Cyc-C7JczgXa-I67w,16039
222
222
  orionis/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
223
  orionis/services/asynchrony/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -280,7 +280,7 @@ orionis/services/introspection/dependencies/entities/resolve_argument.py,sha256=
280
280
  orionis/services/introspection/exceptions/__init__.py,sha256=uVRbnndapr9veJps8EzFJeLItxnMEbjUDdPBy3dQbeM,221
281
281
  orionis/services/introspection/exceptions/introspection.py,sha256=Qd021psWiXyY9HQVNWIBVZ3KNfHGSgq8NL4btUTR8tg,2532
282
282
  orionis/services/introspection/instances/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
283
- orionis/services/introspection/instances/reflection.py,sha256=RZTgrHnd_oWSZGQ2lHmsj03QkQxkzR3yuv5bg8Hl7Ck,58495
283
+ orionis/services/introspection/instances/reflection.py,sha256=ziyaJ7zjlvX0wkbpm7tZ4i5em9UxGdCf2lsFmNVrr_4,58528
284
284
  orionis/services/introspection/instances/contracts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
285
285
  orionis/services/introspection/instances/contracts/reflection.py,sha256=OBZ7vI6KsII76oqIF63v1I-msh94_xGfhPZQvqAVLgY,20834
286
286
  orionis/services/introspection/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -371,7 +371,7 @@ orionis/test/contracts/render.py,sha256=wpDQzUtT0r8KFZ7zPcxWHXQ1EVNKxzA_rZ6ZKUcZ
371
371
  orionis/test/contracts/test_result.py,sha256=SNXJ2UerkweYn7uCT0i0HmMGP0XBrL_9KJs-0ZvIYU4,4002
372
372
  orionis/test/contracts/unit_test.py,sha256=EyidHoOPJItwgkBWGYY1TymbNklyn2EUXnghVvW4htc,4652
373
373
  orionis/test/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
374
- orionis/test/core/unit_test.py,sha256=wVNFx3b39Unxu6q4P1lprFwlAm_MEJOX8ndEqalNeWw,71266
374
+ orionis/test/core/unit_test.py,sha256=-T5QS7mWYykOX28Q-dVCP1JoOwwlIzFLlOjZRvYguOU,72500
375
375
  orionis/test/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
376
376
  orionis/test/entities/result.py,sha256=eZ6UIqGmFW8FZ9x8PB_MZbLAc-SAuUyi4FUcMYIZzGo,4777
377
377
  orionis/test/enums/__init__.py,sha256=M3imAgMvKFTKg55FbtVoY3zxj7QRY9AfaUWxiSZVvn4,66
@@ -404,8 +404,8 @@ orionis/test/validators/workers.py,sha256=rWcdRexINNEmGaO7mnc1MKUxkHKxrTsVuHgbnI
404
404
  orionis/test/view/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
405
405
  orionis/test/view/render.py,sha256=R55ykeRs0wDKcdTf4O1YZ8GDHTFmJ0IK6VQkbJkYUvo,5571
406
406
  orionis/test/view/report.stub,sha256=QLqqCdRoENr3ECiritRB3DO_MOjRQvgBh5jxZ3Hs1r0,28189
407
- orionis-0.641.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
408
- orionis-0.641.0.dist-info/METADATA,sha256=FCsNt3V9b6ZZscnE-c54RK7AT0iRM_rRp7gJakViS3A,4772
409
- orionis-0.641.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
410
- orionis-0.641.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
411
- orionis-0.641.0.dist-info/RECORD,,
407
+ orionis-0.643.0.dist-info/licenses/LICENCE,sha256=JhC-z_9mbpUrCfPjcl3DhDA8trNDMzb57cvRSam1avc,1463
408
+ orionis-0.643.0.dist-info/METADATA,sha256=I1M9inorrXvliOKu3GxjeeGG0K8QMvrAIuDbh0_Cum0,4772
409
+ orionis-0.643.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
410
+ orionis-0.643.0.dist-info/top_level.txt,sha256=lyXi6jArpqJ-0zzNqd_uwsH-z9TCEBVBL-pC3Ekv7hU,8
411
+ orionis-0.643.0.dist-info/RECORD,,