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.
Files changed (287) hide show
  1. danielutils/__init__.py +50 -0
  2. danielutils/abstractions/__init__.py +3 -0
  3. danielutils/abstractions/db/__init__.py +10 -0
  4. danielutils/abstractions/db/database.py +206 -0
  5. danielutils/abstractions/db/database_definitions.py +219 -0
  6. danielutils/abstractions/db/database_exceptions.py +34 -0
  7. danielutils/abstractions/db/database_factory.py +70 -0
  8. danielutils/abstractions/db/database_initializer.py +261 -0
  9. danielutils/abstractions/db/database_models.py +213 -0
  10. danielutils/abstractions/db/dependencies.py +6 -0
  11. danielutils/abstractions/db/implementations/__init__.py +4 -0
  12. danielutils/abstractions/db/implementations/in_memory_database.py +365 -0
  13. danielutils/abstractions/db/implementations/persistent_in_memory_database.py +174 -0
  14. danielutils/abstractions/db/implementations/redis_database.py +403 -0
  15. danielutils/abstractions/db/implementations/sqlite_database.py +491 -0
  16. danielutils/abstractions/multiprogramming/__init__.py +3 -0
  17. danielutils/abstractions/multiprogramming/multi_id.py +26 -0
  18. danielutils/abstractions/multiprogramming/worker.py +104 -0
  19. danielutils/abstractions/multiprogramming/worker_pool.py +98 -0
  20. danielutils/abstractions/repl.py +125 -0
  21. danielutils/aliases.py +174 -0
  22. danielutils/async_/__init__.py +7 -0
  23. danielutils/async_/async_cmd.py +28 -0
  24. danielutils/async_/async_command.py +879 -0
  25. danielutils/async_/async_layered_command.py +125 -0
  26. danielutils/async_/async_retry_executor.py +86 -0
  27. danielutils/async_/async_worker_pool.py +110 -0
  28. danielutils/async_/time_strategy.py +73 -0
  29. danielutils/async_/utils.py +57 -0
  30. danielutils/better_builtins/__init__.py +3 -0
  31. danielutils/better_builtins/counter.py +48 -0
  32. danielutils/better_builtins/frange.py +266 -0
  33. danielutils/better_builtins/typed_builtins/__init__.py +4 -0
  34. danielutils/better_builtins/typed_builtins/factory.py +126 -0
  35. danielutils/better_builtins/typed_builtins/tdict.py +36 -0
  36. danielutils/better_builtins/typed_builtins/tlist.py +223 -0
  37. danielutils/better_builtins/typed_builtins/tset.py +67 -0
  38. danielutils/better_builtins/typed_builtins/ttuple.py +15 -0
  39. danielutils/colors.py +203 -0
  40. danielutils/context_managers/__init__.py +5 -0
  41. danielutils/context_managers/attr_context.py +40 -0
  42. danielutils/context_managers/multi_context.py +34 -0
  43. danielutils/context_managers/optional_context.py +33 -0
  44. danielutils/context_managers/state_context.py +25 -0
  45. danielutils/context_managers/temporary_file.py +108 -0
  46. danielutils/convenience.py +12 -0
  47. danielutils/conversions/__init__.py +2 -0
  48. danielutils/conversions/main_conversions.py +131 -0
  49. danielutils/conversions/specialized_conversions/__init__.py +2 -0
  50. danielutils/conversions/specialized_conversions/to_hex.py +25 -0
  51. danielutils/conversions/specialized_conversions/to_int.py +19 -0
  52. danielutils/custom_types.py +18 -0
  53. danielutils/data_structures/__init__.py +8 -0
  54. danielutils/data_structures/algorithms.py +52 -0
  55. danielutils/data_structures/comparer.py +47 -0
  56. danielutils/data_structures/default_dict.py +23 -0
  57. danielutils/data_structures/functions.py +35 -0
  58. danielutils/data_structures/graph/__init__.py +4 -0
  59. danielutils/data_structures/graph/binary_node.py +71 -0
  60. danielutils/data_structures/graph/graph.py +208 -0
  61. danielutils/data_structures/graph/multinode.py +101 -0
  62. danielutils/data_structures/graph/node.py +60 -0
  63. danielutils/data_structures/heap/__init__.py +3 -0
  64. danielutils/data_structures/heap/heap.py +119 -0
  65. danielutils/data_structures/heap/max_heap.py +18 -0
  66. danielutils/data_structures/heap/min_heap.py +18 -0
  67. danielutils/data_structures/queue/__init__.py +3 -0
  68. danielutils/data_structures/queue/atomic_queue.py +15 -0
  69. danielutils/data_structures/queue/priority_queue.py +110 -0
  70. danielutils/data_structures/queue/queue.py +92 -0
  71. danielutils/data_structures/stack.py +102 -0
  72. danielutils/data_structures/trees/__init__.py +2 -0
  73. danielutils/data_structures/trees/binary_syntax_tree.py +84 -0
  74. danielutils/data_structures/trees/binary_tree.py +63 -0
  75. danielutils/date.py +43 -0
  76. danielutils/date_time.py +23 -0
  77. danielutils/decorators/__init__.py +18 -0
  78. danielutils/decorators/atomic.py +45 -0
  79. danielutils/decorators/attach.py +61 -0
  80. danielutils/decorators/chain_decorators.py +39 -0
  81. danielutils/decorators/decorate_conditionally.py +32 -0
  82. danielutils/decorators/delay_call.py +47 -0
  83. danielutils/decorators/deprecate.py +46 -0
  84. danielutils/decorators/final.py +39 -0
  85. danielutils/decorators/limit_recursion.py +63 -0
  86. danielutils/decorators/memo.py +68 -0
  87. danielutils/decorators/normalize_decorator.py +55 -0
  88. danielutils/decorators/overload.py +204 -0
  89. danielutils/decorators/partially_implemented.py +32 -0
  90. danielutils/decorators/processify.py +74 -0
  91. danielutils/decorators/property.py +42 -0
  92. danielutils/decorators/singleton.py +59 -0
  93. danielutils/decorators/threadify.py +40 -0
  94. danielutils/decorators/timeout.py +82 -0
  95. danielutils/decorators/total_ordering.py +82 -0
  96. danielutils/decorators/validate.py +227 -0
  97. danielutils/exceptions.py +90 -0
  98. danielutils/functions/__init__.py +13 -0
  99. danielutils/functions/areoneof.py +47 -0
  100. danielutils/functions/check_foreach.py +39 -0
  101. danielutils/functions/factorial.py +24 -0
  102. danielutils/functions/flatten.py +33 -0
  103. danielutils/functions/foreach.py +20 -0
  104. danielutils/functions/isoftype.py +475 -0
  105. danielutils/functions/isoneof.py +71 -0
  106. danielutils/functions/multiloop.py +51 -0
  107. danielutils/functions/parallel_for.py +47 -0
  108. danielutils/functions/partition.py +45 -0
  109. danielutils/functions/powerset.py +31 -0
  110. danielutils/functions/subseteq.py +25 -0
  111. danielutils/functions/types_subseteq.py +51 -0
  112. danielutils/generators/__init__.py +3 -0
  113. danielutils/generators/conditional_generator.py +59 -0
  114. danielutils/generators/generator_from_stream.py +31 -0
  115. danielutils/generators/join_generators.py +109 -0
  116. danielutils/internet.py +92 -0
  117. danielutils/io_.py +451 -0
  118. danielutils/java/__init__.py +18 -0
  119. danielutils/java/interfaces/__init__.py +1 -0
  120. danielutils/java/interfaces/comparable.py +31 -0
  121. danielutils/java/java_interface.py +59 -0
  122. danielutils/logging_/__init__.py +2 -0
  123. danielutils/logging_/_impl/__init__.py +4 -0
  124. danielutils/logging_/_impl/builtin_impls/__init__.py +2 -0
  125. danielutils/logging_/_impl/builtin_impls/file_logger.py +35 -0
  126. danielutils/logging_/_impl/builtin_impls/print_logger.py +21 -0
  127. danielutils/logging_/_impl/log_level.py +13 -0
  128. danielutils/logging_/_impl/logger.py +109 -0
  129. danielutils/logging_/_impl/logger_strategy_impl_base.py +37 -0
  130. danielutils/logging_/utils.py +199 -0
  131. danielutils/lombok/__init__.py +1 -0
  132. danielutils/lombok/builder.py +68 -0
  133. danielutils/math_/__init__.py +2 -0
  134. danielutils/math_/constants.py +103 -0
  135. danielutils/math_/functions.py +34 -0
  136. danielutils/math_/math_print.py +52 -0
  137. danielutils/math_/math_symbols.py +125 -0
  138. danielutils/metaclasses/__init__.py +5 -0
  139. danielutils/metaclasses/atomic_class_meta.py +36 -0
  140. danielutils/metaclasses/implicit_data_deleter_meta.py +87 -0
  141. danielutils/metaclasses/instance_cache_meta.py +66 -0
  142. danielutils/metaclasses/interface.py +328 -0
  143. danielutils/metaclasses/overload_meta.py +48 -0
  144. danielutils/mock_/__init__.py +1 -0
  145. danielutils/mock_/mock_module.py +27 -0
  146. danielutils/path.py +55 -0
  147. danielutils/print_.py +123 -0
  148. danielutils/progress_bar/__init__.py +3 -0
  149. danielutils/progress_bar/ascii_progress_bar.py +161 -0
  150. danielutils/progress_bar/progress_bar.py +75 -0
  151. danielutils/progress_bar/progress_bar_pool.py +72 -0
  152. danielutils/protocols/__init__.py +3 -0
  153. danielutils/protocols/dictable.py +38 -0
  154. danielutils/protocols/evaluable.py +26 -0
  155. danielutils/protocols/serializable.py +51 -0
  156. danielutils/py.typed +0 -0
  157. danielutils/random_.py +47 -0
  158. danielutils/reflection/__init__.py +6 -0
  159. danielutils/reflection/declarations.py +288 -0
  160. danielutils/reflection/file/__init__.py +1 -0
  161. danielutils/reflection/file/file_reflection.py +85 -0
  162. danielutils/reflection/function/__init__.py +1 -0
  163. danielutils/reflection/function/function_reflections.py +152 -0
  164. danielutils/reflection/info_classes/__init__.py +6 -0
  165. danielutils/reflection/info_classes/argument_info.py +278 -0
  166. danielutils/reflection/info_classes/class_info.py +204 -0
  167. danielutils/reflection/info_classes/decorator_info.py +54 -0
  168. danielutils/reflection/info_classes/file_info.py +1180 -0
  169. danielutils/reflection/info_classes/folder_info.py +592 -0
  170. danielutils/reflection/info_classes/function_info.py +551 -0
  171. danielutils/reflection/info_classes/import_info.py +207 -0
  172. danielutils/reflection/interpreter/__init__.py +9 -0
  173. danielutils/reflection/interpreter/callstack.py +57 -0
  174. danielutils/reflection/interpreter/get_traceback.py +27 -0
  175. danielutils/reflection/interpreter/interpreter.py +41 -0
  176. danielutils/reflection/interpreter/is_debugging.py +13 -0
  177. danielutils/reflection/interpreter/os_.py +33 -0
  178. danielutils/reflection/interpreter/packages.py +33 -0
  179. danielutils/reflection/interpreter/python_version.py +33 -0
  180. danielutils/reflection/interpreter/signals.py +18 -0
  181. danielutils/reflection/interpreter/tracer.py +175 -0
  182. danielutils/reflection/module/__init__.py +3 -0
  183. danielutils/reflection/module/lazy_module.py +104 -0
  184. danielutils/reflection/module/module_reflections.py +34 -0
  185. danielutils/reflection/module/package_reflection.py +161 -0
  186. danielutils/retry_executor/__init__.py +3 -0
  187. danielutils/retry_executor/backoff_strategies/__init__.py +6 -0
  188. danielutils/retry_executor/backoff_strategies/constant_backoff.py +25 -0
  189. danielutils/retry_executor/backoff_strategies/exponential_backoff.py +26 -0
  190. danielutils/retry_executor/backoff_strategies/functional_backoff.py +29 -0
  191. danielutils/retry_executor/backoff_strategies/linear_backoff.py +23 -0
  192. danielutils/retry_executor/backoff_strategies/multiplicative_backoff.py +23 -0
  193. danielutils/retry_executor/backoff_strategies/no_backoff.py +17 -0
  194. danielutils/retry_executor/backoff_strategy.py +28 -0
  195. danielutils/retry_executor/retry_executor.py +55 -0
  196. danielutils/snippets/__init__.py +1 -0
  197. danielutils/snippets/try_get.py +28 -0
  198. danielutils/system/__init__.py +3 -0
  199. danielutils/system/independent.py +197 -0
  200. danielutils/system/layered_command.py +130 -0
  201. danielutils/system/windows/__init__.py +2 -0
  202. danielutils/system/windows/utils/__init__.py +1 -0
  203. danielutils/system/windows/utils/filetime.py +19 -0
  204. danielutils/system/windows/win32_ctime.py +183 -0
  205. danielutils/system/windows/windows.py +78 -0
  206. danielutils/testing/__init__.py +1 -0
  207. danielutils/testing/unittest_/__init__.py +2 -0
  208. danielutils/testing/unittest_/always_teardown_testcase.py +75 -0
  209. danielutils/testing/unittest_/auto_cwd_testcase.py +114 -0
  210. danielutils/text.py +169 -0
  211. danielutils/time.py +64 -0
  212. danielutils/tools/__init__.py +1 -0
  213. danielutils/tools/unittest_test_runner/__init__.py +9 -0
  214. danielutils/tools/unittest_test_runner/cli.py +70 -0
  215. danielutils/tools/unittest_test_runner/core/__init__.py +17 -0
  216. danielutils/tools/unittest_test_runner/core/discovery.py +322 -0
  217. danielutils/tools/unittest_test_runner/core/execution.py +244 -0
  218. danielutils/tools/unittest_test_runner/core/parser.py +163 -0
  219. danielutils/tools/unittest_test_runner/core/runner.py +561 -0
  220. danielutils/tools/unittest_test_runner/models.py +82 -0
  221. danielutils/university/__init__.py +7 -0
  222. danielutils/university/computability_and_complexity/__init__.py +2 -0
  223. danielutils/university/computability_and_complexity/discreate_finite_automaton.py +89 -0
  224. danielutils/university/computability_and_complexity/languages/__init__.py +0 -0
  225. danielutils/university/computability_and_complexity/languages/language.py +17 -0
  226. danielutils/university/computability_and_complexity/languages/sat.py +71 -0
  227. danielutils/university/computability_and_complexity/turing_machine.py +47 -0
  228. danielutils/university/databases/__init__.py +1 -0
  229. danielutils/university/databases/all.py +756 -0
  230. danielutils/university/image_proccesing/__init__.py +1 -0
  231. danielutils/university/image_proccesing/encoding/__init__.py +3 -0
  232. danielutils/university/image_proccesing/encoding/encoding.py +35 -0
  233. danielutils/university/image_proccesing/encoding/lossless/__init__.py +4 -0
  234. danielutils/university/image_proccesing/encoding/lossless/huffman.py +0 -0
  235. danielutils/university/image_proccesing/encoding/lossless/lossless_encoding.py +10 -0
  236. danielutils/university/image_proccesing/encoding/lossless/lzw.py +0 -0
  237. danielutils/university/image_proccesing/encoding/lossless/run_length.py +22 -0
  238. danielutils/university/image_proccesing/encoding/lossy/__init__.py +1 -0
  239. danielutils/university/image_proccesing/encoding/lossy/lossy_encoding.py +10 -0
  240. danielutils/university/image_proccesing/tansformations/__init__.py +0 -0
  241. danielutils/university/image_proccesing/tansformations/gaussian.py +0 -0
  242. danielutils/university/image_proccesing/tansformations/gradient.py +0 -0
  243. danielutils/university/image_proccesing/tansformations/hough.py +0 -0
  244. danielutils/university/image_proccesing/tansformations/laplacian.py +0 -0
  245. danielutils/university/image_proccesing/tansformations/transformation.py +11 -0
  246. danielutils/university/linear_algebra/__init__.py +1 -0
  247. danielutils/university/linear_algebra/matrix.py +404 -0
  248. danielutils/university/machine_learning/__init__.py +0 -0
  249. danielutils/university/machine_learning/activation_functions/__init__.py +2 -0
  250. danielutils/university/machine_learning/activation_functions/activation_function.py +11 -0
  251. danielutils/university/machine_learning/activation_functions/relu.py +11 -0
  252. danielutils/university/machine_learning/neuron.py +15 -0
  253. danielutils/university/oop/__init__.py +1 -0
  254. danielutils/university/oop/observer.py +31 -0
  255. danielutils/university/oop/strategy.py +9 -0
  256. danielutils/university/probability/__init__.py +7 -0
  257. danielutils/university/probability/conditional_variable/__init__.py +3 -0
  258. danielutils/university/probability/conditional_variable/conditional_variable.py +138 -0
  259. danielutils/university/probability/conditional_variable/continuous/__init__.py +0 -0
  260. danielutils/university/probability/conditional_variable/discrete/__init__.py +8 -0
  261. danielutils/university/probability/conditional_variable/discrete/bernoulli.py +38 -0
  262. danielutils/university/probability/conditional_variable/discrete/bernoulli_sum.py +31 -0
  263. danielutils/university/probability/conditional_variable/discrete/binomial.py +40 -0
  264. danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +36 -0
  265. danielutils/university/probability/conditional_variable/discrete/discrete.py +42 -0
  266. danielutils/university/probability/conditional_variable/discrete/geometric.py +43 -0
  267. danielutils/university/probability/conditional_variable/discrete/poisson.py +32 -0
  268. danielutils/university/probability/conditional_variable/discrete/uniform.py +33 -0
  269. danielutils/university/probability/distributions.py +35 -0
  270. danielutils/university/probability/expressions/__init__.py +2 -0
  271. danielutils/university/probability/expressions/accumulation_expression.py +291 -0
  272. danielutils/university/probability/expressions/probability_expression.py +110 -0
  273. danielutils/university/probability/funcs/__init__.py +4 -0
  274. danielutils/university/probability/funcs/covariance.py +12 -0
  275. danielutils/university/probability/funcs/expected_value.py +41 -0
  276. danielutils/university/probability/funcs/probability_function.py +14 -0
  277. danielutils/university/probability/funcs/variance.py +17 -0
  278. danielutils/university/probability/operator.py +79 -0
  279. danielutils/university/probability/protocols.py +32 -0
  280. danielutils/university/probability/supp.py +101 -0
  281. danielutils/university/probability/transformation.py +44 -0
  282. danielutils/versioned_imports.py +31 -0
  283. danielutils-1.1.28.dist-info/METADATA +390 -0
  284. danielutils-1.1.28.dist-info/RECORD +287 -0
  285. danielutils-1.1.28.dist-info/WHEEL +5 -0
  286. danielutils-1.1.28.dist-info/licenses/LICENSE +21 -0
  287. danielutils-1.1.28.dist-info/top_level.txt +1 -0
