danielutils 1.1.2__tar.gz → 1.1.22__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. {danielutils-1.1.2/danielutils.egg-info → danielutils-1.1.22}/PKG-INFO +2 -2
  2. {danielutils-1.1.2 → danielutils-1.1.22}/README.md +1 -1
  3. danielutils-1.1.22/danielutils/reflection/info_classes/argument_info.py +278 -0
  4. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/class_info.py +12 -3
  5. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/decorator_info.py +11 -2
  6. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/function_info.py +15 -2
  7. danielutils-1.1.22/danielutils/tools/__init__.py +1 -0
  8. danielutils-1.1.22/danielutils/tools/unittest_test_runner/__init__.py +9 -0
  9. danielutils-1.1.22/danielutils/tools/unittest_test_runner/cli.py +70 -0
  10. danielutils-1.1.22/danielutils/tools/unittest_test_runner/core/__init__.py +17 -0
  11. danielutils-1.1.22/danielutils/tools/unittest_test_runner/core/discovery.py +322 -0
  12. danielutils-1.1.22/danielutils/tools/unittest_test_runner/core/execution.py +244 -0
  13. danielutils-1.1.22/danielutils/tools/unittest_test_runner/core/parser.py +163 -0
  14. danielutils-1.1.22/danielutils/tools/unittest_test_runner/core/runner.py +561 -0
  15. danielutils-1.1.22/danielutils/tools/unittest_test_runner/models.py +82 -0
  16. {danielutils-1.1.2 → danielutils-1.1.22/danielutils.egg-info}/PKG-INFO +2 -2
  17. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils.egg-info/SOURCES.txt +9 -0
  18. {danielutils-1.1.2 → danielutils-1.1.22}/pyproject.toml +1 -1
  19. danielutils-1.1.2/danielutils/reflection/info_classes/argument_info.py +0 -124
  20. {danielutils-1.1.2 → danielutils-1.1.22}/LICENSE +0 -0
  21. {danielutils-1.1.2 → danielutils-1.1.22}/MANIFEST.in +0 -0
  22. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/__init__.py +0 -0
  23. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/__init__.py +0 -0
  24. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/__init__.py +0 -0
  25. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database.py +0 -0
  26. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database_definitions.py +0 -0
  27. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database_exceptions.py +0 -0
  28. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database_factory.py +0 -0
  29. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database_initializer.py +0 -0
  30. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/database_models.py +0 -0
  31. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/dependencies.py +0 -0
  32. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/implementations/__init__.py +0 -0
  33. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/implementations/in_memory_database.py +0 -0
  34. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/implementations/persistent_in_memory_database.py +0 -0
  35. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/implementations/redis_database.py +0 -0
  36. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/db/implementations/sqlite_database.py +0 -0
  37. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/multiprogramming/__init__.py +0 -0
  38. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/multiprogramming/multi_id.py +0 -0
  39. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/multiprogramming/worker.py +0 -0
  40. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/multiprogramming/worker_pool.py +0 -0
  41. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/abstractions/repl.py +0 -0
  42. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/aliases.py +0 -0
  43. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/__init__.py +0 -0
  44. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/async_cmd.py +0 -0
  45. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/async_command.py +0 -0
  46. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/async_layered_command.py +0 -0
  47. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/async_retry_executor.py +0 -0
  48. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/async_worker_pool.py +0 -0
  49. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/time_strategy.py +0 -0
  50. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/async_/utils.py +0 -0
  51. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/__init__.py +0 -0
  52. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/counter.py +0 -0
  53. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/frange.py +0 -0
  54. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/__init__.py +0 -0
  55. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/factory.py +0 -0
  56. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/tdict.py +0 -0
  57. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/tlist.py +0 -0
  58. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/tset.py +0 -0
  59. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/better_builtins/typed_builtins/ttuple.py +0 -0
  60. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/colors.py +0 -0
  61. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/__init__.py +0 -0
  62. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/attr_context.py +0 -0
  63. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/multi_context.py +0 -0
  64. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/optional_context.py +0 -0
  65. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/state_context.py +0 -0
  66. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/context_managers/temporary_file.py +0 -0
  67. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/convenience.py +0 -0
  68. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/conversions/__init__.py +0 -0
  69. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/conversions/main_conversions.py +0 -0
  70. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/conversions/specialized_conversions/__init__.py +0 -0
  71. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/conversions/specialized_conversions/to_hex.py +0 -0
  72. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/conversions/specialized_conversions/to_int.py +0 -0
  73. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/custom_types.py +0 -0
  74. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/__init__.py +0 -0
  75. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/algorithms.py +0 -0
  76. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/comparer.py +0 -0
  77. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/default_dict.py +0 -0
  78. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/functions.py +0 -0
  79. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/graph/__init__.py +0 -0
  80. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/graph/binary_node.py +0 -0
  81. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/graph/graph.py +0 -0
  82. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/graph/multinode.py +0 -0
  83. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/graph/node.py +0 -0
  84. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/heap/__init__.py +0 -0
  85. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/heap/heap.py +0 -0
  86. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/heap/max_heap.py +0 -0
  87. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/heap/min_heap.py +0 -0
  88. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/queue/__init__.py +0 -0
  89. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/queue/atomic_queue.py +0 -0
  90. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/queue/priority_queue.py +0 -0
  91. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/queue/queue.py +0 -0
  92. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/stack.py +0 -0
  93. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/trees/__init__.py +0 -0
  94. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/trees/binary_syntax_tree.py +0 -0
  95. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/data_structures/trees/binary_tree.py +0 -0
  96. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/date.py +0 -0
  97. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/date_time.py +0 -0
  98. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/__init__.py +0 -0
  99. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/atomic.py +0 -0
  100. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/attach.py +0 -0
  101. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/chain_decorators.py +0 -0
  102. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/decorate_conditionally.py +0 -0
  103. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/delay_call.py +0 -0
  104. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/deprecate.py +0 -0
  105. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/final.py +0 -0
  106. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/limit_recursion.py +0 -0
  107. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/memo.py +0 -0
  108. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/normalize_decorator.py +0 -0
  109. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/overload.py +0 -0
  110. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/partially_implemented.py +0 -0
  111. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/processify.py +0 -0
  112. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/property.py +0 -0
  113. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/singleton.py +0 -0
  114. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/threadify.py +0 -0
  115. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/timeout.py +0 -0
  116. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/total_ordering.py +0 -0
  117. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/decorators/validate.py +0 -0
  118. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/exceptions.py +0 -0
  119. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/__init__.py +0 -0
  120. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/areoneof.py +0 -0
  121. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/check_foreach.py +0 -0
  122. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/factorial.py +0 -0
  123. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/flatten.py +0 -0
  124. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/foreach.py +0 -0
  125. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/isoftype.py +0 -0
  126. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/isoneof.py +0 -0
  127. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/multiloop.py +0 -0
  128. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/parallel_for.py +0 -0
  129. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/partition.py +0 -0
  130. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/powerset.py +0 -0
  131. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/subseteq.py +0 -0
  132. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/functions/types_subseteq.py +0 -0
  133. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/generators/__init__.py +0 -0
  134. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/generators/conditional_generator.py +0 -0
  135. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/generators/generator_from_stream.py +0 -0
  136. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/generators/join_generators.py +0 -0
  137. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/internet.py +0 -0
  138. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/io_.py +0 -0
  139. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/java/__init__.py +0 -0
  140. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/java/interfaces/__init__.py +0 -0
  141. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/java/interfaces/comparable.py +0 -0
  142. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/java/java_interface.py +0 -0
  143. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/__init__.py +0 -0
  144. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/__init__.py +0 -0
  145. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/builtin_impls/__init__.py +0 -0
  146. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/builtin_impls/file_logger.py +0 -0
  147. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/builtin_impls/print_logger.py +0 -0
  148. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/log_level.py +0 -0
  149. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/logger.py +0 -0
  150. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/_impl/logger_strategy_impl_base.py +0 -0
  151. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/logging_/utils.py +0 -0
  152. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/lombok/__init__.py +0 -0
  153. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/lombok/builder.py +0 -0
  154. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/math_/__init__.py +0 -0
  155. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/math_/constants.py +0 -0
  156. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/math_/functions.py +0 -0
  157. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/math_/math_print.py +0 -0
  158. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/math_/math_symbols.py +0 -0
  159. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/__init__.py +0 -0
  160. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/atomic_class_meta.py +0 -0
  161. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/implicit_data_deleter_meta.py +0 -0
  162. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/instance_cache_meta.py +0 -0
  163. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/interface.py +0 -0
  164. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/metaclasses/overload_meta.py +0 -0
  165. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/mock_/__init__.py +0 -0
  166. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/mock_/mock_module.py +0 -0
  167. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/path.py +0 -0
  168. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/print_.py +0 -0
  169. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/progress_bar/__init__.py +0 -0
  170. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/progress_bar/ascii_progress_bar.py +0 -0
  171. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/progress_bar/progress_bar.py +0 -0
  172. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/progress_bar/progress_bar_pool.py +0 -0
  173. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/protocols/__init__.py +0 -0
  174. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/protocols/dictable.py +0 -0
  175. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/protocols/evaluable.py +0 -0
  176. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/protocols/serializable.py +0 -0
  177. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/py.typed +0 -0
  178. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/random_.py +0 -0
  179. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/__init__.py +0 -0
  180. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/file/__init__.py +0 -0
  181. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/file/file_reflection.py +0 -0
  182. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/function/__init__.py +0 -0
  183. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/function/function_reflections.py +0 -0
  184. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/__init__.py +0 -0
  185. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/file_info.py +0 -0
  186. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/folder_info.py +0 -0
  187. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/info_classes/import_info.py +0 -0
  188. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/__init__.py +0 -0
  189. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/callstack.py +0 -0
  190. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/get_traceback.py +0 -0
  191. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/interpreter.py +0 -0
  192. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/is_debugging.py +0 -0
  193. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/os_.py +0 -0
  194. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/packages.py +0 -0
  195. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/python_version.py +0 -0
  196. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/signals.py +0 -0
  197. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/interpreter/tracer.py +0 -0
  198. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/module/__init__.py +0 -0
  199. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/module/lazy_module.py +0 -0
  200. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/module/module_reflections.py +0 -0
  201. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/reflection/module/package_reflection.py +0 -0
  202. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/__init__.py +0 -0
  203. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/__init__.py +0 -0
  204. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/constant_backoff.py +0 -0
  205. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/exponential_backoff.py +0 -0
  206. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/functional_backoff.py +0 -0
  207. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/linear_backoff.py +0 -0
  208. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +0 -0
  209. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategies/no_backoff.py +0 -0
  210. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/backoff_strategy.py +0 -0
  211. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/retry_executor/retry_executor.py +0 -0
  212. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/snippets/__init__.py +0 -0
  213. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/snippets/try_get.py +0 -0
  214. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/__init__.py +0 -0
  215. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/independent.py +0 -0
  216. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/layered_command.py +0 -0
  217. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/windows/__init__.py +0 -0
  218. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/windows/utils/__init__.py +0 -0
  219. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/windows/utils/filetime.py +0 -0
  220. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/windows/win32_ctime.py +0 -0
  221. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/system/windows/windows.py +0 -0
  222. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/testing/__init__.py +0 -0
  223. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/testing/unittest_/__init__.py +0 -0
  224. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/testing/unittest_/always_teardown_testcase.py +0 -0
  225. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/testing/unittest_/auto_cwd_testcase.py +0 -0
  226. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/text.py +0 -0
  227. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/time.py +0 -0
  228. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/__init__.py +0 -0
  229. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/__init__.py +0 -0
  230. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/discreate_finite_automaton.py +0 -0
  231. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
  232. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/languages/language.py +0 -0
  233. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/languages/sat.py +0 -0
  234. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/computability_and_complexity/turing_machine.py +0 -0
  235. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/databases/__init__.py +0 -0
  236. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/databases/all.py +0 -0
  237. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/__init__.py +0 -0
  238. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/__init__.py +0 -0
  239. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/encoding.py +0 -0
  240. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossless/__init__.py +0 -0
  241. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
  242. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +0 -0
  243. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
  244. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossless/run_length.py +0 -0
  245. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossy/__init__.py +0 -0
  246. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +0 -0
  247. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
  248. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
  249. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
  250. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/hough.py +0 -0
  251. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
  252. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/image_proccesing/tansformations/transformation.py +0 -0
  253. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/linear_algebra/__init__.py +0 -0
  254. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/linear_algebra/matrix.py +0 -0
  255. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/machine_learning/__init__.py +0 -0
  256. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/machine_learning/activation_functions/__init__.py +0 -0
  257. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/machine_learning/activation_functions/activation_function.py +0 -0
  258. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/machine_learning/activation_functions/relu.py +0 -0
  259. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/machine_learning/neuron.py +0 -0
  260. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/oop/__init__.py +0 -0
  261. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/oop/observer.py +0 -0
  262. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/oop/strategy.py +0 -0
  263. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/__init__.py +0 -0
  264. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/__init__.py +0 -0
  265. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/conditional_variable.py +0 -0
  266. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
  267. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/__init__.py +0 -0
  268. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/bernoulli.py +0 -0
  269. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/binomial.py +0 -0
  270. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +0 -0
  271. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/discrete.py +0 -0
  272. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/geometric.py +0 -0
  273. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/poisson.py +0 -0
  274. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/conditional_variable/discrete/uniform.py +0 -0
  275. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/distributions.py +0 -0
  276. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/expressions/__init__.py +0 -0
  277. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/expressions/accumulation_expression.py +0 -0
  278. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/expressions/probability_expression.py +0 -0
  279. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/funcs/__init__.py +0 -0
  280. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/funcs/covariance.py +0 -0
  281. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/funcs/expected_value.py +0 -0
  282. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/funcs/probability_function.py +0 -0
  283. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/funcs/variance.py +0 -0
  284. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/operator.py +0 -0
  285. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/protocols.py +0 -0
  286. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/supp.py +0 -0
  287. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/university/probability/transformation.py +0 -0
  288. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils/versioned_imports.py +0 -0
  289. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils.egg-info/dependency_links.txt +0 -0
  290. {danielutils-1.1.2 → danielutils-1.1.22}/danielutils.egg-info/top_level.txt +0 -0
  291. {danielutils-1.1.2 → danielutils-1.1.22}/setup.cfg +0 -0
  292. {danielutils-1.1.2 → danielutils-1.1.22}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: danielutils
