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
|
@@ -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,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
|
+
]
|
danielutils/internet.py
ADDED
|
@@ -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
|
+
]
|