danielutils 1.0.52__tar.gz → 1.1.1__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.
- {danielutils-1.0.52/danielutils.egg-info → danielutils-1.1.1}/PKG-INFO +1 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/__init__.py +0 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database.py +37 -5
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_factory.py +12 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_initializer.py +21 -15
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/implementations/in_memory_database.py +6 -6
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/implementations/persistent_in_memory_database.py +2 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/implementations/redis_database.py +8 -9
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/implementations/sqlite_database.py +10 -13
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/multiprogramming/worker.py +34 -6
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/multiprogramming/worker_pool.py +24 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/repl.py +37 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/__init__.py +1 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/async_cmd.py +6 -1
- danielutils-1.1.1/danielutils/async_/async_command.py +866 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/async_layered_command.py +20 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/async_retry_executor.py +15 -19
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/async_worker_pool.py +39 -36
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/time_strategy.py +12 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/async_/utils.py +10 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/frange.py +32 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/colors.py +7 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/context_managers/attr_context.py +14 -0
- danielutils-1.1.1/danielutils/context_managers/multi_context.py +34 -0
- danielutils-1.1.1/danielutils/context_managers/optional_context.py +33 -0
- danielutils-1.1.1/danielutils/context_managers/state_context.py +25 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/context_managers/temporary_file.py +24 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/algorithms.py +9 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/comparer.py +8 -1
- danielutils-1.1.1/danielutils/data_structures/default_dict.py +23 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/functions.py +10 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/graph/graph.py +17 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/heap/heap.py +24 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/queue/queue.py +22 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/stack.py +14 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/date.py +11 -2
- danielutils-1.1.1/danielutils/date_time.py +23 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/atomic.py +10 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/attach.py +12 -0
- danielutils-1.1.1/danielutils/decorators/chain_decorators.py +39 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/delay_call.py +12 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/limit_recursion.py +12 -0
- danielutils-1.1.1/danielutils/decorators/memo.py +68 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/overload.py +4 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/processify.py +16 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/singleton.py +19 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/threadify.py +10 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/timeout.py +18 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/validate.py +9 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/exceptions.py +7 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/areoneof.py +12 -1
- danielutils-1.1.1/danielutils/functions/check_foreach.py +39 -0
- danielutils-1.1.1/danielutils/functions/factorial.py +24 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/flatten.py +5 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/foreach.py +6 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/isoftype.py +12 -5
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/isoneof.py +18 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/multiloop.py +10 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/parallel_for.py +10 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/partition.py +9 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/powerset.py +11 -0
- danielutils-1.1.1/danielutils/functions/subseteq.py +25 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/types_subseteq.py +14 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/generators/conditional_generator.py +20 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/generators/generator_from_stream.py +10 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/generators/join_generators.py +31 -3
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/internet.py +7 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/io_.py +9 -2
- danielutils-1.1.1/danielutils/java/__init__.py +17 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/java/java_interface.py +23 -5
- danielutils-1.1.1/danielutils/logging_/__init__.py +2 -0
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/builtin_impls/file_logger.py +13 -3
- danielutils-1.1.1/danielutils/logging_/_impl/builtin_impls/print_logger.py +21 -0
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/logger.py +18 -8
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/logger_strategy_impl_base.py +8 -0
- danielutils-1.1.1/danielutils/logging_/utils.py +199 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/lombok/builder.py +24 -5
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/math_/math_print.py +8 -0
- danielutils-1.1.1/danielutils/metaclasses/atomic_class_meta.py +36 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/metaclasses/implicit_data_deleter_meta.py +11 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/metaclasses/instance_cache_meta.py +20 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/metaclasses/interface.py +15 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/metaclasses/overload_meta.py +9 -20
- danielutils-1.1.1/danielutils/mock_/mock_module.py +27 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/path.py +4 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/print_.py +5 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/progress_bar/ascii_progress_bar.py +9 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/progress_bar/progress_bar.py +7 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/progress_bar/progress_bar_pool.py +10 -2
- danielutils-1.1.1/danielutils/protocols/dictable.py +38 -0
- danielutils-1.1.1/danielutils/protocols/evaluable.py +26 -0
- danielutils-1.1.1/danielutils/protocols/serializable.py +51 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/class_/class_reflection.py +38 -12
- danielutils-1.1.1/danielutils/reflection/file/file_reflection.py +85 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/function/function_reflections.py +11 -3
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/argument_info.py +1 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/class_info.py +17 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/file_info.py +2 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/folder_info.py +5 -5
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/function_info.py +1 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/callstack.py +16 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/python_version.py +9 -2
- danielutils-1.1.1/danielutils/reflection/module/__init__.py +3 -0
- danielutils-1.1.1/danielutils/reflection/module/lazy_module.py +104 -0
- danielutils-1.1.1/danielutils/reflection/module/module_reflections.py +34 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/constant_backoff.py +5 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/exponential_backoff.py +7 -1
- danielutils-1.1.1/danielutils/retry_executor/backoff_strategies/functional_backoff.py +29 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/linear_backoff.py +6 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +6 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/no_backoff.py +5 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategy.py +7 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/retry_executor.py +17 -5
- danielutils-1.1.1/danielutils/snippets/try_get.py +28 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/independent.py +11 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/layered_command.py +12 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/testing/unittest_/always_teardown_testcase.py +8 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/testing/unittest_/auto_cwd_testcase.py +14 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/text.py +8 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/time.py +8 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/languages/sat.py +1 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossless/run_length.py +1 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/linear_algebra/matrix.py +8 -2
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/versioned_imports.py +3 -3
- {danielutils-1.0.52 → danielutils-1.1.1/danielutils.egg-info}/PKG-INFO +1 -1
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils.egg-info/SOURCES.txt +10 -7
- {danielutils-1.0.52 → danielutils-1.1.1}/pyproject.toml +1 -1
- danielutils-1.0.52/danielutils/context_managers/multi_context.py +0 -23
- danielutils-1.0.52/danielutils/context_managers/optional_context.py +0 -18
- danielutils-1.0.52/danielutils/context_managers/state_context.py +0 -16
- danielutils-1.0.52/danielutils/data_structures/default_dict.py +0 -15
- danielutils-1.0.52/danielutils/date_time.py +0 -15
- danielutils-1.0.52/danielutils/decorators/chain_decorators.py +0 -26
- danielutils-1.0.52/danielutils/decorators/memo.py +0 -51
- danielutils-1.0.52/danielutils/file_specifications/__init__.py +0 -72
- danielutils-1.0.52/danielutils/functions/check_foreach.py +0 -26
- danielutils-1.0.52/danielutils/functions/factorial.py +0 -5
- danielutils-1.0.52/danielutils/functions/subseteq.py +0 -16
- danielutils-1.0.52/danielutils/java/__init__.py +0 -8
- danielutils-1.0.52/danielutils/logging_/builtin_impls/print_logger.py +0 -11
- danielutils-1.0.52/danielutils/metaclasses/atomic_class_meta.py +0 -24
- danielutils-1.0.52/danielutils/mock_/mock_module.py +0 -18
- danielutils-1.0.52/danielutils/protocols/dictable.py +0 -20
- danielutils-1.0.52/danielutils/protocols/evaluable.py +0 -15
- danielutils-1.0.52/danielutils/protocols/serializable.py +0 -27
- danielutils-1.0.52/danielutils/reflection/file/file_reflection.py +0 -58
- danielutils-1.0.52/danielutils/reflection/module/__init__.py +0 -2
- danielutils-1.0.52/danielutils/reflection/module/module_reflections.py +0 -20
- danielutils-1.0.52/danielutils/retry_executor/backoff_strategies/functional_backoff.py +0 -20
- danielutils-1.0.52/danielutils/snippets/try_get.py +0 -21
- {danielutils-1.0.52 → danielutils-1.1.1}/LICENSE +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/MANIFEST.in +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/README.md +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_definitions.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_exceptions.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_models.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/dependencies.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/implementations/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/multiprogramming/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/multiprogramming/multi_id.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/aliases.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/counter.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/factory.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/tdict.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/tlist.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/tset.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/better_builtins/typed_builtins/ttuple.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/context_managers/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/convenience.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/conversions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/conversions/main_conversions.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/conversions/specialized_conversions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/conversions/specialized_conversions/to_hex.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/conversions/specialized_conversions/to_int.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/custom_types.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/graph/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/graph/binary_node.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/graph/multinode.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/graph/node.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/heap/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/heap/max_heap.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/heap/min_heap.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/queue/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/queue/atomic_queue.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/queue/priority_queue.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/trees/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/trees/binary_syntax_tree.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/data_structures/trees/binary_tree.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/decorate_conditionally.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/deprecate.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/final.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/normalize_decorator.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/partially_implemented.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/property.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/decorators/total_ordering.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/functions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/generators/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/java/interfaces/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/java/interfaces/comparable.py +0 -0
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/__init__.py +0 -0
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/builtin_impls/__init__.py +0 -0
- {danielutils-1.0.52/danielutils/logging_ → danielutils-1.1.1/danielutils/logging_/_impl}/log_level.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/lombok/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/math_/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/math_/constants.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/math_/functions.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/math_/math_symbols.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/metaclasses/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/mock_/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/progress_bar/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/protocols/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/py.typed +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/random_.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/class_/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/file/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/function/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/decorator_info.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/info_classes/import_info.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/get_traceback.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/interpreter.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/is_debugging.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/os_.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/packages.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/signals.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/interpreter/tracer.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/reflection/module/package_reflection.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/retry_executor/backoff_strategies/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/snippets/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/windows/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/windows/utils/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/windows/utils/filetime.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/windows/win32_ctime.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/system/windows/windows.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/testing/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/testing/unittest_/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/discreate_finite_automaton.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/languages/language.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/computability_and_complexity/turing_machine.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/databases/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/databases/all.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/encoding.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossless/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossy/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/hough.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/image_proccesing/tansformations/transformation.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/linear_algebra/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/machine_learning/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/machine_learning/activation_functions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/machine_learning/activation_functions/activation_function.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/machine_learning/activation_functions/relu.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/machine_learning/neuron.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/oop/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/oop/observer.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/oop/strategy.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/conditional_variable.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/bernoulli.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/binomial.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/discrete.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/geometric.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/poisson.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/conditional_variable/discrete/uniform.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/distributions.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/expressions/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/expressions/accumulation_expression.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/expressions/probability_expression.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/funcs/__init__.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/funcs/covariance.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/funcs/expected_value.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/funcs/probability_function.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/funcs/variance.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/operator.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/protocols.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/supp.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils/university/probability/transformation.py +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils.egg-info/dependency_links.txt +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/danielutils.egg-info/top_level.txt +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/setup.cfg +0 -0
- {danielutils-1.0.52 → danielutils-1.1.1}/setup.py +0 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import functools
|
|
2
|
+
import logging
|
|
2
3
|
from abc import ABC, abstractmethod
|
|
3
4
|
from typing import Dict, Any, List, Callable, TypeVar, cast, Optional, Set
|
|
4
5
|
from .database_exceptions import DBException
|
|
5
6
|
from .database_definitions import TableSchema, SelectQuery, UpdateQuery, DeleteQuery
|
|
7
|
+
from ...logging_.utils import get_logger
|
|
8
|
+
logger = get_logger(__name__)
|
|
6
9
|
|
|
7
10
|
# Type variable for the decorator
|
|
8
11
|
F = TypeVar('F', bound=Callable[..., Any])
|
|
@@ -20,11 +23,17 @@ class Database(ABC):
|
|
|
20
23
|
|
|
21
24
|
@functools.wraps(db_method)
|
|
22
25
|
async def wrapper(self: 'Database', *args: Any, **kwargs: Any) -> Any:
|
|
26
|
+
method_name = db_method.__name__
|
|
27
|
+
logger.debug("Executing database method: %s", method_name)
|
|
23
28
|
try:
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
result = await db_method(self, *args, **kwargs)
|
|
30
|
+
logger.debug("Database method '%s' completed successfully", method_name)
|
|
31
|
+
return result
|
|
32
|
+
except DBException as e:
|
|
33
|
+
logger.error("Database method '%s' failed with DBException: %s", method_name, e)
|
|
26
34
|
raise
|
|
27
35
|
except Exception as e:
|
|
36
|
+
logger.error("Database method '%s' failed with %s: %s", method_name, type(e).__name__, e)
|
|
28
37
|
raise cls._default_class_exception_conversion(e)
|
|
29
38
|
|
|
30
39
|
return cast(F, wrapper)
|
|
@@ -45,6 +54,8 @@ class Database(ABC):
|
|
|
45
54
|
@classmethod
|
|
46
55
|
def __init_subclass__(cls) -> None:
|
|
47
56
|
"""Initialize subclass by wrapping all public methods with exception handling"""
|
|
57
|
+
logger.debug("Initializing Database subclass: %s", cls.__name__)
|
|
58
|
+
wrapped_methods = []
|
|
48
59
|
for name, method in cls.__dict__.items():
|
|
49
60
|
if (
|
|
50
61
|
callable(method) and
|
|
@@ -53,6 +64,8 @@ class Database(ABC):
|
|
|
53
64
|
and name in cls._get_functions_with_auto_converted_exceptions()
|
|
54
65
|
):
|
|
55
66
|
setattr(cls, name, cls._wrap_db_exceptions(method))
|
|
67
|
+
wrapped_methods.append(name)
|
|
68
|
+
logger.debug("Database subclass '%s' initialized with %s wrapped methods: %s", cls.__name__, len(wrapped_methods), wrapped_methods)
|
|
56
69
|
|
|
57
70
|
@classmethod
|
|
58
71
|
def _default_class_exception_conversion(cls, e: Exception) -> Exception:
|
|
@@ -66,6 +79,7 @@ class Database(ABC):
|
|
|
66
79
|
Returns:
|
|
67
80
|
Exception: The converted exception
|
|
68
81
|
"""
|
|
82
|
+
logger.warning("Converting exception %s to DBException: %s", type(e).__name__, e)
|
|
69
83
|
return DBException(f"Database error: {str(e)}")
|
|
70
84
|
|
|
71
85
|
async def __aenter__(self) -> 'Database':
|
|
@@ -75,7 +89,9 @@ class Database(ABC):
|
|
|
75
89
|
Returns:
|
|
76
90
|
Database: The database instance for use in the context
|
|
77
91
|
"""
|
|
92
|
+
logger.debug("Entering database context for %s", self.__class__.__name__)
|
|
78
93
|
await self.connect()
|
|
94
|
+
logger.debug("Database context entered successfully for %s", self.__class__.__name__)
|
|
79
95
|
return self
|
|
80
96
|
|
|
81
97
|
async def __aexit__(self, exc_type: Optional[type], exc_val: Optional[Exception], exc_tb: Optional[Any]) -> None:
|
|
@@ -87,24 +103,35 @@ class Database(ABC):
|
|
|
87
103
|
exc_val: The exception instance that was raised, if any
|
|
88
104
|
exc_tb: The traceback for the exception, if any
|
|
89
105
|
"""
|
|
106
|
+
logger.debug("Exiting database context for %s", self.__class__.__name__)
|
|
107
|
+
if exc_type is not None:
|
|
108
|
+
logger.warning("Database context exited with exception: %s: %s", exc_type.__name__, exc_val)
|
|
90
109
|
await self.disconnect()
|
|
110
|
+
logger.debug("Database context exited successfully for %s", self.__class__.__name__)
|
|
91
111
|
|
|
92
112
|
@abstractmethod
|
|
93
113
|
async def connect(self) -> None:
|
|
94
|
-
"""Establish connection to the database
|
|
114
|
+
"""Establish connection to the database
|
|
115
|
+
Note: Implementations should log connection attempts and results
|
|
116
|
+
"""
|
|
95
117
|
|
|
96
118
|
@abstractmethod
|
|
97
119
|
async def disconnect(self) -> None:
|
|
98
|
-
"""Close the database connection
|
|
120
|
+
"""Close the database connection
|
|
121
|
+
Note: Implementations should log disconnection attempts and results
|
|
122
|
+
"""
|
|
99
123
|
|
|
100
124
|
@abstractmethod
|
|
101
125
|
def is_connected(self) -> bool:
|
|
102
|
-
"""Check if the database connection is open
|
|
126
|
+
"""Check if the database connection is open
|
|
127
|
+
Note: Implementations should log connection status checks
|
|
128
|
+
"""
|
|
103
129
|
|
|
104
130
|
@abstractmethod
|
|
105
131
|
async def get_schemas(self) -> Dict[str, TableSchema]:
|
|
106
132
|
"""
|
|
107
133
|
Get the complete database schema
|
|
134
|
+
Note: Implementations should log schema retrieval operations
|
|
108
135
|
|
|
109
136
|
Returns:
|
|
110
137
|
Dict[str, TableSchema]: Dictionary mapping table names to their schemas
|
|
@@ -114,6 +141,7 @@ class Database(ABC):
|
|
|
114
141
|
async def create_table(self, schema: TableSchema) -> None:
|
|
115
142
|
"""
|
|
116
143
|
Create a new table in the database
|
|
144
|
+
Note: Implementations should log table creation operations
|
|
117
145
|
|
|
118
146
|
Args:
|
|
119
147
|
schema (TableSchema): Schema definition for the table
|
|
@@ -123,6 +151,7 @@ class Database(ABC):
|
|
|
123
151
|
async def insert(self, table: str, data: Dict[str, Any]) -> Any:
|
|
124
152
|
"""
|
|
125
153
|
Insert a record into the specified table
|
|
154
|
+
Note: Implementations should log insert operations with table name and data size
|
|
126
155
|
|
|
127
156
|
Args:
|
|
128
157
|
table (str): Name of the table to insert into
|
|
@@ -136,6 +165,7 @@ class Database(ABC):
|
|
|
136
165
|
async def get(self, query: SelectQuery) -> List[Dict[str, Any]]:
|
|
137
166
|
"""
|
|
138
167
|
Get records from the database
|
|
168
|
+
Note: Implementations should log query operations with table name and result count
|
|
139
169
|
|
|
140
170
|
Args:
|
|
141
171
|
query (SelectQuery): Query definition containing table name, conditions, ordering, etc.
|
|
@@ -148,6 +178,7 @@ class Database(ABC):
|
|
|
148
178
|
async def update(self, query: UpdateQuery) -> int:
|
|
149
179
|
"""
|
|
150
180
|
Update records in the database
|
|
181
|
+
Note: Implementations should log update operations with table name and affected row count
|
|
151
182
|
|
|
152
183
|
Args:
|
|
153
184
|
query (UpdateQuery): Query definition containing table name, conditions, and data to update
|
|
@@ -160,6 +191,7 @@ class Database(ABC):
|
|
|
160
191
|
async def delete(self, query: DeleteQuery) -> int:
|
|
161
192
|
"""
|
|
162
193
|
Delete records from the database
|
|
194
|
+
Note: Implementations should log delete operations with table name and affected row count
|
|
163
195
|
|
|
164
196
|
Args:
|
|
165
197
|
query (DeleteQuery): Query definition containing table name and conditions
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
+
import logging
|
|
2
3
|
from typing import Literal, Dict, Any, Optional, Tuple
|
|
3
4
|
from .database import Database
|
|
4
5
|
from .implementations import InMemoryDatabase, SQLiteDatabase, PersistentInMemoryDatabase, RedisDatabase
|
|
6
|
+
from ...logging_.utils import get_logger
|
|
7
|
+
logger = get_logger(__name__)
|
|
5
8
|
|
|
6
9
|
MAPPING = {
|
|
7
10
|
"sqlite": SQLiteDatabase,
|
|
@@ -34,14 +37,23 @@ class DatabaseFactory(ABC):
|
|
|
34
37
|
Returns:
|
|
35
38
|
Database: Database instance
|
|
36
39
|
"""
|
|
40
|
+
logger.debug("Requesting database instance: type=%s, args_count=%s, kwargs_count=%s", db_type, len(db_args) if db_args else 0, len(db_kwargs) if db_kwargs else 0)
|
|
41
|
+
|
|
37
42
|
if db_type not in cls._instances:
|
|
43
|
+
logger.info("Creating new database instance: %s", db_type)
|
|
38
44
|
if db_type not in MAPPING:
|
|
45
|
+
logger.error("Unsupported database type requested: %s", db_type)
|
|
39
46
|
raise ValueError(f"Unsupported database type: '{db_type}'")
|
|
40
47
|
|
|
41
48
|
# Convert None to empty tuple/dict for database initialization
|
|
42
49
|
args = db_args or ()
|
|
43
50
|
kwargs = db_kwargs or {}
|
|
51
|
+
logger.debug("Initializing %s database with args=%s, kwargs=%s", db_type, args, kwargs)
|
|
44
52
|
cls._instances[db_type] = MAPPING[db_type](*args, **kwargs)
|
|
53
|
+
logger.info("Database instance created successfully: %s", db_type)
|
|
54
|
+
else:
|
|
55
|
+
logger.debug("Returning existing database instance: %s", db_type)
|
|
56
|
+
|
|
45
57
|
return cls._instances[db_type]
|
|
46
58
|
|
|
47
59
|
@classmethod
|
{danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/db/database_initializer.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
from typing import Dict, Optional, Type, Any, Sequence
|
|
4
|
+
from ...logging_.utils import get_logger
|
|
4
5
|
|
|
5
6
|
try:
|
|
6
7
|
from sqlalchemy import inspect, Column
|
|
@@ -14,8 +15,7 @@ except ImportError:
|
|
|
14
15
|
|
|
15
16
|
from .database import Database
|
|
16
17
|
from .database_definitions import ColumnType, TableSchema, TableColumn as ColumnSchema, TableIndex as IndexSchema
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
19
|
|
|
20
20
|
TYPE_MAPPING = {
|
|
21
21
|
'INTEGER': ColumnType.INTEGER,
|
|
@@ -52,7 +52,7 @@ async def validate_schema(db: Database, table_name: str, expected_schema: TableS
|
|
|
52
52
|
# Get existing schema
|
|
53
53
|
existing_schemas = await db.get_schemas()
|
|
54
54
|
if table_name not in existing_schemas:
|
|
55
|
-
logger.warning(
|
|
55
|
+
logger.warning("Table '%s' does not exist", table_name)
|
|
56
56
|
return False
|
|
57
57
|
|
|
58
58
|
existing_schema = existing_schemas[table_name]
|
|
@@ -60,9 +60,12 @@ async def validate_schema(db: Database, table_name: str, expected_schema: TableS
|
|
|
60
60
|
# Compare columns
|
|
61
61
|
if len(existing_schema.columns) != len(expected_schema.columns):
|
|
62
62
|
logger.warning(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
"Column count mismatch in '%s': "
|
|
64
|
+
"expected %d, "
|
|
65
|
+
"got %d",
|
|
66
|
+
table_name,
|
|
67
|
+
len(expected_schema.columns),
|
|
68
|
+
len(existing_schema.columns)
|
|
66
69
|
)
|
|
67
70
|
return False
|
|
68
71
|
|
|
@@ -77,15 +80,18 @@ async def validate_schema(db: Database, table_name: str, expected_schema: TableS
|
|
|
77
80
|
expected_col.unique != existing_col.unique or
|
|
78
81
|
expected_col.foreign_key != existing_col.foreign_key
|
|
79
82
|
):
|
|
80
|
-
logger.warning(
|
|
83
|
+
logger.warning("Column mismatch in '%s': expected %s, got %s", table_name, expected_col, existing_col)
|
|
81
84
|
return False
|
|
82
85
|
|
|
83
86
|
# Compare indexes
|
|
84
87
|
if len(existing_schema.indexes) != len(expected_schema.indexes):
|
|
85
88
|
logger.warning(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
"Index count mismatch in '%s': "
|
|
90
|
+
"expected %d, "
|
|
91
|
+
"got %d",
|
|
92
|
+
table_name,
|
|
93
|
+
len(expected_schema.indexes),
|
|
94
|
+
len(existing_schema.indexes)
|
|
89
95
|
)
|
|
90
96
|
return False
|
|
91
97
|
|
|
@@ -97,13 +103,13 @@ async def validate_schema(db: Database, table_name: str, expected_schema: TableS
|
|
|
97
103
|
expected_idx.columns != existing_idx.columns or
|
|
98
104
|
expected_idx.unique != existing_idx.unique
|
|
99
105
|
):
|
|
100
|
-
logger.warning(
|
|
106
|
+
logger.warning("Index mismatch in '%s': expected %s, got %s", table_name, expected_idx, existing_idx)
|
|
101
107
|
return False
|
|
102
108
|
|
|
103
109
|
return True
|
|
104
110
|
|
|
105
111
|
except Exception as e:
|
|
106
|
-
logger.error(
|
|
112
|
+
logger.error("Error validating schema for '%s': %s", table_name, str(e))
|
|
107
113
|
return False
|
|
108
114
|
|
|
109
115
|
|
|
@@ -233,10 +239,10 @@ class DatabaseInitializer(ABC):
|
|
|
233
239
|
# Create or validate each table
|
|
234
240
|
for table_name, expected_schema in table_schemas.items():
|
|
235
241
|
if table_name not in existing_schemas:
|
|
236
|
-
logger.info(
|
|
242
|
+
logger.info("Creating table '%s'", table_name)
|
|
237
243
|
await db.create_table(expected_schema)
|
|
238
244
|
else:
|
|
239
|
-
logger.info(
|
|
245
|
+
logger.info("Validating table '%s'", table_name)
|
|
240
246
|
if not await validate_schema(db, table_name, expected_schema):
|
|
241
247
|
raise ValueError(
|
|
242
248
|
f"Schema validation failed for table '{table_name}'. "
|
|
@@ -246,7 +252,7 @@ class DatabaseInitializer(ABC):
|
|
|
246
252
|
logger.info("Database initialization completed successfully")
|
|
247
253
|
|
|
248
254
|
except Exception as e:
|
|
249
|
-
logger.error(
|
|
255
|
+
logger.error("Error initializing database: %s", str(e))
|
|
250
256
|
raise
|
|
251
257
|
|
|
252
258
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from typing import Dict, Any, List, Type, Union, Sequence
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from ....logging_.utils import get_logger
|
|
4
5
|
|
|
5
6
|
try:
|
|
6
7
|
from starlette import status
|
|
@@ -14,7 +15,6 @@ from ..database_definitions import Operator, WhereClause, Condition, SelectQuery
|
|
|
14
15
|
TableColumn
|
|
15
16
|
from ..database_exceptions import DBValidationError, DBQueryError, DBConnectionError, DBException
|
|
16
17
|
|
|
17
|
-
|
|
18
18
|
class InMemoryDatabase(Database):
|
|
19
19
|
"""In-memory database implementation using dictionaries"""
|
|
20
20
|
|
|
@@ -43,7 +43,7 @@ class InMemoryDatabase(Database):
|
|
|
43
43
|
# table_name -> {column_name -> last_used_id}
|
|
44
44
|
self.auto_increment_counters: Dict[str, Dict[str, int]] = {}
|
|
45
45
|
self._connected = False
|
|
46
|
-
self.logger =
|
|
46
|
+
self.logger = get_logger(__name__)
|
|
47
47
|
|
|
48
48
|
async def connect(self) -> None:
|
|
49
49
|
"""Connect to the database (no-op for in-memory)"""
|
|
@@ -75,7 +75,7 @@ class InMemoryDatabase(Database):
|
|
|
75
75
|
if column.type == ColumnType.AUTOINCREMENT:
|
|
76
76
|
self.auto_increment_counters[schema.name][column.name] = 0
|
|
77
77
|
|
|
78
|
-
self.logger.info(
|
|
78
|
+
self.logger.info("Created table '%s'", schema.name)
|
|
79
79
|
|
|
80
80
|
def _get_next_auto_increment_id(self, table: str, column: str) -> int:
|
|
81
81
|
"""Get the next available ID for an auto-increment column"""
|
|
@@ -161,7 +161,7 @@ class InMemoryDatabase(Database):
|
|
|
161
161
|
# Add row
|
|
162
162
|
self.tables[table][row_data['id']] = row_data
|
|
163
163
|
self.logger.info(
|
|
164
|
-
|
|
164
|
+
"Inserted row into '%s' with ID '%s'", table, row_data['id'])
|
|
165
165
|
return row_data['id']
|
|
166
166
|
|
|
167
167
|
async def get(self, query: SelectQuery) -> List[Dict[str, Any]]:
|
|
@@ -232,7 +232,7 @@ class InMemoryDatabase(Database):
|
|
|
232
232
|
row.update(query.data)
|
|
233
233
|
updated_count += 1
|
|
234
234
|
|
|
235
|
-
self.logger.info(
|
|
235
|
+
self.logger.info("Updated '%s' rows in '%s'", updated_count, query.table)
|
|
236
236
|
return updated_count
|
|
237
237
|
|
|
238
238
|
async def delete(self, query: DeleteQuery) -> int:
|
|
@@ -254,7 +254,7 @@ class InMemoryDatabase(Database):
|
|
|
254
254
|
del self.tables[query.table][row_id]
|
|
255
255
|
|
|
256
256
|
self.logger.info(
|
|
257
|
-
|
|
257
|
+
"Deleted %d rows from '%s'", len(rows_to_delete), query.table)
|
|
258
258
|
return len(rows_to_delete)
|
|
259
259
|
|
|
260
260
|
def _validate_column_type(self, column: TableColumn, value: Any) -> bool:
|
|
@@ -90,7 +90,7 @@ class PersistentInMemoryDatabase(InMemoryDatabase):
|
|
|
90
90
|
json.dump(state, f, indent=2, cls=DateTimeEncoder)
|
|
91
91
|
self.logger.info("Database state saved successfully")
|
|
92
92
|
except Exception as e:
|
|
93
|
-
self.logger.error(
|
|
93
|
+
self.logger.error("Error saving database state: %s", e)
|
|
94
94
|
raise DBException(f"Failed to save database state: {str(e)}")
|
|
95
95
|
|
|
96
96
|
def _load_state(self) -> None:
|
|
@@ -127,7 +127,7 @@ class PersistentInMemoryDatabase(InMemoryDatabase):
|
|
|
127
127
|
|
|
128
128
|
self.logger.info("Database state loaded successfully")
|
|
129
129
|
except Exception as e:
|
|
130
|
-
self.logger.error(
|
|
130
|
+
self.logger.error("Error loading database state: %s", e)
|
|
131
131
|
raise DBException(f"Failed to load database state: {str(e)}")
|
|
132
132
|
|
|
133
133
|
def _maybe_save_state(self) -> None:
|
|
@@ -2,6 +2,7 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
from typing import List, Dict, Any, Optional, Type, Union, Sequence
|
|
4
4
|
from datetime import datetime
|
|
5
|
+
from ....logging_.utils import get_logger
|
|
5
6
|
|
|
6
7
|
try:
|
|
7
8
|
import redis.asyncio as redis
|
|
@@ -17,7 +18,6 @@ from ..database_definitions import (
|
|
|
17
18
|
)
|
|
18
19
|
from ..database_exceptions import DBException, DBValidationError, DBQueryError, DBConnectionError
|
|
19
20
|
|
|
20
|
-
|
|
21
21
|
class RedisDatabase(Database):
|
|
22
22
|
"""Redis implementation of the Database abstract class"""
|
|
23
23
|
|
|
@@ -54,7 +54,7 @@ class RedisDatabase(Database):
|
|
|
54
54
|
self.decode_responses = decode_responses
|
|
55
55
|
self._db: redis.Redis = None # type:ignore
|
|
56
56
|
self._connected = False
|
|
57
|
-
self.logger =
|
|
57
|
+
self.logger = get_logger(__name__)
|
|
58
58
|
|
|
59
59
|
# Redis key prefixes
|
|
60
60
|
self.SCHEMA_PREFIX = "schema:"
|
|
@@ -77,10 +77,9 @@ class RedisDatabase(Database):
|
|
|
77
77
|
# Test connection
|
|
78
78
|
await self._db.ping()
|
|
79
79
|
self._connected = True
|
|
80
|
-
self.logger.info(
|
|
81
|
-
f"Connected to Redis database at {self.host}:{self.port}")
|
|
80
|
+
self.logger.info("Connected to Redis database at %s:%s", self.host, self.port)
|
|
82
81
|
except Exception as e:
|
|
83
|
-
self.logger.error(
|
|
82
|
+
self.logger.error("Error connecting to Redis database: %s", e)
|
|
84
83
|
raise
|
|
85
84
|
|
|
86
85
|
async def disconnect(self) -> None:
|
|
@@ -130,7 +129,7 @@ class RedisDatabase(Database):
|
|
|
130
129
|
counter_key = f"{self.COUNTER_PREFIX}{schema.name}:{column.name}"
|
|
131
130
|
await self._db.set(counter_key, 0)
|
|
132
131
|
|
|
133
|
-
self.logger.info(
|
|
132
|
+
self.logger.info("Created table '%s'", schema.name)
|
|
134
133
|
|
|
135
134
|
async def _get_next_auto_increment_id(self, table: str, column: str) -> int:
|
|
136
135
|
"""Get the next available ID for an auto-increment column"""
|
|
@@ -215,7 +214,7 @@ class RedisDatabase(Database):
|
|
|
215
214
|
|
|
216
215
|
await self._db.hset(table_key, row_key, json.dumps(hash_data)) # type: ignore
|
|
217
216
|
|
|
218
|
-
self.logger.info(
|
|
217
|
+
self.logger.info("Inserted row %s into table '%s'", row_id, table)
|
|
219
218
|
return row_id
|
|
220
219
|
|
|
221
220
|
def _evaluate_condition(self, row: Dict[str, Any], condition: Condition) -> bool:
|
|
@@ -367,7 +366,7 @@ class RedisDatabase(Database):
|
|
|
367
366
|
await self._db.hset(table_key, row_id, json.dumps(row_data)) # type: ignore
|
|
368
367
|
updated_count += 1
|
|
369
368
|
|
|
370
|
-
self.logger.info(
|
|
369
|
+
self.logger.info("Updated %s rows in '%s'", updated_count, query.table)
|
|
371
370
|
return updated_count
|
|
372
371
|
|
|
373
372
|
async def delete(self, query: DeleteQuery) -> int:
|
|
@@ -395,7 +394,7 @@ class RedisDatabase(Database):
|
|
|
395
394
|
for row_id in rows_to_delete:
|
|
396
395
|
await self._db.hdel(table_key, row_id) # type: ignore
|
|
397
396
|
|
|
398
|
-
self.logger.info(
|
|
397
|
+
self.logger.info("Deleted %s rows from '%s'", len(rows_to_delete), query.table)
|
|
399
398
|
return len(rows_to_delete)
|
|
400
399
|
|
|
401
400
|
|
|
@@ -44,7 +44,7 @@ class SQLiteDatabase(Database):
|
|
|
44
44
|
"""SQLite implementation of the Database abstract class using SQLAlchemy"""
|
|
45
45
|
|
|
46
46
|
def is_connected(self) -> bool:
|
|
47
|
-
|
|
47
|
+
return self._connected
|
|
48
48
|
|
|
49
49
|
@classmethod
|
|
50
50
|
def _default_class_exception_conversion(cls, e: Exception) -> Exception:
|
|
@@ -95,15 +95,12 @@ class SQLiteDatabase(Database):
|
|
|
95
95
|
self.session_local = sessionmaker(autocommit=False, autoflush=False, bind=self.engine)
|
|
96
96
|
self.metadata.reflect(bind=self.engine)
|
|
97
97
|
self._connected = True
|
|
98
|
-
logging.info(
|
|
98
|
+
logging.info("Connected to SQLite database at '%s'", self.url)
|
|
99
99
|
except Exception as e:
|
|
100
100
|
logging.error(
|
|
101
|
-
|
|
101
|
+
"Error connecting to SQLite database at '%s': %s", self.url, e)
|
|
102
102
|
raise
|
|
103
103
|
|
|
104
|
-
def is_connected(self) -> bool:
|
|
105
|
-
return self._connected
|
|
106
|
-
|
|
107
104
|
async def disconnect(self) -> None:
|
|
108
105
|
"""Close the SQLite database connection"""
|
|
109
106
|
if self.engine:
|
|
@@ -179,7 +176,7 @@ class SQLiteDatabase(Database):
|
|
|
179
176
|
column_type = self._get_column_type(col.type)
|
|
180
177
|
except ValueError as e:
|
|
181
178
|
logging.warning(
|
|
182
|
-
|
|
179
|
+
"Could not map type for column %s in table %s: %s", col['name'], table_name, e)
|
|
183
180
|
continue
|
|
184
181
|
|
|
185
182
|
# Handle default values
|
|
@@ -284,9 +281,9 @@ class SQLiteDatabase(Database):
|
|
|
284
281
|
# Create table with all columns
|
|
285
282
|
table = Table(schema.name, self.metadata, *columns)
|
|
286
283
|
table.create(self.engine) # type: ignore
|
|
287
|
-
logging.info(
|
|
284
|
+
logging.info("Created table: '%s'", schema.name)
|
|
288
285
|
except Exception as e:
|
|
289
|
-
logging.error(
|
|
286
|
+
logging.error("Error creating table '%s': %s", schema.name, e)
|
|
290
287
|
raise
|
|
291
288
|
|
|
292
289
|
def _get_session(self) -> Session:
|
|
@@ -312,7 +309,7 @@ class SQLiteDatabase(Database):
|
|
|
312
309
|
session.commit()
|
|
313
310
|
return result.inserted_primary_key[0]
|
|
314
311
|
except Exception as e:
|
|
315
|
-
logging.error(
|
|
312
|
+
logging.error("Error inserting into '%s': %s", table, e)
|
|
316
313
|
raise
|
|
317
314
|
|
|
318
315
|
async def get(self, query: SelectQuery) -> List[Dict[str, Any]]:
|
|
@@ -417,7 +414,7 @@ class SQLiteDatabase(Database):
|
|
|
417
414
|
# Convert result rows to dictionaries
|
|
418
415
|
return [dict(zip(result.keys(), row)) for row in result]
|
|
419
416
|
except Exception as e:
|
|
420
|
-
logging.error(
|
|
417
|
+
logging.error("Error selecting from '%s': %s", query.table, e)
|
|
421
418
|
raise
|
|
422
419
|
|
|
423
420
|
async def update(self, query: UpdateQuery) -> int:
|
|
@@ -451,7 +448,7 @@ class SQLiteDatabase(Database):
|
|
|
451
448
|
session.commit()
|
|
452
449
|
return result.rowcount
|
|
453
450
|
except Exception as e:
|
|
454
|
-
logging.error(
|
|
451
|
+
logging.error("Error updating '%s': %s", query.table, e)
|
|
455
452
|
raise
|
|
456
453
|
|
|
457
454
|
async def delete(self, query: DeleteQuery) -> int:
|
|
@@ -485,7 +482,7 @@ class SQLiteDatabase(Database):
|
|
|
485
482
|
session.commit()
|
|
486
483
|
return result.rowcount
|
|
487
484
|
except Exception as e:
|
|
488
|
-
logging.error(
|
|
485
|
+
logging.error("Error deleting from '%s': %s", query.table, e)
|
|
489
486
|
raise
|
|
490
487
|
|
|
491
488
|
|
{danielutils-1.0.52 → danielutils-1.1.1}/danielutils/abstractions/multiprogramming/worker.py
RENAMED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
from threading import Thread
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
3
|
from typing import Optional, Any, Tuple as Tuple
|
|
4
|
-
|
|
4
|
+
import logging
|
|
5
5
|
import danielutils # this is explicitly this way to prevent circular import
|
|
6
6
|
from ...reflection import get_python_version
|
|
7
|
+
from ...logging_.utils import get_logger
|
|
7
8
|
|
|
8
9
|
if get_python_version() >= (3, 9):
|
|
9
10
|
from builtins import tuple as Tuple # type:ignore
|
|
10
11
|
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
class Worker(ABC):
|
|
13
16
|
"""A Worker Interface
|
|
@@ -15,9 +18,11 @@ class Worker(ABC):
|
|
|
15
18
|
|
|
16
19
|
def __init__(self, id: int,
|
|
17
20
|
pool: "danielutils.abstractions.multiprogramming.worker_pool.WorkerPool") -> None: # pylint: disable=redefined-builtin #noqa
|
|
21
|
+
logger.debug("Initializing Worker with id=%s", id)
|
|
18
22
|
self.id = id
|
|
19
23
|
self.pool = pool
|
|
20
24
|
self.thread: Thread = Thread(target=self._loop)
|
|
25
|
+
logger.debug("Worker %s initialized successfully", id)
|
|
21
26
|
|
|
22
27
|
@abstractmethod
|
|
23
28
|
def _work(self, obj: Any) -> None:
|
|
@@ -27,38 +32,55 @@ class Worker(ABC):
|
|
|
27
32
|
def _loop(self) -> None:
|
|
28
33
|
"""main loop of the worker
|
|
29
34
|
"""
|
|
35
|
+
logger.debug("Worker %s main loop started", self.id)
|
|
30
36
|
while True:
|
|
31
37
|
try:
|
|
32
38
|
obj = self.acquire()
|
|
33
39
|
if obj is not None:
|
|
40
|
+
logger.debug("Worker %s acquired job: %s", self.id, type(obj[0]).__name__)
|
|
34
41
|
self.work(obj[0])
|
|
35
42
|
else:
|
|
43
|
+
logger.debug("Worker %s received None job, exiting loop", self.id)
|
|
36
44
|
break
|
|
37
45
|
except Exception as e: # pylint: disable=broad-exception-caught
|
|
38
|
-
error(
|
|
46
|
+
logger.error("Worker %s thread encountered an error: %s: %s", self.id, type(e).__name__, e)
|
|
47
|
+
break
|
|
48
|
+
logger.debug("Worker %s main loop ended", self.id)
|
|
39
49
|
|
|
40
50
|
def run(self) -> None:
|
|
41
51
|
"""will start self._run() as a new thread with the argument given in __init__
|
|
42
52
|
"""
|
|
53
|
+
logger.debug("Starting worker %s thread", self.id)
|
|
43
54
|
self.thread.start()
|
|
55
|
+
logger.debug("Worker %s thread started successfully", self.id)
|
|
44
56
|
|
|
45
57
|
def is_alive(self) -> bool:
|
|
46
58
|
"""returns whether the worker is alive or not
|
|
47
59
|
"""
|
|
48
|
-
|
|
60
|
+
is_alive = self.thread.is_alive()
|
|
61
|
+
logger.debug("Worker %s is_alive: %s", self.id, is_alive)
|
|
62
|
+
return is_alive
|
|
49
63
|
|
|
50
64
|
def work(self, obj: Any) -> None:
|
|
51
65
|
"""performed the actual work that needs to happen
|
|
52
66
|
execution of a single job
|
|
53
67
|
"""
|
|
54
|
-
self.
|
|
55
|
-
|
|
68
|
+
logger.debug("Worker %s starting work on job: %s", self.id, type(obj).__name__)
|
|
69
|
+
try:
|
|
70
|
+
self._work(obj)
|
|
71
|
+
logger.debug("Worker %s completed work on job: %s", self.id, type(obj).__name__)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error("Worker %s failed to process job %s: %s: %s", self.id, type(obj).__name__, type(e).__name__, e)
|
|
74
|
+
raise
|
|
75
|
+
finally:
|
|
76
|
+
self._notify()
|
|
56
77
|
|
|
57
78
|
def _notify(self) -> None:
|
|
58
79
|
"""utility method to be called on the end of each iteration of work
|
|
59
80
|
to signal actions if needed
|
|
60
81
|
will call 'notification_function'
|
|
61
82
|
"""
|
|
83
|
+
logger.debug("Worker %s notifying pool of job completion", self.id)
|
|
62
84
|
# TODO
|
|
63
85
|
self.pool._notify_subscribers() # type:ignore # pylint: disable=protected-access
|
|
64
86
|
|
|
@@ -68,7 +90,13 @@ class Worker(ABC):
|
|
|
68
90
|
Returns:
|
|
69
91
|
Optional[tuple[Any]]: tuple of job object or None
|
|
70
92
|
"""
|
|
71
|
-
|
|
93
|
+
logger.debug("Worker %s attempting to acquire job from pool", self.id)
|
|
94
|
+
job = self.pool._acquire() # pylint: disable=protected-access
|
|
95
|
+
if job is not None:
|
|
96
|
+
logger.debug("Worker %s acquired job: %s", self.id, type(job[0]).__name__)
|
|
97
|
+
else:
|
|
98
|
+
logger.debug("Worker %s no jobs available in pool", self.id)
|
|
99
|
+
return job
|
|
72
100
|
|
|
73
101
|
|
|
74
102
|
__all__ = [
|