@@ -0,0 +1,31 @@
1
+ import logging
2
+ from typing import Iterable, Optional, Generator, Any
3
+ import itertools
4
+ from ..logging_.utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ def powerset(iterable: Iterable[Any], length: Optional[int] = None) -> Generator[tuple, None, None]:
10
+ """returns the powerset of specified length of an iterable
11
+ """
12
+ logger.debug("Generating powerset for iterable with length: %s", length)
13
+ if length is None:
14
+ if hasattr(iterable, "__len__"):
15
+ length = len(iterable) # type:ignore
16
+ logger.debug("Auto-detected length: %s", length)
17
+ else:
18
+ logger.error("Cannot determine length of iterable")
19
+ raise ValueError(
20
+ "when using powerset must supply length explicitly or object should support len()")
21
+
22
+ logger.debug("Generating combinations for lengths 0 to %s", length)
23
+ for i in range(length+1):
24
+ logger.debug("Generating combinations of length %s", i)
25
+ yield from itertools.combinations(iterable, i)
26
+ logger.debug("Powerset generation completed")
27
+
28
+
29
+ __all__ = [
30
+ "powerset"
31
+ ]
@@ -0,0 +1,25 @@
1
+ import logging
2
+ from ..logging_.utils import get_logger
3
+
4
+ logger = get_logger(__name__)
5
+
6
+
7
+ def subseteq(l1: list, l2: list) -> bool:
8
+ """return whether l1 is in list l2
9
+
10
+ Args:
11
+ l1 (list): first list
12
+ l2 (list): second list
13
+
14
+ Returns:
15
+ bool: boolean result
16
+ """
17
+ logger.debug("Checking if %s is subset of %s", l1, l2)
18
+ result = set(l1).issubset(set(l2))
19
+ logger.debug("Subset check result: %s", result)
20
+ return result
21
+
22
+
23
+ __all__ = [
24
+ "subseteq"
25
+ ]
@@ -0,0 +1,51 @@
1
+ import logging
2
+ from typing import Iterable, get_args, Union, Set as Set
3
+ from ..reflection import get_python_version
4
+ from ..logging_.utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+ if get_python_version() >= (3, 9):
9
+ from builtins import set as Set
10
+
11
+
12
+ def to_set(x: Union[type, Iterable[type]]) -> Set[int]:
13
+ """converts type/types to a set representing them
14
+ """
15
+ logger.debug("Converting type to set: %s", x)
16
+ res: Set[int] = set()
17
+ if hasattr(x, "__origin__") and x.__origin__ is Union:
18
+ logger.debug("Processing Union type")
19
+ for xi in get_args(x):
20
+ res.update(to_set(xi))
21
+ elif isinstance(x, Iterable):
22
+ logger.debug("Processing Iterable type")
23
+ for v in x:
24
+ res.update(to_set(v))
25
+ return res
26
+ else:
27
+ logger.debug("Adding single type ID: %s", id(x))
28
+ res.update(set([id(x)]))
29
+ logger.debug("Result set: %s", res)
30
+ return res
31
+
32
+
33
+ def types_subseteq(a: Union[type, Iterable[type]], b: Union[type, Iterable[type]]) -> bool:
34
+ """checks if 'a' is contained in 'b' typing wise
35
+
36
+ Args:
37
+ a (type | Iterable[type])
38
+ b (type | Iterable[type])
39
+
40
+ Returns:
41
+ bool: result of containment
42
+ """
43
+ logger.debug("Checking type subset: %s ⊆ %s", a, b)
44
+ result = to_set(a).issubset(to_set(b))
45
+ logger.debug("Type subset result: %s", result)
46
+ return result
47
+
48
+
49
+ __all__ = [
50
+ "types_subseteq"
51
+ ]
@@ -0,0 +1,3 @@
1
+ from .join_generators import *
2
+ from .generator_from_stream import *
3
+ from .conditional_generator import *
@@ -0,0 +1,59 @@
1
+ import logging
2
+ from typing import Generator, Callable, Any
3
+ from ..logging_.utils import get_logger
4
+
5
+ logger = get_logger(__name__)
6
+
7
+
8
+ def generate_except(generator: Generator[Any, None, None],
9
+ binary_consumer: Callable[[int, Any], bool]) -> Generator[Any, None, None]:
10
+ """will yield from generator except from when the predicate will return False
11
+
12
+ Args:
13
+ generator (Generator[Any, None, None]): generator
14
+ binary_consumer (Callable[[int, Any], bool]): predicate. (item_index, item)
15
+
16
+ Yields:
17
+ Generator[Any, None, None]: filtered generator
18
+ """
19
+ logger.info("Starting generate_except filtering")
20
+ items_processed = 0
21
+ items_yielded = 0
22
+
23
+ for i, value in enumerate(generator):
24
+ items_processed += 1
25
+ if not binary_consumer(i, value):
26
+ items_yielded += 1
27
+ yield value
28
+
29
+ logger.info("generate_except completed: processed %s items, yielded %s items", items_processed, items_yielded)
30
+
31
+
32
+ def generate_when(generator: Generator[Any, None, None],
33
+ binary_consumer: Callable[[int, Any], bool]) -> Generator[Any, None, None]:
34
+ """will yield from generator except from when the predicate will return True
35
+
36
+ Args:
37
+ generator (Generator[Any, None, None]): generator
38
+ binary_consumer (Callable[[int, Any], bool]): predicate. (item_index, item)
39
+
40
+ Yields:
41
+ Generator[Any, None, None]: filtered generator
42
+ """
43
+ logger.info("Starting generate_when filtering")
44
+ items_processed = 0
45
+ items_yielded = 0
46
+
47
+ for i, value in enumerate(generator):
48
+ items_processed += 1
49
+ if binary_consumer(i, value):
50
+ items_yielded += 1
51
+ yield value
52
+
53
+ logger.info("generate_when completed: processed %s items, yielded %s items", items_processed, items_yielded)
54
+
55
+
56
+ __all__ = [
57
+ "generate_when",
58
+ "generate_except"
59
+ ]
@@ -0,0 +1,31 @@
1
+ import logging
2
+ from typing import IO, Generator, Any, Iterable, Union
3
+ from ..decorators import validate
4
+ from ..logging_.utils import get_logger
5
+
6
+ logger = get_logger(__name__)
7
+
8
+
9
+ @validate # type:ignore
10
+ def generator_from_stream(stream: Union[IO, Iterable[Any]]) -> Generator[Any, None, None]:
11
+ """will yield values from a given stream
12
+
13
+ Args:
14
+ stream (IO): the stream
15
+
16
+ Yields:
17
+ Generator[Any, None, None]: the resulting generator
18
+ """
19
+ logger.info("Starting generator_from_stream with stream type: %s", type(stream).__name__)
20
+ items_yielded = 0
21
+
22
+ for v in stream:
23
+ items_yielded += 1
24
+ yield v
25
+
26
+ logger.info("generator_from_stream completed, yielded %s items", items_yielded)
27
+
28
+
29
+ __all__ = [
30
+ "generator_from_stream"
31
+ ]
@@ -0,0 +1,109 @@
1
+ import logging
2
+ import time
3
+ from typing import Generator, Any, Tuple as Tuple
4
+ from threading import Semaphore # , Condition
5
+ from ..decorators import threadify
6
+ from ..data_structures import AtomicQueue, Queue
7
+ from ..better_builtins import AtomicCounter
8
+ # from ..Print import aprint
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 tuple as Tuple # type:ignore
16
+
17
+
18
+ def join_generators_busy_waiting(*generators) -> Generator[Tuple[int, Any], None, None]:
19
+ """joins an arbitrary amount of generators to yield objects as soon someone yield an object
20
+
21
+ Yields:
22
+ Generator[tuple[int, Any], None, None]: resulting generator
23
+ """
24
+ logger.info("Starting join_generators_busy_waiting with %s generators", len(generators))
25
+ q: AtomicQueue[Tuple[int, Any]] = AtomicQueue()
26
+ threads_status = [False for _ in range(len(generators))]
27
+
28
+ @threadify # type:ignore
29
+ def yield_from_one(thread_id: int, generator: Generator):
30
+ nonlocal threads_status
31
+ items_yielded = 0
32
+ for v in generator:
33
+ q.push((thread_id, v))
34
+ items_yielded += 1
35
+ logger.debug("Thread %s finished processing, yielded %s items", thread_id, items_yielded)
36
+ threads_status[thread_id] = True
37
+
38
+ for i, gen in enumerate(generators):
39
+ yield_from_one(i, gen)
40
+
41
+ # busy waiting
42
+ total_yielded = 0
43
+ while not all(threads_status):
44
+ while not q.is_empty():
45
+ item = q.pop()
46
+ total_yielded += 1
47
+ yield item
48
+ if not q.is_empty():
49
+ remaining_items = 0
50
+ for item in q:
51
+ remaining_items += 1
52
+ yield item
53
+
54
+ logger.info("join_generators_busy_waiting completed, yielded %s items total", total_yielded)
55
+
56
+
57
+ def join_generators(*generators) -> Generator[Tuple[int, Any], None, None]:
58
+ """will join generators to yield from all of them simultaneously
59
+ without busy waiting, using semaphores and multithreading
60
+
61
+ Yields:
62
+ Generator[Any, None, None]: one generator that combines all of the given ones
63
+ """
64
+ logger.info("Starting join_generators with %s generators", len(generators))
65
+ queue: Queue = Queue()
66
+ edit_queue_semaphore = Semaphore(1)
67
+ queue_status_semaphore = Semaphore(0)
68
+ finished_threads_counter = AtomicCounter()
69
+
70
+ @threadify # type:ignore
71
+ def thread_entry_point(index: int, generator: Generator) -> None:
72
+ items_processed = 0
73
+ for value in generator:
74
+ with edit_queue_semaphore:
75
+ queue.push((index, value))
76
+ queue_status_semaphore.release()
77
+ items_processed += 1
78
+ time.sleep(0)
79
+ logger.debug("Thread %s finished processing, processed %s items", index, items_processed)
80
+ finished_threads_counter.increment()
81
+
82
+ if finished_threads_counter.get() == len(generators):
83
+ # re-release the lock once from the last thread because it
84
+ # gets stuck in the main loop after the generation has stopped
85
+ queue_status_semaphore.release()
86
+
87
+ for i, generator in enumerate(generators):
88
+ thread_entry_point(i, generator)
89
+
90
+ total_yielded = 0
91
+ while True:
92
+ queue_status_semaphore.acquire()
93
+ with edit_queue_semaphore:
94
+ while not queue.is_empty():
95
+ item = queue.pop()
96
+ total_yielded += 1
97
+ yield item
98
+ if finished_threads_counter.get() == len(generators):
99
+ with edit_queue_semaphore:
100
+ if queue.is_empty():
101
+ break
102
+
103
+ logger.info("join_generators completed, yielded %s items total", total_yielded)
104
+
105
+
106
+ __all__ = [
107
+ "join_generators_busy_waiting",
108
+ "join_generators"
109
+ ]
@@ -0,0 +1,92 @@
1
+ import logging
2
+ import urllib.request
3
+ import urllib.parse
4
+ from urllib.parse import urlparse
5
+ import urllib
6
+ from typing import Tuple as Tuple
7
+ from .decorators import validate
8
+ from .reflection import get_python_version
9
+ from .logging_.utils import get_logger
10
+
11
+ logger = get_logger(__name__)
12
+
13
+ if get_python_version() >= (3, 9):
14
+ from builtins import tuple as Tuple # type:ignore
15
+
16
+ # def prettify_html(html: str) -> str:
17
+ # return html
18
+
19
+
20
+ @validate # type:ignore
21
+ def get_html(url: str) -> str:
22
+ """returns the html for a given url
23
+
24
+ Args:
25
+ url (str): url
26
+
27
+ Returns:
28
+ str: the html as a string
29
+ """
30
+ logger.info("Fetching HTML from URL: %s", url)
31
+ user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'
32
+ headers = {'User-Agent': user_agent, }
33
+ req = urllib.request.Request(url, headers=headers)
34
+ with urllib.request.urlopen(req) as f:
35
+ html = f.read().decode('UTF-8')
36
+ logger.info("Successfully fetched HTML, length: %d characters", len(html))
37
+ # return bs4(html, 'html.parser').prettify()
38
+ return html
39
+
40
+
41
+ @validate # type:ignore
42
+ def get_url_details(url: str) -> "Tuple[str, str, str, str, str, str]":
43
+ """returns details about a url
44
+
45
+ Args:
46
+ url (str): url
47
+
48
+ Returns:
49
+ tuple[str, str, str, str, str]: scheme, netloc, path, params, query, fragment
50
+ """
51
+ scheme, netloc, path, params, query, fragment = urlparse(url)
52
+ return scheme, netloc, path, params, query, fragment
53
+
54
+
55
+ @validate # type:ignore
56
+ def url_encode(s: str) -> str:
57
+ """encodes a string for url
58
+
59
+ Args:
60
+ s (str): string to encode
61
+
62
+ Returns:
63
+ str: encoded string
64
+ """
65
+ return urllib.parse.quote(s)
66
+
67
+
68
+ @validate # type:ignore
69
+ def url_decode(s: str) -> str:
70
+ """decodes a url encoded string back to normal string
71
+
72
+ Args:
73
+ s (str): string to decode
74
+
75
+ Returns:
76
+ str: result string
77
+ """
78
+ return urllib.parse.unquote_plus(s)
79
+
80
+
81
+ # def get_elements(html: str, tag: str) -> list[str]:
82
+ # return [str(v) for v in bs4(html, 'html.parser').find_all(tag)]
83
+
84
+
85
+ __all__ = [
86
+ # "prettify_html",
87
+ "get_html",
88
+ "get_url_details",
89
+ "url_encode",
90
+ "url_decode",
91
+ # "get_elements"
92
+ ]