danielutils 0.9.74__tar.gz → 0.9.77__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- danielutils-0.9.77/MANIFEST.in +1 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/PKG-INFO +6 -3
- {danielutils-0.9.74 → danielutils-0.9.77}/README.md +4 -1
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/__init__.py +7 -11
- danielutils-0.9.77/danielutils/abstractions/__init__.py +3 -0
- danielutils-0.9.77/danielutils/abstractions/database/__init__.py +2 -0
- danielutils-0.9.77/danielutils/abstractions/database/cached_database.py +75 -0
- danielutils-0.9.77/danielutils/abstractions/database/database.py +104 -0
- danielutils-0.9.77/danielutils/abstractions/database/redis_database.py +44 -0
- {danielutils-0.9.74/danielutils/threads → danielutils-0.9.77/danielutils/abstractions/multiprogramming}/__init__.py +1 -0
- {danielutils-0.9.74/danielutils/threads → danielutils-0.9.77/danielutils/abstractions/multiprogramming}/worker.py +1 -1
- {danielutils-0.9.74/danielutils/threads → danielutils-0.9.77/danielutils/abstractions/multiprogramming}/worker_pool.py +1 -1
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/abstractions}/repl.py +1 -2
- danielutils-0.9.77/danielutils/better_builtins/__init__.py +3 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/frange.py +55 -59
- danielutils-0.9.77/danielutils/data_structures/graph/__init__.py +4 -0
- danielutils-0.9.77/danielutils/data_structures/graph/binary_node.py +71 -0
- danielutils-0.9.77/danielutils/data_structures/graph/graph.py +192 -0
- danielutils-0.9.77/danielutils/data_structures/graph/multinode.py +101 -0
- danielutils-0.9.77/danielutils/data_structures/graph/node.py +60 -0
- danielutils-0.9.77/danielutils/data_structures/heap/__init__.py +3 -0
- danielutils-0.9.77/danielutils/data_structures/heap/heap.py +95 -0
- danielutils-0.9.77/danielutils/data_structures/heap/max_heap.py +18 -0
- danielutils-0.9.77/danielutils/data_structures/heap/min_heap.py +18 -0
- danielutils-0.9.77/danielutils/data_structures/queue/__init__.py +3 -0
- danielutils-0.9.77/danielutils/data_structures/queue/atomic_queue.py +15 -0
- danielutils-0.9.77/danielutils/data_structures/queue/priority_queue.py +110 -0
- danielutils-0.9.77/danielutils/data_structures/queue/queue.py +72 -0
- danielutils-0.9.77/danielutils/data_structures/trees/__init__.py +2 -0
- danielutils-0.9.77/danielutils/data_structures/trees/binary_syntax_tree.py +84 -0
- danielutils-0.9.77/danielutils/data_structures/trees/binary_tree.py +62 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/__init__.py +1 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/atomic.py +4 -6
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/attach.py +4 -5
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/delay_call.py +4 -5
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/deprecate.py +7 -5
- danielutils-0.9.77/danielutils/decorators/final.py +37 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/limit_recursion.py +6 -8
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/memo.py +3 -7
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/overload.py +1 -6
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/partially_implemented.py +3 -6
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/processify.py +1 -2
- danielutils-0.9.77/danielutils/decorators/singleton.py +24 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/threadify.py +3 -5
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/timeout.py +1 -5
- danielutils-0.9.77/danielutils/decorators/total_ordering.py +82 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/validate.py +89 -90
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/__init__.py +3 -0
- danielutils-0.9.77/danielutils/functions/flatten.py +28 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/isoftype.py +33 -11
- danielutils-0.9.74/danielutils/loops.py → danielutils-0.9.77/danielutils/functions/multiloop.py +1 -24
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/generators/join_generators.py +1 -1
- {danielutils-0.9.74/danielutils/math → danielutils-0.9.77/danielutils/math_}/__init__.py +1 -1
- {danielutils-0.9.74/danielutils/math → danielutils-0.9.77/danielutils/math_}/math_print.py +1 -1
- {danielutils-0.9.74/danielutils/math → danielutils-0.9.77/danielutils/math_}/math_symbols.py +1 -1
- danielutils-0.9.77/danielutils/math_/polynomial/__init__.py +1 -0
- danielutils-0.9.77/danielutils/math_/polynomial/polinomial.py +33 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/metaclasses/instance_cache_meta.py +1 -1
- danielutils-0.9.74/danielutils/metaclasses/Interface.py → danielutils-0.9.77/danielutils/metaclasses/interface.py +1 -1
- danielutils-0.9.77/danielutils/mock_/__init__.py +2 -0
- danielutils-0.9.77/danielutils/mock_/mock_database.py +72 -0
- danielutils-0.9.77/danielutils/mock_/mock_module.py +18 -0
- danielutils-0.9.74/danielutils/d_print.py → danielutils-0.9.77/danielutils/print_.py +1 -1
- danielutils-0.9.77/danielutils/protocols/__init__.py +2 -0
- danielutils-0.9.77/danielutils/protocols/dictable.py +20 -0
- danielutils-0.9.77/danielutils/protocols/evaluable.py +13 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/reflection/__init__.py +6 -8
- danielutils-0.9.77/danielutils/reflection/class_/__init__.py +1 -0
- danielutils-0.9.77/danielutils/reflection/class_/class_reflection.py +164 -0
- danielutils-0.9.77/danielutils/reflection/file/__init__.py +1 -0
- danielutils-0.9.77/danielutils/reflection/file/file_reflection.py +58 -0
- danielutils-0.9.77/danielutils/reflection/function/__init__.py +1 -0
- {danielutils-0.9.74/danielutils/reflection → danielutils-0.9.77/danielutils/reflection/function}/function_reflections.py +2 -3
- danielutils-0.9.77/danielutils/reflection/interpreter/__init__.py +7 -0
- danielutils-0.9.77/danielutils/reflection/interpreter/callstack.py +40 -0
- {danielutils-0.9.74/danielutils/reflection → danielutils-0.9.77/danielutils/reflection/interpreter}/get_traceback.py +1 -1
- danielutils-0.9.77/danielutils/reflection/interpreter/packages.py +33 -0
- danielutils-0.9.77/danielutils/reflection/interpreter/python_version.py +26 -0
- danielutils-0.9.77/danielutils/reflection/interpreter/tracer.py +175 -0
- danielutils-0.9.77/danielutils/reflection/module/__init__.py +2 -0
- danielutils-0.9.77/danielutils/reflection/module/package_reflection.py +153 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/time.py +1 -5
- danielutils-0.9.74/danielutils/my_tqdm.py → danielutils-0.9.77/danielutils/tqdm_.py +1 -1
- danielutils-0.9.77/danielutils/university/oop/__init__.py +1 -0
- danielutils-0.9.77/danielutils/university/oop/observer.py +31 -0
- danielutils-0.9.77/danielutils/university/oop/strategy.py +9 -0
- danielutils-0.9.77/danielutils/university/probability/__init__.py +7 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/__init__.py +3 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/conditional_variable.py +110 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/__init__.py +7 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/bernoulli.py +38 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/binomial.py +40 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/conditional_from_discrete_probability_func.py +36 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/discrete.py +42 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/geometric.py +47 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/poisson.py +32 -0
- danielutils-0.9.77/danielutils/university/probability/conditional_variable/discrete/uniform.py +33 -0
- danielutils-0.9.77/danielutils/university/probability/distributions.py +35 -0
- danielutils-0.9.77/danielutils/university/probability/expressions/__init__.py +2 -0
- danielutils-0.9.77/danielutils/university/probability/expressions/accumulation_expression.py +185 -0
- danielutils-0.9.77/danielutils/university/probability/expressions/probability_expression.py +110 -0
- danielutils-0.9.77/danielutils/university/probability/funcs/__init__.py +4 -0
- danielutils-0.9.77/danielutils/university/probability/funcs/covariance.py +12 -0
- danielutils-0.9.77/danielutils/university/probability/funcs/expected_value.py +39 -0
- danielutils-0.9.77/danielutils/university/probability/funcs/probability_function.py +14 -0
- danielutils-0.9.77/danielutils/university/probability/funcs/variance.py +17 -0
- danielutils-0.9.77/danielutils/university/probability/operator.py +79 -0
- danielutils-0.9.77/danielutils/university/probability/protocols.py +32 -0
- danielutils-0.9.77/danielutils/university/probability/supp.py +100 -0
- danielutils-0.9.77/danielutils/university/probability/transformation.py +40 -0
- danielutils-0.9.77/danielutils/versioned_imports.py +21 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils.egg-info/PKG-INFO +6 -3
- danielutils-0.9.77/danielutils.egg-info/SOURCES.txt +180 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/pyproject.toml +3 -3
- danielutils-0.9.74/danielutils/classes/Tree.py +0 -0
- danielutils-0.9.74/danielutils/classes/__init__.py +0 -6
- danielutils-0.9.74/danielutils/classes/sorted_builtins/sset.py +0 -6
- danielutils-0.9.74/danielutils/reflection/class_reflection.py +0 -41
- danielutils-0.9.74/danielutils/reflection/file_reflection.py +0 -44
- danielutils-0.9.74/danielutils.egg-info/SOURCES.txt +0 -118
- {danielutils-0.9.74 → danielutils-0.9.77}/LICENSE +0 -0
- /danielutils-0.9.74/danielutils/multi_x.py → /danielutils-0.9.77/danielutils/abstractions/multiprogramming/multi_id.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/aliases.py +0 -0
- /danielutils-0.9.74/danielutils/classes/Counter.py → /danielutils-0.9.77/danielutils/better_builtins/counter.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/__init__.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/factory.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/tdict.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/tlist.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/tset.py +0 -0
- {danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/typed_builtins/ttuple.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/colors.py +0 -0
- /danielutils-0.9.74/danielutils/classes/Convenience.py → /danielutils-0.9.77/danielutils/convenience.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/conversions/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/conversions/main_conversions.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/conversions/specialized_conversions/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/conversions/specialized_conversions/to_hex.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/conversions/specialized_conversions/to_int.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/data_structures/__init__.py +0 -0
- /danielutils-0.9.74/danielutils/data_structures/Comparer.py → /danielutils-0.9.77/danielutils/data_structures/comparer.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/data_structures/default_dict.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/data_structures/functions.py +0 -0
- /danielutils-0.9.74/danielutils/data_structures/Stack.py → /danielutils-0.9.77/danielutils/data_structures/stack.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/date.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/date_time.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/chain_decorators.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/decorate_conditionally.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/decorators/property.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/exceptions.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/areoneof.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/check_foreach.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/isoneof.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/powerset.py +0 -0
- /danielutils-0.9.74/danielutils/relations.py → /danielutils-0.9.77/danielutils/functions/subseteq.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/functions/types_subseteq.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/generators/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/generators/conditional_generator.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/generators/generator_from_stream.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/internet.py +0 -0
- /danielutils-0.9.74/danielutils/files_and_folders.py → /danielutils-0.9.77/danielutils/io_.py +0 -0
- {danielutils-0.9.74/danielutils/math → danielutils-0.9.77/danielutils/math_}/constants.py +0 -0
- {danielutils-0.9.74/danielutils/math → danielutils-0.9.77/danielutils/math_}/functions.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/metaclasses/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/metaclasses/atomic_class_meta.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/metaclasses/implicit_data_deleter_meta.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/metaclasses/overload_meta.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/path.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/py.typed +0 -0
- /danielutils-0.9.74/danielutils/reflection/system_reflections.py → /danielutils-0.9.77/danielutils/reflection/interpreter/os_.py +0 -0
- {danielutils-0.9.74/danielutils → danielutils-0.9.77/danielutils/reflection/interpreter}/signals.py +0 -0
- {danielutils-0.9.74/danielutils/reflection → danielutils-0.9.77/danielutils/reflection/module}/module_reflections.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/snippets/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/snippets/try_get.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/independent.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/windows/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/windows/utils/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/windows/utils/filetime.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/windows/win32_ctime.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/system/windows/windows.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/text.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/university/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/university/databases/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils/university/databases/all.py +0 -0
- {danielutils-0.9.74/danielutils/classes/sorted_builtins → danielutils-0.9.77/danielutils/university/probability/conditional_variable/continuous}/__init__.py +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils.egg-info/dependency_links.txt +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/danielutils.egg-info/top_level.txt +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/setup.cfg +0 -0
- {danielutils-0.9.74 → danielutils-0.9.77}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include danielutils *.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: danielutils
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.77
|
|
4
4
|
Summary: A python utils library for things I find useful
|
|
5
5
|
Author-email: danielnachumdev <danielnachumdev@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -26,7 +26,7 @@ License: MIT License
|
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
Project-URL: Homepage, https://github.com/danielnachumdev/danielutils
|
|
28
28
|
Project-URL: Bug Tracker, https://github.com/danielnachumdev/danielutils/issues
|
|
29
|
-
Keywords: functions,decorators,methods,
|
|
29
|
+
Keywords: functions,decorators,methods,better_builtins,metaclasses
|
|
30
30
|
Classifier: Development Status :: 3 - Alpha
|
|
31
31
|
Classifier: Intended Audience :: Developers
|
|
32
32
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -41,12 +41,15 @@ License-File: LICENSE
|
|
|
41
41
|
[](https://www.python.org/downloads/release/python-31011/)
|
|
42
42
|
[](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml)
|
|
43
43
|
[](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql)
|
|
44
|
-
# danielutils v=0.9.
|
|
44
|
+
# danielutils v=0.9.75
|
|
45
45
|
A utils library for things that I find useful for my coding workflow.\
|
|
46
46
|
Feel free to use and / or contribute / improve my code :)
|
|
47
47
|
|
|
48
48
|
THIS PACKAGE IS IN DEVELOPMENT AND SUBJECT TO CHANGE, USE AT YOUR OWN RISK!
|
|
49
49
|
|
|
50
|
+
**Tested python versions**: `3.8.0`*, `3.9.0`, `3.10.13`
|
|
51
|
+
|
|
52
|
+
Versions marked with * are partially working
|
|
50
53
|
# Showcase
|
|
51
54
|
In [this](./READMES/) folder you can check out some more in depth showcase of some of the topics I have covered in this package
|
|
52
55
|
|
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
[](https://www.python.org/downloads/release/python-31011/)
|
|
5
5
|
[](https://github.com/danielnachumdev/danielutils/actions/workflows/gitleaks.yml)
|
|
6
6
|
[](https://github.com/danielnachumdev/danielutils/actions/workflows/github-code-scanning/codeql)
|
|
7
|
-
# danielutils v=0.9.
|
|
7
|
+
# danielutils v=0.9.75
|
|
8
8
|
A utils library for things that I find useful for my coding workflow.\
|
|
9
9
|
Feel free to use and / or contribute / improve my code :)
|
|
10
10
|
|
|
11
11
|
THIS PACKAGE IS IN DEVELOPMENT AND SUBJECT TO CHANGE, USE AT YOUR OWN RISK!
|
|
12
12
|
|
|
13
|
+
**Tested python versions**: `3.8.0`*, `3.9.0`, `3.10.13`
|
|
14
|
+
|
|
15
|
+
Versions marked with * are partially working
|
|
13
16
|
# Showcase
|
|
14
17
|
In [this](./READMES/) folder you can check out some more in depth showcase of some of the topics I have covered in this package
|
|
15
18
|
|
|
@@ -6,14 +6,11 @@
|
|
|
6
6
|
# =================================================================
|
|
7
7
|
from .path import *
|
|
8
8
|
from .date_time import *
|
|
9
|
-
from .multi_x import *
|
|
10
|
-
from .loops import *
|
|
11
|
-
from .signals import *
|
|
12
9
|
from .aliases import *
|
|
13
10
|
from .exceptions import PrintCatchOne
|
|
14
11
|
from .snippets import *
|
|
15
12
|
from .abstractions import *
|
|
16
|
-
from .
|
|
13
|
+
from .protocols import *
|
|
17
14
|
# =================================================================
|
|
18
15
|
# ========================= ORDER MATTERS =========================
|
|
19
16
|
# =================================================================
|
|
@@ -22,25 +19,24 @@ from .reflection import *
|
|
|
22
19
|
from .decorators import *
|
|
23
20
|
|
|
24
21
|
# ========== NEEDS REFLECTION ==========
|
|
25
|
-
from .
|
|
26
|
-
from .my_tqdm import *
|
|
22
|
+
from .tqdm_ import *
|
|
27
23
|
# ========== NEEDS DECORATORS ==========
|
|
28
24
|
from .colors import *
|
|
29
25
|
# ========== NEEDS BOTH ==========
|
|
30
26
|
|
|
31
27
|
from .functions import *
|
|
32
|
-
from .
|
|
28
|
+
from .io_ import *
|
|
33
29
|
from .system import *
|
|
34
30
|
from .text import *
|
|
35
31
|
from .conversions import *
|
|
36
|
-
from .
|
|
32
|
+
from .better_builtins import *
|
|
37
33
|
from .time import *
|
|
38
34
|
from .date import *
|
|
39
35
|
from .data_structures import *
|
|
40
|
-
from .
|
|
36
|
+
from .math_ import *
|
|
41
37
|
from .system import *
|
|
42
|
-
from .
|
|
38
|
+
from .print_ import *
|
|
43
39
|
from .metaclasses import *
|
|
44
40
|
from .generators import *
|
|
45
41
|
from .university import *
|
|
46
|
-
from .
|
|
42
|
+
from .mock_ import *
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from typing import Any, TypeVar, Optional
|
|
2
|
+
|
|
3
|
+
from .database import Database
|
|
4
|
+
|
|
5
|
+
K = TypeVar('K')
|
|
6
|
+
V = TypeVar('V')
|
|
7
|
+
|
|
8
|
+
class CachedDatabase(Database[K, V]):
|
|
9
|
+
"""
|
|
10
|
+
A database that is composed of two types of databases.
|
|
11
|
+
Args:
|
|
12
|
+
primary (Database): is intended to be the "real" database which is usually slower than the `cache`
|
|
13
|
+
cache (Database): is intended to be a cache layer over `primary` which will be faster when reading
|
|
14
|
+
*
|
|
15
|
+
notify_primary (bool): if a single Database instance is as `primary` for multiple CachedDatabase and the
|
|
16
|
+
current CachedDatabase instance 'set' method is used, it will also update the cache on different
|
|
17
|
+
CachedDatabase instances. Defaults to False
|
|
18
|
+
notify_cache (bool): same as `notify_primary` but will update other primaries on different
|
|
19
|
+
CachedDatabase instances
|
|
20
|
+
Returns:
|
|
21
|
+
None
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def _on_notify(self, updater: 'Database', obj: Any) -> None:
|
|
25
|
+
key, value = obj
|
|
26
|
+
if self._cache is not updater:
|
|
27
|
+
if not self._cache == updater:
|
|
28
|
+
self._cache.set(key, value)
|
|
29
|
+
|
|
30
|
+
if self._primary is not updater:
|
|
31
|
+
if not self._primary == updater:
|
|
32
|
+
self._primary.set(key, value)
|
|
33
|
+
|
|
34
|
+
def __init__(self, primary: Database, cache: Database, *, notify_primary: bool = False, notify_cache: bool = False):
|
|
35
|
+
super().__init__()
|
|
36
|
+
primary._register_subscriber(self)
|
|
37
|
+
cache._register_subscriber(self)
|
|
38
|
+
self._primary = primary
|
|
39
|
+
self._cache = cache
|
|
40
|
+
self._notify_primary = notify_primary
|
|
41
|
+
self._notify_cache = notify_cache
|
|
42
|
+
|
|
43
|
+
def get(self, key: K, default: Any = Database.DEFAULT) -> Optional[V]:
|
|
44
|
+
res = self._cache.get(key, default)
|
|
45
|
+
if res is not default:
|
|
46
|
+
return res
|
|
47
|
+
res = self._primary.get(key, default)
|
|
48
|
+
if res is not default:
|
|
49
|
+
self._cache.set(key, res)
|
|
50
|
+
return res
|
|
51
|
+
|
|
52
|
+
def set(self, key: K, value: V) -> None:
|
|
53
|
+
self._cache.set(key, value)
|
|
54
|
+
if self._notify_cache:
|
|
55
|
+
self._cache._notify_subscribers((key, value)) # pylint: disable=protected-access
|
|
56
|
+
self._primary.set(key, value)
|
|
57
|
+
if self._notify_primary:
|
|
58
|
+
self._primary._notify_subscribers((key, value)) # pylint: disable=protected-access
|
|
59
|
+
|
|
60
|
+
def delete(self, key: K) -> None:
|
|
61
|
+
self._cache.delete(key)
|
|
62
|
+
self._primary.delete(key)
|
|
63
|
+
|
|
64
|
+
def contains(self, key: K) -> bool:
|
|
65
|
+
if self._cache.contains(key):
|
|
66
|
+
return True
|
|
67
|
+
if (res := self.get(key)) is not Database.DEFAULT:
|
|
68
|
+
self._cache.set(key, res)
|
|
69
|
+
return True
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = [
|
|
74
|
+
"CachedDatabase"
|
|
75
|
+
]
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, TypeVar, Generic, Optional
|
|
3
|
+
|
|
4
|
+
K = TypeVar('K')
|
|
5
|
+
V = TypeVar('V')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Database(ABC, Generic[K, V]):
|
|
9
|
+
"""
|
|
10
|
+
Abstract base class for database objects.
|
|
11
|
+
"""
|
|
12
|
+
DEFAULT = None
|
|
13
|
+
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self._subscribers: set[Database] = set()
|
|
16
|
+
|
|
17
|
+
def _register_subscriber(self, subscriber: 'Database') -> None:
|
|
18
|
+
self._subscribers.add(subscriber)
|
|
19
|
+
|
|
20
|
+
def _notify_subscribers(self, obj: Any) -> None:
|
|
21
|
+
for subscriber in self._subscribers:
|
|
22
|
+
subscriber._notify(self, obj) # pylint: disable=protected-access
|
|
23
|
+
|
|
24
|
+
def _notify(self, updater: 'Database', obj: Any) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Notify all subscribers of an object.
|
|
27
|
+
Args:
|
|
28
|
+
updater: the object calling this method.
|
|
29
|
+
obj: the event to notify.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
None
|
|
33
|
+
"""
|
|
34
|
+
self._on_notify(updater, obj)
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def _on_notify(self, updater: 'Database', obj: Any) -> None:
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get(self, key: K, default: Any = DEFAULT) -> Optional[V]:
|
|
42
|
+
"""
|
|
43
|
+
Get a value from the database by key.
|
|
44
|
+
Args:
|
|
45
|
+
key (K): The key to get the value from.:
|
|
46
|
+
default (Any): The default value to return if the key is not found. Defaults to Database.DEFAULT.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Optional[V]
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def set(self, key: K, value: V) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Set a value in the database.
|
|
56
|
+
Args:
|
|
57
|
+
key (K): The key to set.
|
|
58
|
+
value (V): The value to set.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
None
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def delete(self, key: K) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Delete an item from the database.
|
|
68
|
+
Args:
|
|
69
|
+
key (K): The key to delete.:
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
None
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def contains(self, key: K) -> bool:
|
|
77
|
+
"""
|
|
78
|
+
Check if a key is contained in this database.
|
|
79
|
+
Args:
|
|
80
|
+
key (K): Key to be checked.:
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
bool
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __getitem__(self, key: K) -> V:
|
|
87
|
+
res = self.get(key)
|
|
88
|
+
if res is Database.DEFAULT:
|
|
89
|
+
raise KeyError(key)
|
|
90
|
+
return res
|
|
91
|
+
|
|
92
|
+
def __setitem__(self, key: K, value: V) -> None:
|
|
93
|
+
self.set(key, value)
|
|
94
|
+
|
|
95
|
+
def __delitem__(self, key: K) -> None:
|
|
96
|
+
self.delete(key)
|
|
97
|
+
|
|
98
|
+
def __contains__(self, key: K) -> bool:
|
|
99
|
+
return self.contains(key)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
__all__ = [
|
|
103
|
+
"Database",
|
|
104
|
+
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Any, Optional, TypeVar
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
import redis
|
|
5
|
+
except ImportError:
|
|
6
|
+
from ...mock_ import MockImportObject
|
|
7
|
+
|
|
8
|
+
redis = MockImportObject("`redis` is not installed")
|
|
9
|
+
from .database import Database
|
|
10
|
+
|
|
11
|
+
K = TypeVar('K')
|
|
12
|
+
V = TypeVar('V')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RedisDatabase(Database[K, V]):
|
|
16
|
+
"""
|
|
17
|
+
An implementation of the `Database` interface using Redis.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self) -> None:
|
|
21
|
+
super().__init__()
|
|
22
|
+
self._db = redis.StrictRedis(host='localhost', port=6379, db=0)
|
|
23
|
+
|
|
24
|
+
def _on_notify(self, updater: 'Database', obj: Any) -> None:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
def get(self, key: K, default: Any = Database.DEFAULT) -> Optional[V]:
|
|
28
|
+
if key not in self:
|
|
29
|
+
return default
|
|
30
|
+
return self._db.get(key)
|
|
31
|
+
|
|
32
|
+
def set(self, key: K, value: V) -> None:
|
|
33
|
+
self._db.set(key, value)
|
|
34
|
+
|
|
35
|
+
def delete(self, key: K) -> None:
|
|
36
|
+
self._db.delete(key)
|
|
37
|
+
|
|
38
|
+
def contains(self, key: K) -> bool:
|
|
39
|
+
return self._db.exists(key)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"RedisDatabase"
|
|
44
|
+
]
|
|
@@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
|
|
|
3
3
|
from typing import Optional, Any,Tuple as t_tuple
|
|
4
4
|
from logging import error
|
|
5
5
|
import danielutils # this is explicitly this way to prevent circular import
|
|
6
|
-
from
|
|
6
|
+
from ...reflection import get_python_version
|
|
7
7
|
if get_python_version() >= (3, 9):
|
|
8
8
|
from builtins import tuple as t_tuple # type:ignore
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@ from queue import Queue
|
|
|
2
2
|
from typing import Optional, Any, Type as t_type, Tuple as t_tuple, List as t_list
|
|
3
3
|
from threading import Semaphore
|
|
4
4
|
from .worker import Worker
|
|
5
|
-
from
|
|
5
|
+
from ...reflection import get_python_version
|
|
6
6
|
|
|
7
7
|
if get_python_version() >= (3, 9):
|
|
8
8
|
from builtins import type as t_type, tuple as t_tuple, list as t_list # type:ignore
|
{danielutils-0.9.74/danielutils/classes → danielutils-0.9.77/danielutils/better_builtins}/frange.py
RENAMED
|
@@ -12,6 +12,37 @@ class frange(Sequence[float]):
|
|
|
12
12
|
"""will "downcast" `range` to `frange` correctly"""
|
|
13
13
|
return frange(r.start, r.stop, r.step)
|
|
14
14
|
|
|
15
|
+
@staticmethod
|
|
16
|
+
def _is_int(n: Union[int, float]) -> bool:
|
|
17
|
+
if isinstance(n, int):
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
return n.is_integer()
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def _lcm_float(a: float, b: float) -> float:
|
|
24
|
+
prec = min(5, max(decimal.getcontext().prec, 10))
|
|
25
|
+
a = round(a, prec)
|
|
26
|
+
b = round(b, prec)
|
|
27
|
+
return math.lcm(int(a * 10 ** prec), int(b * 10 ** prec)) / 10 ** prec
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def _find_min_step(s1: float, s2: float) -> float:
|
|
31
|
+
"""
|
|
32
|
+
returns the minimum LCM for two step values
|
|
33
|
+
Args:
|
|
34
|
+
s1 (float): first step value:
|
|
35
|
+
s2 (float): second step value:
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
float: minimum LCM
|
|
39
|
+
"""
|
|
40
|
+
M = max(s1, s2)
|
|
41
|
+
m = min(s1, s2)
|
|
42
|
+
if float.is_integer(M / m):
|
|
43
|
+
return M
|
|
44
|
+
return frange._lcm_float(s1, s2)
|
|
45
|
+
|
|
15
46
|
def __init__(self, start: float, stop: Optional[float] = None,
|
|
16
47
|
step: float = 1, round_method: Callable[[float], float] = lambda f: round(f, 3)):
|
|
17
48
|
if stop is None:
|
|
@@ -21,27 +52,6 @@ class frange(Sequence[float]):
|
|
|
21
52
|
self.stop = stop
|
|
22
53
|
self.step = step
|
|
23
54
|
self.method = round_method
|
|
24
|
-
self._is_finite = len(self) != float("inf")
|
|
25
|
-
|
|
26
|
-
@property
|
|
27
|
-
def is_finite(self) -> bool:
|
|
28
|
-
"""
|
|
29
|
-
Returns `True` if the range is finite
|
|
30
|
-
inverse if `is_infinite`
|
|
31
|
-
Returns:
|
|
32
|
-
bool
|
|
33
|
-
"""
|
|
34
|
-
return self._is_finite
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def is_infinite(self) -> bool:
|
|
38
|
-
"""
|
|
39
|
-
Returns `True` if the range is infinite
|
|
40
|
-
inverse if `is_finite`
|
|
41
|
-
Returns:
|
|
42
|
-
bool
|
|
43
|
-
"""
|
|
44
|
-
return not self.is_finite
|
|
45
55
|
|
|
46
56
|
@overload
|
|
47
57
|
def __getitem__(self, index: int) -> float:
|
|
@@ -78,9 +88,9 @@ class frange(Sequence[float]):
|
|
|
78
88
|
return self.start == other.start and self.stop == other.stop and self.step == other.step
|
|
79
89
|
|
|
80
90
|
def __iter__(self) -> Iterator[float]:
|
|
81
|
-
if self.stop < self.start:
|
|
91
|
+
if self.stop < self.start and self.step > 0:
|
|
82
92
|
return
|
|
83
|
-
if self.start > self.stop:
|
|
93
|
+
if self.start > self.stop and self.step > 0:
|
|
84
94
|
return
|
|
85
95
|
if abs(self.stop - self.start) < abs(self.step):
|
|
86
96
|
return
|
|
@@ -90,14 +100,14 @@ class frange(Sequence[float]):
|
|
|
90
100
|
return
|
|
91
101
|
|
|
92
102
|
cur = self.start
|
|
93
|
-
while cur < self.stop:
|
|
103
|
+
while (cur < self.stop and self.step > 0) or (cur > self.stop and self.step < 0):
|
|
94
104
|
yield self.method(cur)
|
|
95
105
|
cur += self.step
|
|
96
106
|
|
|
97
107
|
def __len__(self) -> int:
|
|
98
108
|
if self.stop in {float("inf"), -float("inf")}:
|
|
99
109
|
return float("inf")
|
|
100
|
-
return int((self.stop - self.start) // self.step)
|
|
110
|
+
return int(abs(self.stop - self.start) // abs(self.step))
|
|
101
111
|
|
|
102
112
|
def __str__(self) -> str:
|
|
103
113
|
return repr(self)
|
|
@@ -105,13 +115,6 @@ class frange(Sequence[float]):
|
|
|
105
115
|
def __repr__(self):
|
|
106
116
|
return f"{self.__class__.__name__}({self.start}, {self.stop}, {self.step})"
|
|
107
117
|
|
|
108
|
-
@staticmethod
|
|
109
|
-
def _is_int(n: Union[int, float]) -> bool:
|
|
110
|
-
if isinstance(n, int):
|
|
111
|
-
return True
|
|
112
|
-
|
|
113
|
-
return n.is_integer()
|
|
114
|
-
|
|
115
118
|
def __contains__(self, item):
|
|
116
119
|
if item < self.start:
|
|
117
120
|
return False
|
|
@@ -124,40 +127,33 @@ class frange(Sequence[float]):
|
|
|
124
127
|
|
|
125
128
|
return item / self.step - item // self.step == 0
|
|
126
129
|
|
|
127
|
-
|
|
130
|
+
@property
|
|
131
|
+
def is_finite(self) -> bool:
|
|
128
132
|
"""
|
|
129
|
-
|
|
133
|
+
Returns `True` if the range is finite
|
|
134
|
+
inverse if `is_infinite`
|
|
130
135
|
Returns:
|
|
131
|
-
|
|
136
|
+
bool
|
|
132
137
|
"""
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
# def _normalize_with(self, other: 'frange') -> 'frange':
|
|
136
|
-
# return frange(self.start / (self.step * other.step), self.stop / (self.step * other.step), 1)
|
|
137
|
-
|
|
138
|
-
@staticmethod
|
|
139
|
-
def _lcm_float(a: float, b: float) -> float:
|
|
140
|
-
prec = min(5, max(decimal.getcontext().prec, 10))
|
|
141
|
-
a = round(a, prec)
|
|
142
|
-
b = round(b, prec)
|
|
143
|
-
return math.lcm(int(a * 10 ** prec), int(b * 10 ** prec)) / 10 ** prec
|
|
138
|
+
return len(self) != float("inf")
|
|
144
139
|
|
|
145
|
-
@
|
|
146
|
-
def
|
|
140
|
+
@property
|
|
141
|
+
def is_infinite(self) -> bool:
|
|
147
142
|
"""
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
143
|
+
Returns `True` if the range is infinite
|
|
144
|
+
inverse if `is_finite`
|
|
145
|
+
Returns:
|
|
146
|
+
bool
|
|
147
|
+
"""
|
|
148
|
+
return not self.is_finite
|
|
152
149
|
|
|
150
|
+
def normalize(self) -> 'frange':
|
|
151
|
+
"""
|
|
152
|
+
will normalize the `frange` object
|
|
153
153
|
Returns:
|
|
154
|
-
|
|
154
|
+
frange
|
|
155
155
|
"""
|
|
156
|
-
|
|
157
|
-
m = min(s1, s2)
|
|
158
|
-
if float.is_integer(M / m):
|
|
159
|
-
return M
|
|
160
|
-
return frange._lcm_float(s1, s2)
|
|
156
|
+
return frange(self.start / self.step, self.stop / self.step, 1)
|
|
161
157
|
|
|
162
158
|
def intersect(self, other: 'frange') -> 'frange':
|
|
163
159
|
if not isinstance(other, frange):
|
|
@@ -214,7 +210,7 @@ class brange(frange):
|
|
|
214
210
|
def __iter__(self):
|
|
215
211
|
itr = super().__iter__()
|
|
216
212
|
try:
|
|
217
|
-
from
|
|
213
|
+
from tqdm_ import tqdm # type:ignore # pylint: disable=import-error
|
|
218
214
|
return iter(tqdm(itr, desc=f"{self}", total=len(self)))
|
|
219
215
|
except:
|
|
220
216
|
return itr
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional, TypeVar
|
|
3
|
+
from .multinode import MultiNode
|
|
4
|
+
from ...metaclasses import ImplicitDataDeleterMeta
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BinaryNode(MultiNode[T], metaclass=ImplicitDataDeleterMeta):
|
|
10
|
+
"""A 'classic' node class with only one child
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, data: T, l: Optional[BinaryNode[T]] = None,
|
|
14
|
+
r: Optional[BinaryNode[T]] = None): # pylint: disable=redefined-builtin
|
|
15
|
+
# intentionally can be None
|
|
16
|
+
super().__init__(data, [l, r]) # type:ignore
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return MultiNode.__str__(self).replace(
|
|
20
|
+
self.__class__.__mro__[1].__name__,
|
|
21
|
+
self.__class__.__name__
|
|
22
|
+
).replace("[", "").replace("]", "")
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
return str(self)
|
|
26
|
+
|
|
27
|
+
def __reversed__(self) -> 'BinaryNode[T]':
|
|
28
|
+
return self.reverse()
|
|
29
|
+
|
|
30
|
+
def __eq__(self, other):
|
|
31
|
+
return MultiNode.__eq__(self, other)
|
|
32
|
+
|
|
33
|
+
def __iter__(self):
|
|
34
|
+
return MultiNode.__iter__(self)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def left(self) -> "BinaryNode[T]":
|
|
38
|
+
"""return the next node after self
|
|
39
|
+
"""
|
|
40
|
+
return self._children[0] # type:ignore
|
|
41
|
+
|
|
42
|
+
@left.setter
|
|
43
|
+
def left(self, value: "BinaryNode[T]") -> None:
|
|
44
|
+
self._children[0] = value
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def right(self) -> "BinaryNode[T]":
|
|
48
|
+
"""return the next node after self
|
|
49
|
+
"""
|
|
50
|
+
return self._children[1] # type:ignore
|
|
51
|
+
|
|
52
|
+
@right.setter
|
|
53
|
+
def right(self, value: "BinaryNode[T]") -> None:
|
|
54
|
+
self._children[1] = value
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def is_leaf(self) -> bool:
|
|
58
|
+
return self.left is None and self.right is None
|
|
59
|
+
|
|
60
|
+
def reverse(self) -> 'BinaryNode[T]':
|
|
61
|
+
new_left = self.right.reverse() if self.right is not None else None
|
|
62
|
+
new_right = self.left.reverse() if self.left is not None else None
|
|
63
|
+
return BinaryNode(self.data, new_left, new_right)
|
|
64
|
+
|
|
65
|
+
def depth(self) -> int:
|
|
66
|
+
return MultiNode.depth(self)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
"BinaryNode"
|
|
71
|
+
]
|