danielutils 1.1.28__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- danielutils/__init__.py +50 -0
- danielutils/abstractions/__init__.py +3 -0
- danielutils/abstractions/db/__init__.py +10 -0
- danielutils/abstractions/db/database.py +206 -0
- danielutils/abstractions/db/database_definitions.py +219 -0
- danielutils/abstractions/db/database_exceptions.py +34 -0
- danielutils/abstractions/db/database_factory.py +70 -0
- danielutils/abstractions/db/database_initializer.py +261 -0
- danielutils/abstractions/db/database_models.py +213 -0
- danielutils/abstractions/db/dependencies.py +6 -0
- danielutils/abstractions/db/implementations/__init__.py +4 -0
- danielutils/abstractions/db/implementations/in_memory_database.py +365 -0
- danielutils/abstractions/db/implementations/persistent_in_memory_database.py +174 -0
- danielutils/abstractions/db/implementations/redis_database.py +403 -0
- danielutils/abstractions/db/implementations/sqlite_database.py +491 -0
- danielutils/abstractions/multiprogramming/__init__.py +3 -0
- danielutils/abstractions/multiprogramming/multi_id.py +26 -0
- danielutils/abstractions/multiprogramming/worker.py +104 -0
- danielutils/abstractions/multiprogramming/worker_pool.py +98 -0
- danielutils/abstractions/repl.py +125 -0
- danielutils/aliases.py +174 -0
- danielutils/async_/__init__.py +7 -0
- danielutils/async_/async_cmd.py +28 -0
- danielutils/async_/async_command.py +879 -0
- danielutils/async_/async_layered_command.py +125 -0
- danielutils/async_/async_retry_executor.py +86 -0
- danielutils/async_/async_worker_pool.py +110 -0
- danielutils/async_/time_strategy.py +73 -0
- danielutils/async_/utils.py +57 -0
- danielutils/better_builtins/__init__.py +3 -0
- danielutils/better_builtins/counter.py +48 -0
- danielutils/better_builtins/frange.py +266 -0
- danielutils/better_builtins/typed_builtins/__init__.py +4 -0
- danielutils/better_builtins/typed_builtins/factory.py +126 -0
- danielutils/better_builtins/typed_builtins/tdict.py +36 -0
- danielutils/better_builtins/typed_builtins/tlist.py +223 -0
- danielutils/better_builtins/typed_builtins/tset.py +67 -0
- danielutils/better_builtins/typed_builtins/ttuple.py +15 -0
- danielutils/colors.py +203 -0
- danielutils/context_managers/__init__.py +5 -0
- danielutils/context_managers/attr_context.py +40 -0
- danielutils/context_managers/multi_context.py +34 -0
- danielutils/context_managers/optional_context.py +33 -0
- danielutils/context_managers/state_context.py +25 -0
- danielutils/context_managers/temporary_file.py +108 -0
- danielutils/convenience.py +12 -0
- danielutils/conversions/__init__.py +2 -0
- danielutils/conversions/main_conversions.py +131 -0
- danielutils/conversions/specialized_conversions/__init__.py +2 -0
- danielutils/conversions/specialized_conversions/to_hex.py +25 -0
- danielutils/conversions/specialized_conversions/to_int.py +19 -0
- danielutils/custom_types.py +18 -0
- danielutils/data_structures/__init__.py +8 -0
- danielutils/data_structures/algorithms.py +52 -0
- danielutils/data_structures/comparer.py +47 -0
- danielutils/data_structures/default_dict.py +23 -0
- danielutils/data_structures/functions.py +35 -0
- danielutils/data_structures/graph/__init__.py +4 -0
- danielutils/data_structures/graph/binary_node.py +71 -0
- danielutils/data_structures/graph/graph.py +208 -0
- danielutils/data_structures/graph/multinode.py +101 -0
- danielutils/data_structures/graph/node.py +60 -0
- danielutils/data_structures/heap/__init__.py +3 -0
- danielutils/data_structures/heap/heap.py +119 -0
- danielutils/data_structures/heap/max_heap.py +18 -0
- danielutils/data_structures/heap/min_heap.py +18 -0
- danielutils/data_structures/queue/__init__.py +3 -0
- danielutils/data_structures/queue/atomic_queue.py +15 -0
- danielutils/data_structures/queue/priority_queue.py +110 -0
- danielutils/data_structures/queue/queue.py +92 -0
- danielutils/data_structures/stack.py +102 -0
- danielutils/data_structures/trees/__init__.py +2 -0
- danielutils/data_structures/trees/binary_syntax_tree.py +84 -0
- danielutils/data_structures/trees/binary_tree.py +63 -0
- danielutils/date.py +43 -0
- danielutils/date_time.py +23 -0
- danielutils/decorators/__init__.py +18 -0
- danielutils/decorators/atomic.py +45 -0
- danielutils/decorators/attach.py +61 -0
- danielutils/decorators/chain_decorators.py +39 -0
- danielutils/decorators/decorate_conditionally.py +32 -0
- danielutils/decorators/delay_call.py +47 -0
- danielutils/decorators/deprecate.py +46 -0
- danielutils/decorators/final.py +39 -0
- danielutils/decorators/limit_recursion.py +63 -0
- danielutils/decorators/memo.py +68 -0
- danielutils/decorators/normalize_decorator.py +55 -0
- danielutils/decorators/overload.py +204 -0
- danielutils/decorators/partially_implemented.py +32 -0
- danielutils/decorators/processify.py +74 -0
- danielutils/decorators/property.py +42 -0
- danielutils/decorators/singleton.py +59 -0
- danielutils/decorators/threadify.py +40 -0
- danielutils/decorators/timeout.py +82 -0
- danielutils/decorators/total_ordering.py +82 -0
- danielutils/decorators/validate.py +227 -0
- danielutils/exceptions.py +90 -0
- danielutils/functions/__init__.py +13 -0
- danielutils/functions/areoneof.py +47 -0
- danielutils/functions/check_foreach.py +39 -0
- danielutils/functions/factorial.py +24 -0
- danielutils/functions/flatten.py +33 -0
- danielutils/functions/foreach.py +20 -0
- danielutils/functions/isoftype.py +475 -0
- danielutils/functions/isoneof.py +71 -0
- danielutils/functions/multiloop.py +51 -0
- danielutils/functions/parallel_for.py +47 -0
- danielutils/functions/partition.py +45 -0
- danielutils/functions/powerset.py +31 -0
- danielutils/functions/subseteq.py +25 -0
- danielutils/functions/types_subseteq.py +51 -0
- danielutils/generators/__init__.py +3 -0
- danielutils/generators/conditional_generator.py +59 -0
- danielutils/generators/generator_from_stream.py +31 -0
- danielutils/generators/join_generators.py +109 -0
- danielutils/internet.py +92 -0
- danielutils/io_.py +451 -0
- danielutils/java/__init__.py +18 -0
- danielutils/java/interfaces/__init__.py +1 -0
- danielutils/java/interfaces/comparable.py +31 -0
- danielutils/java/java_interface.py +59 -0
- danielutils/logging_/__init__.py +2 -0
- danielutils/logging_/_impl/__init__.py +4 -0
- danielutils/logging_/_impl/builtin_impls/__init__.py +2 -0
- danielutils/logging_/_impl/builtin_impls/file_logger.py +35 -0
- danielutils/logging_/_impl/builtin_impls/print_logger.py +21 -0
- danielutils/logging_/_impl/log_level.py +13 -0
- danielutils/logging_/_impl/logger.py +109 -0
- danielutils/logging_/_impl/logger_strategy_impl_base.py +37 -0
- danielutils/logging_/utils.py +199 -0
- danielutils/lombok/__init__.py +1 -0
- danielutils/lombok/builder.py +68 -0
- danielutils/math_/__init__.py +2 -0
- danielutils/math_/constants.py +103 -0
- danielutils/math_/functions.py +34 -0
- danielutils/math_/math_print.py +52 -0
- danielutils/math_/math_symbols.py +125 -0
- danielutils/metaclasses/__init__.py +5 -0
- danielutils/metaclasses/atomic_class_meta.py +36 -0
- danielutils/metaclasses/implicit_data_deleter_meta.py +87 -0
- danielutils/metaclasses/instance_cache_meta.py +66 -0
- danielutils/metaclasses/interface.py +328 -0
- danielutils/metaclasses/overload_meta.py +48 -0
- danielutils/mock_/__init__.py +1 -0
- danielutils/mock_/mock_module.py +27 -0
- danielutils/path.py +55 -0
- danielutils/print_.py +123 -0
- danielutils/progress_bar/__init__.py +3 -0
- danielutils/progress_bar/ascii_progress_bar.py +161 -0
- danielutils/progress_bar/progress_bar.py +75 -0
- danielutils/progress_bar/progress_bar_pool.py +72 -0
- danielutils/protocols/__init__.py +3 -0
- danielutils/protocols/dictable.py +38 -0
- danielutils/protocols/evaluable.py +26 -0
- danielutils/protocols/serializable.py +51 -0
- danielutils/py.typed +0 -0
- danielutils/random_.py +47 -0
- danielutils/reflection/__init__.py +6 -0
- danielutils/reflection/declarations.py +288 -0
- danielutils/reflection/file/__init__.py +1 -0
- danielutils/reflection/file/file_reflection.py +85 -0
- danielutils/reflection/function/__init__.py +1 -0
- danielutils/reflection/function/function_reflections.py +152 -0
- danielutils/reflection/info_classes/__init__.py +6 -0
- danielutils/reflection/info_classes/argument_info.py +278 -0
- danielutils/reflection/info_classes/class_info.py +204 -0
- danielutils/reflection/info_classes/decorator_info.py +54 -0
- danielutils/reflection/info_classes/file_info.py +1180 -0
- danielutils/reflection/info_classes/folder_info.py +592 -0
- danielutils/reflection/info_classes/function_info.py +551 -0
- danielutils/reflection/info_classes/import_info.py +207 -0
- danielutils/reflection/interpreter/__init__.py +9 -0
- danielutils/reflection/interpreter/callstack.py +57 -0
- danielutils/reflection/interpreter/get_traceback.py +27 -0
- danielutils/reflection/interpreter/interpreter.py +41 -0
- danielutils/reflection/interpreter/is_debugging.py +13 -0
- danielutils/reflection/interpreter/os_.py +33 -0
- danielutils/reflection/interpreter/packages.py +33 -0
- danielutils/reflection/interpreter/python_version.py +33 -0
- danielutils/reflection/interpreter/signals.py +18 -0
- danielutils/reflection/interpreter/tracer.py +175 -0
- danielutils/reflection/module/__init__.py +3 -0
- danielutils/reflection/module/lazy_module.py +104 -0
- danielutils/reflection/module/module_reflections.py +34 -0
- danielutils/reflection/module/package_reflection.py +161 -0
- danielutils/retry_executor/__init__.py +3 -0
- danielutils/retry_executor/backoff_strategies/__init__.py +6 -0
- danielutils/retry_executor/backoff_strategies/constant_backoff.py +25 -0
- danielutils/retry_executor/backoff_strategies/exponential_backoff.py +26 -0
- danielutils/retry_executor/backoff_strategies/functional_backoff.py +29 -0
- danielutils/retry_executor/backoff_strategies/linear_backoff.py +23 -0
- danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +23 -0
- danielutils/retry_executor/backoff_strategies/no_backoff.py +17 -0
- danielutils/retry_executor/backoff_strategy.py +28 -0
- danielutils/retry_executor/retry_executor.py +55 -0
- danielutils/snippets/__init__.py +1 -0
- danielutils/snippets/try_get.py +28 -0
- danielutils/system/__init__.py +3 -0
- danielutils/system/independent.py +197 -0
- danielutils/system/layered_command.py +130 -0
- danielutils/system/windows/__init__.py +2 -0
- danielutils/system/windows/utils/__init__.py +1 -0
- danielutils/system/windows/utils/filetime.py +19 -0
- danielutils/system/windows/win32_ctime.py +183 -0
- danielutils/system/windows/windows.py +78 -0
- danielutils/testing/__init__.py +1 -0
- danielutils/testing/unittest_/__init__.py +2 -0
- danielutils/testing/unittest_/always_teardown_testcase.py +75 -0
- danielutils/testing/unittest_/auto_cwd_testcase.py +114 -0
- danielutils/text.py +169 -0
- danielutils/time.py +64 -0
- danielutils/tools/__init__.py +1 -0
- danielutils/tools/unittest_test_runner/__init__.py +9 -0
- danielutils/tools/unittest_test_runner/cli.py +70 -0
- danielutils/tools/unittest_test_runner/core/__init__.py +17 -0
- danielutils/tools/unittest_test_runner/core/discovery.py +322 -0
- danielutils/tools/unittest_test_runner/core/execution.py +244 -0
- danielutils/tools/unittest_test_runner/core/parser.py +163 -0
- danielutils/tools/unittest_test_runner/core/runner.py +561 -0
- danielutils/tools/unittest_test_runner/models.py +82 -0
- danielutils/university/__init__.py +7 -0
- danielutils/university/computability_and_complexity/__init__.py +2 -0
- danielutils/university/computability_and_complexity/discreate_finite_automaton.py +89 -0
- danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
- danielutils/university/computability_and_complexity/languages/language.py +17 -0
- danielutils/university/computability_and_complexity/languages/sat.py +71 -0
- danielutils/university/computability_and_complexity/turing_machine.py +47 -0
- danielutils/university/databases/__init__.py +1 -0
- danielutils/university/databases/all.py +756 -0
- danielutils/university/image_proccesing/__init__.py +1 -0
- danielutils/university/image_proccesing/encoding/__init__.py +3 -0
- danielutils/university/image_proccesing/encoding/encoding.py +35 -0
- danielutils/university/image_proccesing/encoding/lossless/__init__.py +4 -0
- danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
- danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +10 -0
- danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
- danielutils/university/image_proccesing/encoding/lossless/run_length.py +22 -0
- danielutils/university/image_proccesing/encoding/lossy/__init__.py +1 -0
- danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +10 -0
- danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
- danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
- danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
- danielutils/university/image_proccesing/tansformations/hough.py +0 -0
- danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
- danielutils/university/image_proccesing/tansformations/transformation.py +11 -0
- danielutils/university/linear_algebra/__init__.py +1 -0
- danielutils/university/linear_algebra/matrix.py +404 -0
- danielutils/university/machine_learning/__init__.py +0 -0
- danielutils/university/machine_learning/activation_functions/__init__.py +2 -0
- danielutils/university/machine_learning/activation_functions/activation_function.py +11 -0
- danielutils/university/machine_learning/activation_functions/relu.py +11 -0
- danielutils/university/machine_learning/neuron.py +15 -0
- danielutils/university/oop/__init__.py +1 -0
- danielutils/university/oop/observer.py +31 -0
- danielutils/university/oop/strategy.py +9 -0
- danielutils/university/probability/__init__.py +7 -0
- danielutils/university/probability/conditional_variable/__init__.py +3 -0
- danielutils/university/probability/conditional_variable/conditional_variable.py +138 -0
- danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
- danielutils/university/probability/conditional_variable/discrete/__init__.py +8 -0
- danielutils/university/probability/conditional_variable/discrete/bernoulli.py +38 -0
- danielutils/university/probability/conditional_variable/discrete/bernoulli_sum.py +31 -0
- danielutils/university/probability/conditional_variable/discrete/binomial.py +40 -0
- danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +36 -0
- danielutils/university/probability/conditional_variable/discrete/discrete.py +42 -0
- danielutils/university/probability/conditional_variable/discrete/geometric.py +43 -0
- danielutils/university/probability/conditional_variable/discrete/poisson.py +32 -0
- danielutils/university/probability/conditional_variable/discrete/uniform.py +33 -0
- danielutils/university/probability/distributions.py +35 -0
- danielutils/university/probability/expressions/__init__.py +2 -0
- danielutils/university/probability/expressions/accumulation_expression.py +291 -0
- danielutils/university/probability/expressions/probability_expression.py +110 -0
- danielutils/university/probability/funcs/__init__.py +4 -0
- danielutils/university/probability/funcs/covariance.py +12 -0
- danielutils/university/probability/funcs/expected_value.py +41 -0
- danielutils/university/probability/funcs/probability_function.py +14 -0
- danielutils/university/probability/funcs/variance.py +17 -0
- danielutils/university/probability/operator.py +79 -0
- danielutils/university/probability/protocols.py +32 -0
- danielutils/university/probability/supp.py +101 -0
- danielutils/university/probability/transformation.py +44 -0
- danielutils/versioned_imports.py +31 -0
- danielutils-1.1.28.dist-info/METADATA +390 -0
- danielutils-1.1.28.dist-info/RECORD +287 -0
- danielutils-1.1.28.dist-info/WHEEL +5 -0
- danielutils-1.1.28.dist-info/licenses/LICENSE +21 -0
- danielutils-1.1.28.dist-info/top_level.txt +1 -0
danielutils/io_.py
ADDED
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import logging
|
|
3
|
+
import subprocess
|
|
4
|
+
from typing import IO, Iterator, Generator, Optional, cast, Union, List as List
|
|
5
|
+
# import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import os
|
|
8
|
+
from .decorators import validate
|
|
9
|
+
from .reflection import get_python_version
|
|
10
|
+
from .logging_.utils import get_logger
|
|
11
|
+
|
|
12
|
+
logger = get_logger(__name__)
|
|
13
|
+
|
|
14
|
+
if get_python_version() >= (3, 9):
|
|
15
|
+
from builtins import list as List
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@validate # type:ignore
|
|
19
|
+
def path_exists(path: str) -> bool:
|
|
20
|
+
"""checks whether a path exists
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
path (str): path to check
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
bool: result of check
|
|
27
|
+
"""
|
|
28
|
+
return os.path.exists(path)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@validate # type:ignore
|
|
32
|
+
def file_exists(path: str) -> bool:
|
|
33
|
+
"""checks whether a file exists at specified path
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
path (str): path to check
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
bool: will return true iff the path exists and it is a path to a file
|
|
40
|
+
"""
|
|
41
|
+
return path_exists(path) and is_file(path)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@validate # type:ignore
|
|
45
|
+
def directory_exists(path: str) -> bool:
|
|
46
|
+
"""checks whether a directory exists at specified path
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
path (str): path to check
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
bool: will return true iff the path exists and it is a path to a directory
|
|
53
|
+
"""
|
|
54
|
+
return path_exists(path) and is_directory(path)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@validate # type:ignore
|
|
58
|
+
def delete_file(path: str) -> None:
|
|
59
|
+
"""deletes a file if it exists
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
path (str): path of file
|
|
63
|
+
"""
|
|
64
|
+
if file_exists(path):
|
|
65
|
+
os.remove(path)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@validate # type:ignore
|
|
69
|
+
# type:ignore
|
|
70
|
+
def read_file(path: str, read_bytes: bool = False) -> Union[List[str], List[bytes]]:
|
|
71
|
+
"""read all lines from a file
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
path (str): the path to the file
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
list[str]: a list of all the lines in the file
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
if read_bytes:
|
|
81
|
+
with open(path, "rb") as f:
|
|
82
|
+
result = f.readlines()
|
|
83
|
+
else:
|
|
84
|
+
with open(path, "r", encoding="mbcs") as f:
|
|
85
|
+
result = f.readlines()
|
|
86
|
+
return result
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.error("Error reading file %s: %s", path, e)
|
|
89
|
+
if isinstance(e, UnicodeDecodeError):
|
|
90
|
+
logger.error("Unicode decode error, suggesting to use read_bytes=True")
|
|
91
|
+
raise UnicodeDecodeError(e.encoding, e.object, e.start, e.end,
|
|
92
|
+
"Can't read byte in file.\nTo use with bytes use: read_bytes = True ") from e
|
|
93
|
+
raise e
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@validate # type:ignore
|
|
97
|
+
def is_file(path: str) -> bool:
|
|
98
|
+
"""return whether a path represents a file
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
path (str): path to check
|
|
102
|
+
"""
|
|
103
|
+
return os.path.isfile(path)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@validate # type:ignore
|
|
107
|
+
def is_directory(path: str) -> bool:
|
|
108
|
+
"""return whether a path represents a directory
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
path (str): path to check
|
|
112
|
+
"""
|
|
113
|
+
return os.path.isdir(path)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@validate # type:ignore
|
|
117
|
+
def get_files(path: str) -> List[str]:
|
|
118
|
+
"""return a list of names of all files inside specified directory
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
path (str): directory
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
list[str]: all files
|
|
125
|
+
"""
|
|
126
|
+
files_and_directories = get_files_and_directories(path)
|
|
127
|
+
return list(
|
|
128
|
+
filter(lambda name: is_file(os.path.join(path, name)), files_and_directories))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@validate # type:ignore
|
|
132
|
+
def get_files_and_directories(path: str) -> List[str]:
|
|
133
|
+
"""get a list of all files and directories in specified path
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
path (str): path to check
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
list[str]: all files and directories
|
|
140
|
+
"""
|
|
141
|
+
return os.listdir(path)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@validate # type:ignore
|
|
145
|
+
def get_directories(path: str) -> List[str]:
|
|
146
|
+
"""get all directories in specified path
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
path (str): path to check
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
list[str]: all directories
|
|
153
|
+
"""
|
|
154
|
+
files_and_directories = get_files_and_directories(path)
|
|
155
|
+
return list(
|
|
156
|
+
filter(lambda name: is_directory(os.path.join(path, name)), files_and_directories))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@validate # type:ignore
|
|
160
|
+
def delete_directory(path: str) -> None:
|
|
161
|
+
"""delete a directory and all its contents
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
path (str): _description_
|
|
165
|
+
"""
|
|
166
|
+
if is_directory(path):
|
|
167
|
+
clear_directory(path)
|
|
168
|
+
os.rmdir(path)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@validate # type:ignore
|
|
172
|
+
def clear_directory(path: str) -> None:
|
|
173
|
+
"""clears the content of a directory
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
path (str): the path of the directory to clean
|
|
177
|
+
"""
|
|
178
|
+
for file in get_files(path):
|
|
179
|
+
delete_file(os.path.join(path, file))
|
|
180
|
+
for subdir in get_directories(path):
|
|
181
|
+
delete_directory(os.path.join(path, subdir))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@validate # type:ignore
|
|
185
|
+
def create_directory(path: str) -> None:
|
|
186
|
+
"""create a directory at the specified path if it doesn't already exists
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
path (str): the path to create a directory at
|
|
190
|
+
"""
|
|
191
|
+
if not directory_exists(path):
|
|
192
|
+
os.makedirs(path)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@validate # type:ignore
|
|
196
|
+
def create_file(path: str) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Will create a file at the specified path if it doesn't already exists
|
|
199
|
+
Args:
|
|
200
|
+
path (str): the path to create a file at
|
|
201
|
+
Returns:
|
|
202
|
+
None
|
|
203
|
+
"""
|
|
204
|
+
if not file_exists(path):
|
|
205
|
+
with open(path, "w", encoding='utf8') as f:
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@validate # type:ignore
|
|
210
|
+
def get_file_type_from_directory(path: str, file_type: str) -> Iterator[str]:
|
|
211
|
+
"""returns all file with specific type from a directory
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
path (str): path of directory
|
|
215
|
+
file_type (str): the desired file type. eg: ".png"
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
list[str]: result
|
|
219
|
+
"""
|
|
220
|
+
return filter(
|
|
221
|
+
lambda name: Path(os.path.join(path, name)).suffix == file_type,
|
|
222
|
+
get_files(path)
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@validate # type:ignore
|
|
227
|
+
def get_file_type_from_directory_recursively(path: str, file_type: str) -> Generator[str, None, None]:
|
|
228
|
+
"""_summary_
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
path (str): _description_
|
|
232
|
+
file_type (str): _description_
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
_type_: _description_
|
|
236
|
+
"""
|
|
237
|
+
yield from filter(
|
|
238
|
+
lambda name: Path(os.path.join(path, name)).suffix == file_type,
|
|
239
|
+
get_files(path)
|
|
240
|
+
)
|
|
241
|
+
for subdir in get_directories(path):
|
|
242
|
+
for v in get_file_type_from_directory_recursively(os.path.join(path, subdir), file_type):
|
|
243
|
+
yield os.path.join(subdir, v)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@validate # type:ignore
|
|
247
|
+
def rename_file(path: str, new_name: str) -> None:
|
|
248
|
+
"""renames a file
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
path (str): file to rename
|
|
252
|
+
new_name (str): the desired new name
|
|
253
|
+
"""
|
|
254
|
+
new_path = "./" + \
|
|
255
|
+
"/".join(Path(path).parts[:-1]) + "/" + new_name + Path(path).suffix
|
|
256
|
+
move_file(path, new_path)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@validate # type:ignore
|
|
260
|
+
def move_file(old_path: str, new_path: str) -> None:
|
|
261
|
+
"""moves a file
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
old_path (str): old path
|
|
265
|
+
new_path (str): new path
|
|
266
|
+
"""
|
|
267
|
+
os.rename(old_path, new_path)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@validate # type:ignore
|
|
271
|
+
async def open_file(file_path: str, application_path: str) -> int:
|
|
272
|
+
"""open a file with the specified application
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
file_path (str): the file to open
|
|
276
|
+
application_path (str): the application to open with
|
|
277
|
+
Returns:
|
|
278
|
+
int: return code
|
|
279
|
+
"""
|
|
280
|
+
with subprocess.Popen([application_path, file_path]) as p:
|
|
281
|
+
return p.wait()
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# @validate # type:ignore
|
|
285
|
+
# def move_directory(old_path: str, new_path: str) -> None:
|
|
286
|
+
# """moves a directory
|
|
287
|
+
#
|
|
288
|
+
# Args:
|
|
289
|
+
# old_path (str): old path
|
|
290
|
+
# new_path (str): new path
|
|
291
|
+
# """
|
|
292
|
+
# shutil.move(old_path, new_path)
|
|
293
|
+
#
|
|
294
|
+
#
|
|
295
|
+
# @validate # type:ignore
|
|
296
|
+
# def copy_file(src: str, dest: str) -> None:
|
|
297
|
+
# """copies file from src to dest
|
|
298
|
+
#
|
|
299
|
+
# Args:
|
|
300
|
+
# src (str): src
|
|
301
|
+
# dest (str): dest
|
|
302
|
+
# """
|
|
303
|
+
# shutil.copy(src, dest)
|
|
304
|
+
#
|
|
305
|
+
#
|
|
306
|
+
# @validate # type:ignore
|
|
307
|
+
# def copy_directory(src: str, dest: str) -> None:
|
|
308
|
+
# """copies a directory from src to dest
|
|
309
|
+
#
|
|
310
|
+
# Args:
|
|
311
|
+
# src (str): stc
|
|
312
|
+
# dest (str): dest
|
|
313
|
+
# """
|
|
314
|
+
# shutil.copy(src, dest)
|
|
315
|
+
#
|
|
316
|
+
|
|
317
|
+
class IndentedWriter:
|
|
318
|
+
"""every class that will inherit this class will have the following functions available
|
|
319
|
+
write() with the same arguments a builtin print()
|
|
320
|
+
indent()
|
|
321
|
+
undent()
|
|
322
|
+
|
|
323
|
+
also, it is expected in the __init__ function to call super().__init__()
|
|
324
|
+
also, the output_stream must be set whether by the first argument io super().__init__(...)
|
|
325
|
+
or by set_stream() explicitly somewhere else.
|
|
326
|
+
|
|
327
|
+
this class will not function properly is the output_stream is not set!
|
|
328
|
+
|
|
329
|
+
"""
|
|
330
|
+
|
|
331
|
+
def __init__(self, output_stream: Optional[IO] = None, indent_value: str = "\t"):
|
|
332
|
+
self.indent_level = 0
|
|
333
|
+
self.output_stream: Optional[IO] = output_stream
|
|
334
|
+
self.indent_value = indent_value
|
|
335
|
+
|
|
336
|
+
def write(self, *args, sep=" ", end="\n") -> None:
|
|
337
|
+
"""writes the supplied arguments to the output_stream
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
sep (str, optional): the str to use as a separator between arguments. Defaults to " ".
|
|
341
|
+
end (str, optional): the str to use as the final value. Defaults to "\n".
|
|
342
|
+
|
|
343
|
+
Raises:
|
|
344
|
+
ValueError: _description_
|
|
345
|
+
"""
|
|
346
|
+
if self.output_stream is None:
|
|
347
|
+
raise ValueError(
|
|
348
|
+
"Can't write to an empty stream. the stream must not be None:"
|
|
349
|
+
" either by set_stream or by initialization")
|
|
350
|
+
self.output_stream.write(
|
|
351
|
+
str(self.indent_level * self.indent_value + sep.join(args) + end))
|
|
352
|
+
|
|
353
|
+
def set_stream(self, stream: IO) -> None:
|
|
354
|
+
"""explicitly sets the stream
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
stream (IO): stream
|
|
358
|
+
"""
|
|
359
|
+
self.output_stream = stream
|
|
360
|
+
self.output_stream = cast(IO, self.output_stream)
|
|
361
|
+
|
|
362
|
+
def indent(self) -> None:
|
|
363
|
+
"""indents the preceding output with write() by one quantity more
|
|
364
|
+
"""
|
|
365
|
+
self.indent_level += 1
|
|
366
|
+
|
|
367
|
+
def undent(self) -> None:
|
|
368
|
+
"""un-dents the preceding output with write() by one quantity less
|
|
369
|
+
has a minimum value of 0
|
|
370
|
+
"""
|
|
371
|
+
self.indent_level = max(0, self.indent_level - 1)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
class IndentedWriter2:
|
|
375
|
+
"""every class that will inherit this class will have the following functions available
|
|
376
|
+
write() with the same arguments a builtin print()
|
|
377
|
+
indent()
|
|
378
|
+
undent()
|
|
379
|
+
|
|
380
|
+
also, it is expected in the __init__ function to call super().__init__()
|
|
381
|
+
also, the output_stream must be set whether by the first argument io super().__init__(...)
|
|
382
|
+
or by set_stream() explicitly somewhere else.
|
|
383
|
+
|
|
384
|
+
this class will not function properly is the output_stream is not set!
|
|
385
|
+
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
def __init__(self, indent_value: str = "\t"):
|
|
389
|
+
self.indent_level = 0
|
|
390
|
+
self.indent_value = indent_value
|
|
391
|
+
self.buffer: str = ""
|
|
392
|
+
|
|
393
|
+
def to_stream(self, stream: IO[str]) -> None:
|
|
394
|
+
"""outputs the buffer to a stream
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
stream (IO[str]): the stream to output to
|
|
398
|
+
"""
|
|
399
|
+
stream.write(self.buffer)
|
|
400
|
+
|
|
401
|
+
def write(self, *args, sep=" ", end="\n") -> None:
|
|
402
|
+
"""writes the supplied arguments to the output_stream
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
sep (str, optional): the str to use as a separator between arguments. Defaults to " ".
|
|
406
|
+
end (str, optional): the str to use as the final value. Defaults to "\n".
|
|
407
|
+
|
|
408
|
+
Raises:
|
|
409
|
+
ValueError: _description_
|
|
410
|
+
"""
|
|
411
|
+
self.buffer += str(self.indent_level *
|
|
412
|
+
self.indent_value + sep.join(args) + end)
|
|
413
|
+
|
|
414
|
+
def indent(self) -> None:
|
|
415
|
+
"""indents the preceding output with write() by one quantity more
|
|
416
|
+
"""
|
|
417
|
+
self.indent_level += 1
|
|
418
|
+
|
|
419
|
+
def undent(self) -> None:
|
|
420
|
+
"""un-dents the preceding output with write() by one quantity less
|
|
421
|
+
has a minimum value of 0
|
|
422
|
+
"""
|
|
423
|
+
self.indent_level = max(0, self.indent_level - 1)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
__all__ = [
|
|
427
|
+
"path_exists",
|
|
428
|
+
"file_exists",
|
|
429
|
+
"directory_exists",
|
|
430
|
+
"delete_file",
|
|
431
|
+
"read_file",
|
|
432
|
+
"is_file",
|
|
433
|
+
"is_directory",
|
|
434
|
+
"get_files",
|
|
435
|
+
"get_files_and_directories",
|
|
436
|
+
"get_directories",
|
|
437
|
+
"delete_directory",
|
|
438
|
+
"clear_directory",
|
|
439
|
+
"create_directory",
|
|
440
|
+
'create_file',
|
|
441
|
+
"get_file_type_from_directory",
|
|
442
|
+
"get_file_type_from_directory_recursively",
|
|
443
|
+
"rename_file",
|
|
444
|
+
"move_file",
|
|
445
|
+
"open_file",
|
|
446
|
+
# "move_directory",
|
|
447
|
+
# "copy_file",
|
|
448
|
+
# "copy_directory",
|
|
449
|
+
"IndentedWriter",
|
|
450
|
+
"IndentedWriter2"
|
|
451
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from ..logging_.utils import get_logger
|
|
3
|
+
logger = get_logger(__name__)
|
|
4
|
+
|
|
5
|
+
from .java_interface import *
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
from ..reflection import get_python_version # type:ignore
|
|
9
|
+
except ImportError:
|
|
10
|
+
from reflection import get_python_version
|
|
11
|
+
|
|
12
|
+
python_version = get_python_version()
|
|
13
|
+
|
|
14
|
+
if python_version >= (3, 10):
|
|
15
|
+
logger.info("Python version >= 3.10, importing Java interface modules")
|
|
16
|
+
from .interfaces import *
|
|
17
|
+
else:
|
|
18
|
+
logger.debug("Skipping optional Java interface modules on Python %s", python_version)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .comparable import *
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# from abc import abstractmethod
|
|
2
|
+
# from typing import TypeVar, Generic
|
|
3
|
+
#
|
|
4
|
+
# from ..java_interface import JavaInterface
|
|
5
|
+
#
|
|
6
|
+
# T = TypeVar('T')
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
# class Comparable(JavaInterface, Generic[T]):
|
|
10
|
+
# @abstractmethod
|
|
11
|
+
# def __lt__(self, other: T) -> bool: ...
|
|
12
|
+
#
|
|
13
|
+
# @abstractmethod
|
|
14
|
+
# def __gt__(self, other: T) -> bool: ...
|
|
15
|
+
#
|
|
16
|
+
# @abstractmethod
|
|
17
|
+
# def __eq__(self, other: T) -> bool: ...
|
|
18
|
+
#
|
|
19
|
+
# @abstractmethod
|
|
20
|
+
# def __le__(self, other: T) -> bool: ...
|
|
21
|
+
#
|
|
22
|
+
# @abstractmethod
|
|
23
|
+
# def __ge__(self, other: T) -> bool: ...
|
|
24
|
+
#
|
|
25
|
+
# @abstractmethod
|
|
26
|
+
# def __ne__(self, other: T) -> bool: ...
|
|
27
|
+
#
|
|
28
|
+
#
|
|
29
|
+
# __all__ = [
|
|
30
|
+
# "Comparable",
|
|
31
|
+
# ]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
|
|
2
|
+
import logging
|
|
3
|
+
from abc import abstractmethod, ABC
|
|
4
|
+
from typing import Protocol, runtime_checkable, Any, Callable, Generic
|
|
5
|
+
from ..reflection import ClassInfo
|
|
6
|
+
from ..logging_.utils import get_logger
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InterfaceError(Exception):
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# @runtime_checkable
|
|
16
|
+
class JavaInterface(ABC):
|
|
17
|
+
InterfaceError = InterfaceError
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
21
|
+
logger.info("Initializing JavaInterface subclass: %s", cls.__name__)
|
|
22
|
+
info = ClassInfo(cls)
|
|
23
|
+
|
|
24
|
+
# Check if this is a direct interface definition
|
|
25
|
+
is_interface = False
|
|
26
|
+
for base in info.bases:
|
|
27
|
+
if base.name == JavaInterface.__name__:
|
|
28
|
+
setattr(cls, "__is_interface__", True)
|
|
29
|
+
is_interface = True
|
|
30
|
+
break
|
|
31
|
+
|
|
32
|
+
if not is_interface:
|
|
33
|
+
setattr(cls, "__is_interface__", False)
|
|
34
|
+
logger.debug("Validating interface compliance for implementation class: %s", cls.__name__)
|
|
35
|
+
info = ClassInfo(cls)
|
|
36
|
+
|
|
37
|
+
actual_func_names = set(f.name for f in info.functions)
|
|
38
|
+
for to_remove in {"__class_getitem__", "__init_subclass__"}:
|
|
39
|
+
if hasattr(cls, to_remove) and getattr(cls, to_remove, None) is getattr(JavaInterface, to_remove, None):
|
|
40
|
+
actual_func_names.remove(to_remove)
|
|
41
|
+
|
|
42
|
+
# Validate interface implementation
|
|
43
|
+
for interface in (base for base in cls.__mro__ if getattr(base, "__is_interface__", False)):
|
|
44
|
+
expected_func_names = set(f.name for f in ClassInfo(interface).abstract_methods)
|
|
45
|
+
|
|
46
|
+
if subtraction := expected_func_names.difference(actual_func_names):
|
|
47
|
+
error_msg = f"class '{cls.__name__}' does not implement required methods {subtraction}"
|
|
48
|
+
logger.error("Interface validation failed: %s", error_msg)
|
|
49
|
+
raise InterfaceError(error_msg)
|
|
50
|
+
else:
|
|
51
|
+
logger.debug("Class %s successfully implements interface %s", cls.__name__, interface.__name__)
|
|
52
|
+
|
|
53
|
+
logger.info("JavaInterface subclass %s initialized successfully", cls.__name__)
|
|
54
|
+
super().__init_subclass__(**kwargs)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
__all__ = [
|
|
58
|
+
"JavaInterface",
|
|
59
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from ....io_ import delete_file, directory_exists, create_directory
|
|
5
|
+
from ...utils import get_logger
|
|
6
|
+
from ..logger_strategy_impl_base import LoggerStrategyImplBase
|
|
7
|
+
|
|
8
|
+
logger = get_logger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FIleLogger(LoggerStrategyImplBase):
|
|
12
|
+
def __init__(self, output_path: str, logger_id: str, delete_if_already_exists: bool = True, channel: str = "all"):
|
|
13
|
+
logger.info("Initializing FileLogger: path=%s, id=%s, delete_existing=%s, channel=%s", output_path, logger_id, delete_if_already_exists, channel)
|
|
14
|
+
|
|
15
|
+
if delete_if_already_exists:
|
|
16
|
+
delete_file(output_path)
|
|
17
|
+
|
|
18
|
+
parent = str(Path(output_path).parent.absolute().resolve())
|
|
19
|
+
if not directory_exists(parent):
|
|
20
|
+
logger.info("Creating parent directory: %s", parent)
|
|
21
|
+
create_directory(parent)
|
|
22
|
+
|
|
23
|
+
self.output_path: str = str(Path(output_path).absolute().resolve())
|
|
24
|
+
|
|
25
|
+
def foo(s: str):
|
|
26
|
+
with open(self.output_path, "a+") as f:
|
|
27
|
+
f.write(s)
|
|
28
|
+
|
|
29
|
+
super().__init__(foo, logger_id, channel)
|
|
30
|
+
logger.info("FileLogger %s initialized successfully", logger_id)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"FIleLogger"
|
|
35
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from ...utils import get_logger
|
|
3
|
+
from ..logger_strategy_impl_base import LoggerStrategyImplBase
|
|
4
|
+
|
|
5
|
+
logger = get_logger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PrintLogger(LoggerStrategyImplBase):
|
|
9
|
+
def __init__(self, logger_id: str, channel: str = "all"):
|
|
10
|
+
logger.info("Initializing PrintLogger: id=%s, channel=%s", logger_id, channel)
|
|
11
|
+
|
|
12
|
+
def print_func(s: str):
|
|
13
|
+
print(s, end="")
|
|
14
|
+
|
|
15
|
+
super().__init__(print_func, logger_id, channel)
|
|
16
|
+
logger.info("PrintLogger %s initialized successfully", logger_id)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"PrintLogger"
|
|
21
|
+
]
|