winipedia-utils 0.1.63__py3-none-any.whl → 0.2.0__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.

Potentially problematic release.


This version of winipedia-utils might be problematic. Click here for more details.

Files changed (91) hide show
  1. winipedia_utils/concurrent/concurrent.py +245 -242
  2. winipedia_utils/concurrent/multiprocessing.py +130 -115
  3. winipedia_utils/concurrent/multithreading.py +93 -93
  4. winipedia_utils/consts.py +23 -23
  5. winipedia_utils/data/__init__.py +1 -1
  6. winipedia_utils/data/dataframe/__init__.py +1 -0
  7. winipedia_utils/data/dataframe/cleaning.py +378 -0
  8. winipedia_utils/data/structures/__init__.py +1 -0
  9. winipedia_utils/data/structures/dicts.py +16 -0
  10. winipedia_utils/django/__init__.py +24 -24
  11. winipedia_utils/django/bulk.py +538 -538
  12. winipedia_utils/django/command.py +334 -334
  13. winipedia_utils/django/database.py +289 -289
  14. winipedia_utils/git/__init__.py +1 -1
  15. winipedia_utils/git/gitignore/__init__.py +1 -1
  16. winipedia_utils/git/gitignore/gitignore.py +136 -136
  17. winipedia_utils/git/pre_commit/__init__.py +1 -1
  18. winipedia_utils/git/pre_commit/config.py +70 -70
  19. winipedia_utils/git/pre_commit/hooks.py +109 -109
  20. winipedia_utils/git/pre_commit/run_hooks.py +49 -49
  21. winipedia_utils/iterating/__init__.py +1 -1
  22. winipedia_utils/iterating/iterate.py +29 -29
  23. winipedia_utils/logging/ansi.py +6 -6
  24. winipedia_utils/logging/config.py +64 -64
  25. winipedia_utils/logging/logger.py +26 -26
  26. winipedia_utils/modules/class_.py +119 -119
  27. winipedia_utils/modules/function.py +101 -103
  28. winipedia_utils/modules/module.py +379 -379
  29. winipedia_utils/modules/package.py +390 -390
  30. winipedia_utils/oop/mixins/meta.py +333 -331
  31. winipedia_utils/oop/mixins/mixin.py +37 -37
  32. winipedia_utils/os/__init__.py +1 -1
  33. winipedia_utils/os/os.py +63 -63
  34. winipedia_utils/projects/__init__.py +1 -1
  35. winipedia_utils/projects/poetry/__init__.py +1 -1
  36. winipedia_utils/projects/poetry/config.py +91 -91
  37. winipedia_utils/projects/poetry/poetry.py +31 -31
  38. winipedia_utils/projects/project.py +48 -48
  39. winipedia_utils/pyside/__init__.py +1 -1
  40. winipedia_utils/pyside/core/__init__.py +1 -1
  41. winipedia_utils/pyside/core/py_qiodevice.py +476 -476
  42. winipedia_utils/pyside/ui/__init__.py +1 -1
  43. winipedia_utils/pyside/ui/base/__init__.py +1 -1
  44. winipedia_utils/pyside/ui/base/base.py +180 -180
  45. winipedia_utils/pyside/ui/pages/__init__.py +1 -1
  46. winipedia_utils/pyside/ui/pages/base/__init__.py +1 -1
  47. winipedia_utils/pyside/ui/pages/base/base.py +92 -92
  48. winipedia_utils/pyside/ui/pages/browser.py +26 -26
  49. winipedia_utils/pyside/ui/pages/player.py +85 -85
  50. winipedia_utils/pyside/ui/widgets/__init__.py +1 -1
  51. winipedia_utils/pyside/ui/widgets/browser.py +243 -243
  52. winipedia_utils/pyside/ui/widgets/clickable_widget.py +57 -57
  53. winipedia_utils/pyside/ui/widgets/media_player.py +430 -430
  54. winipedia_utils/pyside/ui/widgets/notification.py +78 -78
  55. winipedia_utils/pyside/ui/windows/__init__.py +1 -1
  56. winipedia_utils/pyside/ui/windows/base/__init__.py +1 -1
  57. winipedia_utils/pyside/ui/windows/base/base.py +49 -49
  58. winipedia_utils/resources/__init__.py +1 -1
  59. winipedia_utils/resources/svgs/__init__.py +1 -1
  60. winipedia_utils/resources/svgs/download_arrow.svg +2 -2
  61. winipedia_utils/resources/svgs/exit_fullscreen_icon.svg +5 -5
  62. winipedia_utils/resources/svgs/fullscreen_icon.svg +2 -2
  63. winipedia_utils/resources/svgs/menu_icon.svg +3 -3
  64. winipedia_utils/resources/svgs/pause_icon.svg +3 -3
  65. winipedia_utils/resources/svgs/play_icon.svg +16 -16
  66. winipedia_utils/resources/svgs/plus_icon.svg +23 -23
  67. winipedia_utils/resources/svgs/svg.py +15 -15
  68. winipedia_utils/security/__init__.py +1 -1
  69. winipedia_utils/security/cryptography.py +29 -29
  70. winipedia_utils/security/keyring.py +70 -70
  71. winipedia_utils/setup.py +47 -47
  72. winipedia_utils/testing/assertions.py +23 -23
  73. winipedia_utils/testing/convention.py +177 -177
  74. winipedia_utils/testing/create_tests.py +291 -291
  75. winipedia_utils/testing/fixtures.py +28 -28
  76. winipedia_utils/testing/tests/base/fixtures/__init__.py +1 -1
  77. winipedia_utils/testing/tests/base/fixtures/fixture.py +6 -6
  78. winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +33 -33
  79. winipedia_utils/testing/tests/base/fixtures/scopes/function.py +7 -7
  80. winipedia_utils/testing/tests/base/fixtures/scopes/module.py +31 -31
  81. winipedia_utils/testing/tests/base/fixtures/scopes/package.py +7 -7
  82. winipedia_utils/testing/tests/base/fixtures/scopes/session.py +312 -312
  83. winipedia_utils/testing/tests/base/utils/utils.py +82 -82
  84. winipedia_utils/testing/tests/conftest.py +32 -32
  85. winipedia_utils/text/string.py +126 -126
  86. {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info}/METADATA +5 -4
  87. winipedia_utils-0.2.0.dist-info/RECORD +103 -0
  88. {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info}/WHEEL +1 -1
  89. {winipedia_utils-0.1.63.dist-info → winipedia_utils-0.2.0.dist-info/licenses}/LICENSE +21 -21
  90. winipedia_utils/data/dataframe.py +0 -7
  91. winipedia_utils-0.1.63.dist-info/RECORD +0 -100