3
- Version: 1.1.2
3
+ Version: 1.1.22
4
4
  Summary: A python utils library for things I find useful
5
5
  Author-email: danielnachumdev <danielnachumdev@gmail.com>
6
6
  License: MIT License
@@ -41,7 +41,7 @@ Dynamic: license-file
41
41
  [![gitleaks](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml/badge.svg)](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml)
42
42
  [![CodeQL](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql)
43
43
 
44
- # danielutils v1.0.51
44
+ # danielutils v1.1.21
45
45
 
46
46
  A comprehensive Python utilities library designed to enhance your development workflow with powerful tools for type safety, async programming, database operations, and much more.
47
47
 
@@ -4,7 +4,7 @@
4
4
  [![gitleaks](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml/badge.svg)](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml)
5
5
  [![CodeQL](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql)
6
6
 
7
- # danielutils v1.0.51
7
+ # danielutils v1.1.21
8
8
 
9
9
  A comprehensive Python utilities library designed to enhance your development workflow with powerful tools for type safety, async programming, database operations, and much more.
10
10
 
@@ -0,0 +1,278 @@
1
+ import re
2
+ from dataclasses import dataclass
3
+ from typing import Optional, List
4
+
5
+ ARGUMENT_INFO_REGEX: re.Pattern = re.compile(
6
+ r"(?P<kwargs>\*\*\w[\w\d]*)|(?P<args>\*(?:\w[\w\d]*)?)|(?P<kwarg_only>\/)|(?P<pname>\w[\w\d]*)\[(?P<parameters>.+)\]|(?P<name>\w[\w\d]*)(?:(?:\s*:(?P<type>[^\=\n]+))?(?:\s*=(?P<default_value>[\s\S]+))?)?")
7
+
8
+
9
+ class ArgumentInfo:
10
+ def __init__(
11
+ self,
12
+ name: Optional[str],
13
+ type: Optional[str],
14
+ default: Optional[str],
15
+ is_kwargs: bool,
16
+ is_args: bool,
17
+ is_kwargs_only: bool,
18
+ parameters: Optional[List]
19
+ ) -> None:
20
+ self._name = name
21
+ self._type = type
22
+ self._default = default
23
+ self._is_kwargs = is_kwargs
24
+ self._is_args = is_args
25
+ self._is_kwargs_only = is_kwargs_only
26
+ self._parameters = parameters
27
+
28
+ @property
29
+ def name(self) -> Optional[str]:
30
+ return self._name
31
+
32
+ @property
33
+ def type(self) -> Optional[str]:
34
+ return self._type
35
+
36
+ @property
37
+ def default(self) -> Optional[str]:
38
+ return self._default
39
+
40
+ @property
41
+ def is_kwargs(self) -> bool:
42
+ return self._is_kwargs
43
+
44
+ @property
45
+ def is_args(self) -> bool:
46
+ return self._is_args
47
+
48
+ @property
49
+ def is_kwargs_only(self) -> bool:
50
+ return self._is_kwargs_only
51
+
52
+ @property
53
+ def parameters(self) -> Optional[List]:
54
+ return self._parameters
55
+
56
+ @property
57
+ def is_parameterized(self) -> bool:
58
+ return self._parameters is not None and len(self._parameters) > 0
59
+
60
+ def __repr__(self) -> str:
61
+ res = f"{self.__class__.__name__}(name=\"{self.name}\""
62
+ if self.type is not None:
63
+ res += f", type={self.type}"
64
+ if self.default is not None:
65
+ res += f", default={self.default}"
66
+ if self.is_parameterized:
67
+ res += f", parameters={self.parameters}"
68
+ return res + ")"
69
+
70
+ def __str__(self) -> str:
71
+ return repr(self)
72
+
73
+ @staticmethod
74
+ def _parse_one(string: str) -> 'ArgumentInfo':
75
+ string = string.strip()
76
+
77
+ # Handle string literals (decorator context)
78
+ if string.startswith('"') or string.startswith("'"):
79
+ # Extract the string literal (handling escaped quotes)
80
+ quote_char = string[0]
81
+ # Find the matching closing quote
82
+ i = 1
83
+ while i < len(string):
84
+ if string[i] == quote_char and (i == 0 or string[i-1] != '\\'):
85
+ # Found matching quote
86
+ literal_value = string[:i+1]
87
+ return ArgumentInfo(
88
+ name=None,
89
+ type=None,
90
+ default=literal_value,
91
+ is_kwargs=False,
92
+ is_args=False,
93
+ is_kwargs_only=False,
94
+ parameters=None
95
+ )
96
+ i += 1
97
+ # If no closing quote found, treat the whole string as the literal
98
+ return ArgumentInfo(
99
+ name=None,
100
+ type=None,
101
+ default=string,
102
+ is_kwargs=False,
103
+ is_args=False,
104
+ is_kwargs_only=False,
105
+ parameters=None
106
+ )
107
+
108
+ # Handle other literals (numbers, booleans, None, etc.) - check BEFORE regex
109
+ # In decorator context, these are always literals, not parameter definitions
110
+ if string:
111
+ # Check for numeric literal (starts with digit, possibly with decimal point or negative)
112
+ if string[0].isdigit() or (len(string) > 1 and string[0] == '-' and string[1].isdigit()):
113
+ return ArgumentInfo(
114
+ name=None,
115
+ type=None,
116
+ default=string,
117
+ is_kwargs=False,
118
+ is_args=False,
119
+ is_kwargs_only=False,
120
+ parameters=None
121
+ )
122
+ # Check for boolean or None literals
123
+ if string in ('True', 'False', 'None'):
124
+ return ArgumentInfo(
125
+ name=None,
126
+ type=None,
127
+ default=string,
128
+ is_kwargs=False,
129
+ is_args=False,
130
+ is_kwargs_only=False,
131
+ parameters=None
132
+ )
133
+ # Check for list/dict literals or function calls (starts with bracket, brace, or identifier followed by paren)
134
+ if string.startswith('[') or string.startswith('{') or string.startswith('('):
135
+ return ArgumentInfo(
136
+ name=None,
137
+ type=None,
138
+ default=string,
139
+ is_kwargs=False,
140
+ is_args=False,
141
+ is_kwargs_only=False,
142
+ parameters=None
143
+ )
144
+ # Check for function call pattern (identifier followed by opening paren)
145
+ # This handles cases like "some_function(1, 2)"
146
+ if '(' in string and not string.startswith('='):
147
+ # Check if it looks like a function call (has identifier before paren)
148
+ parts = string.split('(', 1)
149
+ if len(parts) == 2 and parts[0].strip() and (parts[0].strip()[0].isalpha() or parts[0].strip()[0] == '_'):
150
+ return ArgumentInfo(
151
+ name=None,
152
+ type=None,
153
+ default=string,
154
+ is_kwargs=False,
155
+ is_args=False,
156
+ is_kwargs_only=False,
157
+ parameters=None
158
+ )
159
+
160
+ # Try regex matching for normal argument patterns
161
+ m = ARGUMENT_INFO_REGEX.match(string)
162
+ if m is None:
163
+ raise ValueError(f"Invalid argument info string: {string}")
164
+
165
+ kwargs, args, kwarg_only, pname, parameters, name, type, default_value = m.groups()
166
+ type = None if type is None else type.strip()
167
+ default_value = None if default_value is None else default_value.strip()
168
+
169
+ return ArgumentInfo(
170
+ name=name or pname or (args.strip("*") if args else None) or (
171
+ kwargs.strip("*") if kwargs else None) or (kwarg_only if kwarg_only else None) or None,
172
+ type=type,
173
+ default=default_value,
174
+ is_kwargs=kwargs is not None,
175
+ is_args=args is not None,
176
+ is_kwargs_only=kwarg_only is not None,
177
+ parameters=[parameters]
178
+ )
179
+
180
+ @staticmethod
181
+ def _strip_comments(string: str) -> str:
182
+ """Strip comments from string while preserving string literals."""
183
+ result = []
184
+ in_string = False
185
+ string_char = None
186
+ i = 0
187
+ while i < len(string):
188
+ c = string[i]
189
+ # Track string literals
190
+ if c in {'"', "'"} and (i == 0 or string[i-1] != '\\'):
191
+ if not in_string:
192
+ in_string = True
193
+ string_char = c
194
+ elif c == string_char:
195
+ in_string = False
196
+ string_char = None
197
+ result.append(c)
198
+ # Handle comments (only when not in string)
199
+ elif not in_string and c == '#':
200
+ # Skip everything from # to end of line (or end of string)
201
+ # Keep the newline if present to preserve line structure
202
+ while i < len(string) and string[i] != '\n':
203
+ i += 1
204
+ # Include the newline if we found one
205
+ if i < len(string) and string[i] == '\n':
206
+ result.append('\n')
207
+ i += 1
208
+ continue
209
+ else:
210
+ # End of string, break
211
+ break
212
+ else:
213
+ result.append(c)
214
+ i += 1
215
+ return ''.join(result)
216
+
217
+ @staticmethod
218
+ def from_str(string: str) -> List['ArgumentInfo']:
219
+ if string is None:
220
+ return []
221
+ string = string.strip()
222
+ if not string:
223
+ return []
224
+ # Strip comments before processing
225
+ string = ArgumentInfo._strip_comments(string).strip()
226
+ indices = [-1]
227
+ stack: List[str] = []
228
+ in_string = False
229
+ string_char = None
230
+ for i, c in enumerate(string):
231
+ # Track string literals
232
+ if c in {'"', "'"} and (i == 0 or string[i-1] != '\\'):
233
+ if not in_string:
234
+ in_string = True
235
+ string_char = c
236
+ elif c == string_char:
237
+ in_string = False
238
+ string_char = None
239
+ # Track brackets, braces, and parentheses only when not in string
240
+ elif not in_string:
241
+ if c in {'[', ']', '{', '}', '(', ')'}:
242
+ if c in {'[', '{', '('}:
243
+ stack.append(c)
244
+ else:
245
+ # Match closing brackets/braces/parens with opening ones
246
+ if stack:
247
+ opening = stack[-1]
248
+ if (c == ']' and opening == '[') or \
249
+ (c == '}' and opening == '{') or \
250
+ (c == ')' and opening == '('):
251
+ stack.pop()
252
+ elif len(stack) == 0:
253
+ if c == ",":
254
+ indices.append(i)
255
+ indices.append(len(string))
256
+ res = []
257
+ for idx, (start, end) in enumerate(zip(indices[:-1], indices[1:])):
258
+ substr = string[start + 1:end].strip()
259
+ # Skip standalone * (keyword-only separator)
260
+ if substr == "*":
261
+ continue
262
+ # Skip empty strings (from comment-only lines)
263
+ if not substr:
264
+ continue
265
+ try:
266
+ res.append(ArgumentInfo._parse_one(substr))
267
+ except ValueError as e:
268
+ raise ValueError(
269
+ f"Failed to parse argument {idx + 1}: {e}\n"
270
+ f"Argument string: {repr(substr)}\n"
271
+ f"Full arguments string: {repr(string)}"
272
+ ) from e
273
+ return res
274
+
275
+
276
+ __all__ = [
277
+ "ArgumentInfo",
278
+ ]
@@ -75,7 +75,13 @@ class ClassInfo:
75
75
  decorators, name, bases, _ = m.groupdict().values()
76
76
  logger.debug("Parsed class name: %s, bases: %s", name, bases)
77
77
  self._name = name
78
- self._bases = ArgumentInfo.from_str(bases)
78
+ try:
79
+ self._bases = ArgumentInfo.from_str(bases)
80
+ except ValueError as e:
81
+ raise ValueError(
82
+ f"Failed to parse base classes for class '{name}': {e}\n"
83
+ f"Bases string: {repr(bases)}"
84
+ ) from e
79
85
  logger.debug("Parsed %s base classes", len(self._bases))
80
86
  self._parse_body()
81
87
 
@@ -87,8 +93,11 @@ class ClassInfo:
87
93
  self._decorations.append(
88
94
  DecoratorInfo.from_str(substr.strip()))
89
95
  except ValueError as e:
90
- logger.warning(
91
- "Failed to parse decorator '%s': %s", substr.strip(), e)
96
+ error_msg = (
97
+ f"Failed to parse decorator for class '{name}': {e}\n"
98
+ f"Decorator string: {repr(substr.strip())}"
99
+ )
100
+ logger.warning(error_msg)
92
101
  # Skip invalid decorators
93
102
  continue
94
103
  logger.debug("Parsed %s decorators", len(self._decorations))
@@ -25,10 +25,19 @@ class DecoratorInfo:
25
25
  def from_str(string: str) -> 'DecoratorInfo':
26
26
  m = DecoratorInfo.DECORATOR_INFO_REGEX.match(string)
27
27
  if m is None:
28
- raise ValueError()
28
+ raise ValueError(f"Invalid decorator format: {repr(string)}")
29
29
 
30
30
  name, arguments = m.groups()
31
- args = ArgumentInfo.from_str(arguments)
31
+ if arguments:
32
+ try:
33
+ args = ArgumentInfo.from_str(arguments)
34
+ except ValueError as e:
35
+ raise ValueError(
36
+ f"Failed to parse arguments for decorator '{name}': {e}\n"
37
+ f"Arguments string: {repr(arguments)}"
38
+ ) from e
39
+ else:
40
+ args = []
32
41
  return DecoratorInfo(name, args)
33
42
 
34
43
  def __str__(self) -> str:
@@ -166,13 +166,26 @@ class FunctionInfo:
166
166
  decorators, async_, name, arguments, return_type, body = m.groups()
167
167
  if decorators is not None:
168
168
  for substr in decorators.strip().splitlines():
169
- self._decorators.append(DecoratorInfo.from_str(substr.strip()))
169
+ try:
170
+ self._decorators.append(
171
+ DecoratorInfo.from_str(substr.strip()))
172
+ except ValueError as e:
173
+ raise ValueError(
174
+ f"Failed to parse decorator for function '{name}': {e}\n"
175
+ f"Decorator string: {repr(substr.strip())}"
176
+ ) from e
170
177
 
171
178
  self._is_async = async_ is not None
172
179
 
173
180
  self._name = name
174
181
  if arguments is not None:
175
- all_args = ArgumentInfo.from_str(arguments)
182
+ try:
183
+ all_args = ArgumentInfo.from_str(arguments)
184
+ except ValueError as e:
185
+ raise ValueError(
186
+ f"Failed to parse arguments for function '{name}': {e}\n"
187
+ f"Arguments string: {repr(arguments)}"
188
+ ) from e
176
189
  # Filter out separator arguments (/, *) - they are syntax markers, not actual arguments
177
190
  self._arguments = [arg for arg in all_args if not (
178
191
  arg.is_kwargs_only and arg.name == "/") and not (arg.is_args and arg.name is None)]
@@ -0,0 +1 @@
1
+ from .unittest_test_runner import *
@@ -0,0 +1,9 @@
1
+ """
2
+ Test Runner Module
3
+
4
+ A comprehensive test runner with hierarchical execution and smart skipping capabilities.
5
+ """
6
+
7
+ from .core import *
8
+ from .models import *
9
+ from .cli import main
@@ -0,0 +1,70 @@
1
+ """
2
+ Command-line interface for the test runner using Google Fire.
3
+ """
4
+
5
+ import logging
6
+ import fire
7
+ from typing import Optional, Literal
8
+ from .core import TestRunner, VerboseLevel
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def run_tests(python_path: Optional[str] = None,
14
+ results_file: str = "test_results.json",
15
+ skip_threshold: int = 24,
16
+ force: bool = False,
17
+ test_name: Optional[str] = None,
18
+ target: Optional[str] = None,
19
+ verbose: VerboseLevel = "class",
20
+ show_function_results: bool = False):
21
+ """
22
+ Run tests with smart skipping and detailed reporting.
23
+
24
+ Args:
25
+ python_path: Path to Python executable to use for running tests (defaults to current Python)
26
+ results_file: JSON file to store/load results (default: test_results.json)
27
+ skip_threshold: Hours after which to re-run previously passing tests (default: 24)
28
+ force: Force run all tests, ignoring previous results
29
+ test_name: Run only a specific test module (e.g., tests.abstractions.db.test_in_memory_database)
30
+ target: unittest dot-notation target (e.g., tests.module.class.function)
31
+ verbose: Verbose level - module/file/class/function (default: class)
32
+ show_function_results: Show pass/fail status for each individual test function within modules
33
+ """
34
+ logger.info("Starting test run with parameters: python_path=%s, results_file=%s, skip_threshold=%d, force=%s, target=%s, verbose=%s",
35
+ python_path, results_file, skip_threshold, force, target, verbose)
36
+
37
+ runner = TestRunner(
38
+ python_path=python_path,
39
+ results_file=results_file,
40
+ skip_threshold_hours=skip_threshold,
41
+ force_run=force,
42
+ test_name=test_name,
43
+ target=target,
44
+ verbose=verbose,
45
+ show_function_results=show_function_results
46
+ )
47
+
48
+ try:
49
+ logger.info("Executing all tests")
50
+ runner.run_all_tests()
51
+ logger.info("Saving results to JSON file: %s", results_file)
52
+ runner.save_results_json()
53
+ logger.info("Test run completed successfully")
54
+ except KeyboardInterrupt:
55
+ logger.warning("Test run interrupted by user")
56
+ print("\nTest run interrupted by user.")
57
+ except Exception as e:
58
+ logger.error("Error during test run: %s", e)
59
+ print(f"Error during test run: {e}")
60
+ raise
61
+
62
+
63
+ def main():
64
+ """Main entry point for the CLI."""
65
+ logger.info("Starting CLI main entry point")
66
+ fire.Fire(run_tests)
67
+
68
+
69
+ if __name__ == "__main__":
70
+ main()
@@ -0,0 +1,17 @@
1
+ """
2
+ Core test runner modules.
3
+
4
+ This package contains the core functionality split by responsibility:
5
+ - discovery: Test discovery and structure analysis
6
+ - execution: Test execution hierarchy
7
+ - parser: Output parsing and result processing
8
+ - runner: Main TestRunner orchestration
9
+ - types: Type definitions and data structures
10
+ """
11
+
12
+ from .runner import TestRunner
13
+
14
+ # Define VerboseLevel here since it's a simple type alias
15
+ from typing import Literal
16
+ VerboseLevel = Literal["module", "file", "class", "function"]
17
+