@@ -1,242 +1,245 @@
1
- """Concurrent processing utilities for parallel execution.
2
-
3
- This module provides functions for concurrent processing using both multiprocessing
4
- and multithreading approaches. It includes utilities for handling timeouts,
5
- managing process pools, and organizing parallel execution of functions.
6
-
7
- Returns:
8
- Various utility functions for concurrent processing.
9
-
10
- """
11
-
12
- import multiprocessing
13
- import os
14
- import threading
15
- from collections.abc import Callable, Generator, Iterable
16
- from concurrent.futures import ThreadPoolExecutor
17
- from copy import deepcopy
18
- from functools import partial
19
- from multiprocessing.pool import Pool
20
- from typing import Any, cast
21
-
22
- from tqdm import tqdm
23
-
24
- from winipedia_utils.concurrent.multithreading import imap_unordered
25
- from winipedia_utils.iterating.iterate import get_len_with_default
26
- from winipedia_utils.logging.logger import get_logger
27
-
28
- logger = get_logger(__name__)
29
-
30
-
31
- def get_order_and_func_result(
32
- func_order_args: tuple[Any, ...],
33
- ) -> tuple[int, Any]:
34
- """Process function for imap with arguments unpacking.
35
-
36
- Helper function that gives back a function that can be used with imap_unordered
37
- to execute a function with arguments unpacking.
38
-
39
- Args:
40
- func_order_args: Tuple containing the function to be executed,
41
- the order index, and the arguments for the function
42
-
43
- Returns:
44
- A tuple containing the order index and the result of the function execution
45
-
46
- """
47
- function, order, *args = func_order_args
48
- return order, function(*args)
49
-
50
-
51
- def generate_process_args(
52
- *,
53
- process_function: Callable[..., Any],
54
- process_args: Iterable[Iterable[Any]],
55
- process_args_static: Iterable[Any] | None = None,
56
- deepcopy_static_args: Iterable[Any] | None = None,
57
- ) -> Generator[tuple[Any, ...], None, None]:
58
- """Prepare arguments for multiprocessing or multithreading execution.
59
-
60
- Converts input arguments into a format suitable for parallel processing,
61
- organizing them for efficient unpacking during execution. The function:
62
- 1. Prepends process func and order indices to arguments
63
- 2. Handles static arguments (with optional deep copying)
64
- 3. Restructures arguments into tuples for unpacking
65
-
66
- Args:
67
- process_function: Function to be executed
68
- process_args: Iterable of argument lists for each parallel call
69
- process_args_static: Optional constant arguments to add to each call
70
- deepcopy_static_args: Optional constant arguments that should be deep-copied
71
-
72
- Returns:
73
- A Genrator that yields one args tuple for each function call
74
- First is the process function
75
- Second item in the tuple is the order index
76
- Second item in the tuple is the function
77
- Rest of the items are the arguments for the function
78
- The length of the generator
79
- """
80
- process_args_static = (
81
- () if process_args_static is None else tuple(process_args_static)
82
- )
83
- deepcopy_static_args = (
84
- () if deepcopy_static_args is None else tuple(deepcopy_static_args)
85
- )
86
- for order, process_arg in enumerate(process_args):
87
- yield (
88
- process_function,
89
- order,
90
- *process_arg,
91
- *process_args_static,
92
- *(
93
- deepcopy(deepcopy_static_arg)
94
- for deepcopy_static_arg in deepcopy_static_args
95
- ),
96
- )
97
-
98
-
99
- def get_multiprocess_results_with_tqdm(
100
- results: Iterable[Any],
101
- process_func: Callable[..., Any],
102
- process_args_len: int,
103
- *,
104
- threads: bool,
105
- ) -> list[Any]:
106
- """Get multiprocess results with tqdm progress tracking.
107
-
108
- Processes results from parallel execution with a progress bar and ensures
109
- they are returned in the original order.
110
-
111
- Args:
112
- results: Iterable of results from parallel execution
113
- process_func: Function that was executed in parallel
114
- process_args_len: Number of items to process in parallel
115
- threads: Whether threading (True) or multiprocessing (False) was used
116
-
117
- Returns:
118
- list[Any]: Results from parallel execution in original order
119
-
120
- """
121
- results = tqdm(
122
- results,
123
- total=process_args_len,
124
- desc=f"Multi{'threading' if threads else 'processing'} {process_func.__name__}",
125
- unit=f" {'threads' if threads else 'processes'}",
126
- )
127
- results_list = list(results)
128
- # results list is a tuple of (order, result),
129
- # so we need to sort it by order to get the original order
130
- results_list = sorted(results_list, key=lambda x: x[0])
131
- # now extract the results from the tuple
132
- return [result[1] for result in results_list]
133
-
134
-
135
- def find_max_pools(
136
- *,
137
- threads: bool,
138
- process_args_len: int | None = None,
139
- ) -> int:
140
- """Find optimal number of worker processes or threads for parallel execution.
141
-
142
- Determines the maximum number of worker processes or threads based on system
143
- resources, active tasks, and the number of items to process.
144
-
145
- Args:
146
- threads: Whether to use threading (True) or multiprocessing (False)
147
- process_args_len: Number of items to process in parallel
148
-
149
- Returns:
150
- int: Maximum number of worker processes or threads to use
151
-
152
- """
153
- # use tee to find length of process_args
154
- cpu_count = os.cpu_count() or 1
155
- if threads:
156
- active_tasks = threading.active_count()
157
- max_tasks = cpu_count * 4
158
- else:
159
- active_tasks = len(multiprocessing.active_children())
160
- max_tasks = cpu_count
161
-
162
- available_tasks = max_tasks - active_tasks
163
- max_pools = (
164
- min(available_tasks, process_args_len) if process_args_len else available_tasks
165
- )
166
- max_pools = max(max_pools, 1)
167
-
168
- logger.info(
169
- "Multi%s with max_pools: %s",
170
- "threading" if threads else "processing",
171
- max_pools,
172
- )
173
-
174
- return max_pools
175
-
176
-
177
- def concurrent_loop( # noqa: PLR0913
178
- *,
179
- threading: bool,
180
- process_function: Callable[..., Any],
181
- process_args: Iterable[Iterable[Any]],
182
- process_args_static: Iterable[Any] | None = None,
183
- deepcopy_static_args: Iterable[Any] | None = None,
184
- process_args_len: int = 1,
185
- ) -> list[Any]:
186
- """Execute a function concurrently with multiple arguments using a pool executor.
187
-
188
- This function is a helper function for multiprocess_loop and multithread_loop.
189
- It is not meant to be used directly.
190
-
191
- Args:
192
- threading (bool):
193
- Whether to use threading (True) or multiprocessing (False)
194
- pool_executor (Pool | ThreadPoolExecutor):
195
- Pool executor to use for concurrent execution
196
- process_function (Callable[..., Any]):
197
- Function to be executed concurrently
198
- process_args (Iterable[Iterable[Any]]):
199
- Arguments for each process
200
- process_args_static (Iterable[Any] | None, optional):
201
- Static arguments to pass to each process. Defaults to None.
202
- deepcopy_static_args (Iterable[Any] | None, optional):
203
- Arguments that should be deep-copied for each process. Defaults to None.
204
- process_args_len (int | None, optional):
205
- Length of process_args. Defaults to None.
206
-
207
- Returns:
208
- list[Any]: Results from the process_function executions
209
- """
210
- process_args_len = get_len_with_default(process_args, process_args_len)
211
- process_args = generate_process_args(
212
- process_function=process_function,
213
- process_args=process_args,
214
- process_args_static=process_args_static,
215
- deepcopy_static_args=deepcopy_static_args,
216
- )
217
- max_workers = find_max_pools(threads=threading, process_args_len=process_args_len)
218
- pool_executor = (
219
- ThreadPoolExecutor(max_workers=max_workers)
220
- if threading
221
- else Pool(processes=max_workers)
222
- )
223
- with pool_executor as pool:
224
- map_func: Callable[[Callable[..., Any], Iterable[Any]], Any]
225
-
226
- if process_args_len == 1:
227
- map_func = map
228
- elif threading:
229
- pool = cast("ThreadPoolExecutor", pool)
230
- map_func = partial(imap_unordered, pool)
231
- else:
232
- pool = cast("Pool", pool)
233
- map_func = pool.imap_unordered
234
-
235
- results = map_func(get_order_and_func_result, process_args)
236
-
237
- return get_multiprocess_results_with_tqdm(
238
- results=results,
239
- process_func=process_function,
240
- process_args_len=process_args_len,
241
- threads=threading,
242
- )
1
+ """Concurrent processing utilities for parallel execution.
2
+
3
+ This module provides functions for concurrent processing using both multiprocessing
4
+ and multithreading approaches. It includes utilities for handling timeouts,
5
+ managing process pools, and organizing parallel execution of functions.
6
+
7
+ Returns:
8
+ Various utility functions for concurrent processing.
9
+
10
+ """
11
+
12
+ import multiprocessing
13
+ import os
14
+ import threading
15
+ from collections.abc import Callable, Generator, Iterable
16
+ from concurrent.futures import ThreadPoolExecutor
17
+ from copy import deepcopy
18
+ from functools import partial
19
+ from typing import TYPE_CHECKING, Any, cast
20
+
21
+ from tqdm import tqdm
22
+
23
+ from winipedia_utils.concurrent.multiprocessing import get_spwan_pool
24
+ from winipedia_utils.concurrent.multithreading import imap_unordered
25
+ from winipedia_utils.iterating.iterate import get_len_with_default
26
+ from winipedia_utils.logging.logger import get_logger
27
+
28
+ if TYPE_CHECKING:
29
+ from multiprocessing.pool import Pool
30
+
31
+ logger = get_logger(__name__)
32
+
33
+
34
+ def get_order_and_func_result(
35
+ func_order_args: tuple[Any, ...],
36
+ ) -> tuple[int, Any]:
37
+ """Process function for imap with arguments unpacking.
38
+
39
+ Helper function that gives back a function that can be used with imap_unordered
40
+ to execute a function with arguments unpacking.
41
+
42
+ Args:
43
+ func_order_args: Tuple containing the function to be executed,
44
+ the order index, and the arguments for the function
45
+
46
+ Returns:
47
+ A tuple containing the order index and the result of the function execution
48
+
49
+ """
50
+ function, order, *args = func_order_args
51
+ return order, function(*args)
52
+
53
+
54
+ def generate_process_args(
55
+ *,
56
+ process_function: Callable[..., Any],
57
+ process_args: Iterable[Iterable[Any]],
58
+ process_args_static: Iterable[Any] | None = None,
59
+ deepcopy_static_args: Iterable[Any] | None = None,
60
+ ) -> Generator[tuple[Any, ...], None, None]:
61
+ """Prepare arguments for multiprocessing or multithreading execution.
62
+
63
+ Converts input arguments into a format suitable for parallel processing,
64
+ organizing them for efficient unpacking during execution. The function:
65
+ 1. Prepends process func and order indices to arguments
66
+ 2. Handles static arguments (with optional deep copying)
67
+ 3. Restructures arguments into tuples for unpacking
68
+
69
+ Args:
70
+ process_function: Function to be executed
71
+ process_args: Iterable of argument lists for each parallel call
72
+ process_args_static: Optional constant arguments to add to each call
73
+ deepcopy_static_args: Optional constant arguments that should be deep-copied
74
+
75
+ Returns:
76
+ A Genrator that yields one args tuple for each function call
77
+ First is the process function
78
+ Second item in the tuple is the order index
79
+ Second item in the tuple is the function
80
+ Rest of the items are the arguments for the function
81
+ The length of the generator
82
+ """
83
+ process_args_static = (
84
+ () if process_args_static is None else tuple(process_args_static)
85
+ )
86
+ deepcopy_static_args = (
87
+ () if deepcopy_static_args is None else tuple(deepcopy_static_args)
88
+ )
89
+ for order, process_arg in enumerate(process_args):
90
+ yield (
91
+ process_function,
92
+ order,
93
+ *process_arg,
94
+ *process_args_static,
95
+ *(
96
+ deepcopy(deepcopy_static_arg)
97
+ for deepcopy_static_arg in deepcopy_static_args
98
+ ),
99
+ )
100
+
101
+
102
+ def get_multiprocess_results_with_tqdm(
103
+ results: Iterable[Any],
104
+ process_func: Callable[..., Any],
105
+ process_args_len: int,
106
+ *,
107
+ threads: bool,
108
+ ) -> list[Any]:
109
+ """Get multiprocess results with tqdm progress tracking.
110
+
111
+ Processes results from parallel execution with a progress bar and ensures
112
+ they are returned in the original order.
113
+
114
+ Args:
115
+ results: Iterable of results from parallel execution
116
+ process_func: Function that was executed in parallel
117
+ process_args_len: Number of items to process in parallel
118
+ threads: Whether threading (True) or multiprocessing (False) was used
119
+
120
+ Returns:
121
+ list[Any]: Results from parallel execution in original order
122
+
123
+ """
124
+ results = tqdm(
125
+ results,
126
+ total=process_args_len,
127
+ desc=f"Multi{'threading' if threads else 'processing'} {process_func.__name__}",
128
+ unit=f" {'threads' if threads else 'processes'}",
129
+ )
130
+ results_list = list(results)
131
+ # results list is a tuple of (order, result),
132
+ # so we need to sort it by order to get the original order
133
+ results_list = sorted(results_list, key=lambda x: x[0])
134
+ # now extract the results from the tuple
135
+ return [result[1] for result in results_list]
136
+
137
+
138
+ def find_max_pools(
139
+ *,
140
+ threads: bool,
141
+ process_args_len: int | None = None,
142
+ ) -> int:
143
+ """Find optimal number of worker processes or threads for parallel execution.
144
+
145
+ Determines the maximum number of worker processes or threads based on system
146
+ resources, active tasks, and the number of items to process.
147
+
148
+ Args:
149
+ threads: Whether to use threading (True) or multiprocessing (False)
150
+ process_args_len: Number of items to process in parallel
151
+
152
+ Returns:
153
+ int: Maximum number of worker processes or threads to use
154
+
155
+ """
156
+ # use tee to find length of process_args
157
+ cpu_count = os.cpu_count() or 1
158
+ if threads:
159
+ active_tasks = threading.active_count()
160
+ max_tasks = cpu_count * 4
161
+ else:
162
+ active_tasks = len(multiprocessing.active_children())
163
+ max_tasks = cpu_count
164
+
165
+ available_tasks = max_tasks - active_tasks
166
+ max_pools = (
167
+ min(available_tasks, process_args_len) if process_args_len else available_tasks
168
+ )
169
+ max_pools = max(max_pools, 1)
170
+
171
+ logger.info(
172
+ "Multi%s with max_pools: %s",
173
+ "threading" if threads else "processing",
174
+ max_pools,
175
+ )
176
+
177
+ return max_pools
178
+
179
+
180
+ def concurrent_loop( # noqa: PLR0913
181
+ *,
182
+ threading: bool,
183
+ process_function: Callable[..., Any],
184
+ process_args: Iterable[Iterable[Any]],
185
+ process_args_static: Iterable[Any] | None = None,
186
+ deepcopy_static_args: Iterable[Any] | None = None,
187
+ process_args_len: int = 1,
188
+ ) -> list[Any]:
189
+ """Execute a function concurrently with multiple arguments using a pool executor.
190
+
191
+ This function is a helper function for multiprocess_loop and multithread_loop.
192
+ It is not meant to be used directly.
193
+
194
+ Args:
195
+ threading (bool):
196
+ Whether to use threading (True) or multiprocessing (False)
197
+ pool_executor (Pool | ThreadPoolExecutor):
198
+ Pool executor to use for concurrent execution
199
+ process_function (Callable[..., Any]):
200
+ Function to be executed concurrently
201
+ process_args (Iterable[Iterable[Any]]):
202
+ Arguments for each process
203
+ process_args_static (Iterable[Any] | None, optional):
204
+ Static arguments to pass to each process. Defaults to None.
205
+ deepcopy_static_args (Iterable[Any] | None, optional):
206
+ Arguments that should be deep-copied for each process. Defaults to None.
207
+ process_args_len (int | None, optional):
208
+ Length of process_args. Defaults to None.
209
+
210
+ Returns:
211
+ list[Any]: Results from the process_function executions
212
+ """
213
+ process_args_len = get_len_with_default(process_args, process_args_len)
214
+ process_args = generate_process_args(
215
+ process_function=process_function,
216
+ process_args=process_args,
217
+ process_args_static=process_args_static,
218
+ deepcopy_static_args=deepcopy_static_args,
219
+ )
220
+ max_workers = find_max_pools(threads=threading, process_args_len=process_args_len)
221
+ pool_executor = (
222
+ ThreadPoolExecutor(max_workers=max_workers)
223
+ if threading
224
+ else get_spwan_pool(processes=max_workers)
225
+ )
226
+ with pool_executor as pool:
227
+ map_func: Callable[[Callable[..., Any], Iterable[Any]], Any]
228
+
229
+ if process_args_len == 1:
230
+ map_func = map
231
+ elif threading:
232
+ pool = cast("ThreadPoolExecutor", pool)
233
+ map_func = partial(imap_unordered, pool)
234
+ else:
235
+ pool = cast("Pool", pool)
236
+ map_func = pool.imap_unordered
237
+
238
+ results = map_func(get_order_and_func_result, process_args)
239
+
240
+ return get_multiprocess_results_with_tqdm(
241
+ results=results,
242
+ process_func=process_function,
243
+ process_args_len=process_args_len,
244
+ threads=threading,
245
+ )