kisa-utils 0.42.9__py3-none-any.whl → 0.42.11__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.
- kisa_utils/queues/persistent.py +96 -2
- kisa_utils/structures/validator.py +9 -1
- kisa_utils/threads.py +21 -12
- {kisa_utils-0.42.9.dist-info → kisa_utils-0.42.11.dist-info}/METADATA +1 -1
- {kisa_utils-0.42.9.dist-info → kisa_utils-0.42.11.dist-info}/RECORD +7 -7
- {kisa_utils-0.42.9.dist-info → kisa_utils-0.42.11.dist-info}/WHEEL +0 -0
- {kisa_utils-0.42.9.dist-info → kisa_utils-0.42.11.dist-info}/top_level.txt +0 -0
kisa_utils/queues/persistent.py
CHANGED
|
@@ -7,6 +7,8 @@ from kisa_utils import dates
|
|
|
7
7
|
from kisa_utils.functionUtils import enforceRequirements
|
|
8
8
|
from kisa_utils.structures.utils import Value
|
|
9
9
|
|
|
10
|
+
from typing import Callable
|
|
11
|
+
|
|
10
12
|
class __PersistentQueueSingleton(type):
|
|
11
13
|
_instances = {}
|
|
12
14
|
|
|
@@ -26,7 +28,6 @@ class __PersistentQueueSingleton(type):
|
|
|
26
28
|
|
|
27
29
|
return cls._instances[idKey]
|
|
28
30
|
|
|
29
|
-
|
|
30
31
|
class PersistentQueue(metaclass=__PersistentQueueSingleton):
|
|
31
32
|
__openedQueues:dict = {} # name: PersistentQueue
|
|
32
33
|
|
|
@@ -81,7 +82,8 @@ class PersistentQueue(metaclass=__PersistentQueueSingleton):
|
|
|
81
82
|
self.append = queueCallsInThreads(self.append, group=self.id)
|
|
82
83
|
self.peek = queueCallsInThreads(self.peek, group=self.id)
|
|
83
84
|
self.pop = queueCallsInThreads(self.pop, group=self.id)
|
|
84
|
-
|
|
85
|
+
self.process = queueCallsInThreads(self.process, group=self.id)
|
|
86
|
+
|
|
85
87
|
self.__load__ = queueCallsInThreads(self.__load__, group = "pqueue__load__")
|
|
86
88
|
|
|
87
89
|
if not (resp := self.__load__()):
|
|
@@ -162,6 +164,7 @@ class PersistentQueue(metaclass=__PersistentQueueSingleton):
|
|
|
162
164
|
self.__length += 1
|
|
163
165
|
return Ok(self.__length)
|
|
164
166
|
|
|
167
|
+
@enforceRequirements
|
|
165
168
|
def peek(self, index:int, /) -> Response:
|
|
166
169
|
'''
|
|
167
170
|
get data at `index` without popping it from the queue
|
|
@@ -182,6 +185,7 @@ class PersistentQueue(metaclass=__PersistentQueueSingleton):
|
|
|
182
185
|
|
|
183
186
|
return Ok(data)
|
|
184
187
|
|
|
188
|
+
@enforceRequirements
|
|
185
189
|
def pop(self, index:int = 0, /) -> Response:
|
|
186
190
|
'''
|
|
187
191
|
get data at `index` and remove it from the queue
|
|
@@ -206,3 +210,93 @@ class PersistentQueue(metaclass=__PersistentQueueSingleton):
|
|
|
206
210
|
self.__length -= 1
|
|
207
211
|
|
|
208
212
|
return Ok(data)
|
|
213
|
+
|
|
214
|
+
@enforceRequirements
|
|
215
|
+
def process(self, index:int, handler:Callable[...,Response], /, *, popOnHandlerSuccess:bool=True, popOnHandlerError:bool=False) -> Response:
|
|
216
|
+
'''
|
|
217
|
+
process item at `index` by passing it as an argument to `handler`
|
|
218
|
+
Args:
|
|
219
|
+
index(int): the index to process
|
|
220
|
+
handler(Callable): a function/method that takes a single argument and returns a `Response` object
|
|
221
|
+
popOnHandlerSuccess(bool): a bool indicating if the item should be poppoed if `handler` returns as `Ok` object
|
|
222
|
+
popOnHandlerError(bool): a bool indicating if the item should be poppoed if `handler` returns as `Error` object
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
`Ok` object with a KDict containing the processed item along with if or not it was popped if all goes well, `Error` object otherwise
|
|
226
|
+
'''
|
|
227
|
+
|
|
228
|
+
if not (resp := self.peek(index)):
|
|
229
|
+
return resp
|
|
230
|
+
|
|
231
|
+
item = resp.data
|
|
232
|
+
try:
|
|
233
|
+
handlerResp = handler(item)
|
|
234
|
+
except Exception as e:
|
|
235
|
+
return Error(str(e))
|
|
236
|
+
|
|
237
|
+
if not isinstance(handlerResp, Response):
|
|
238
|
+
return Error(f'{handler.__name__} did not return a {Response} object!')
|
|
239
|
+
|
|
240
|
+
popped:bool = False
|
|
241
|
+
|
|
242
|
+
if handlerResp and popOnHandlerSuccess:
|
|
243
|
+
if not (resp := self.pop(index)):
|
|
244
|
+
...
|
|
245
|
+
popped = True
|
|
246
|
+
|
|
247
|
+
if not handlerResp and popOnHandlerError and not popped:
|
|
248
|
+
if not (resp := self.pop(index)):
|
|
249
|
+
...
|
|
250
|
+
popped = True
|
|
251
|
+
|
|
252
|
+
if (popOnHandlerSuccess or popOnHandlerError) and not popped:
|
|
253
|
+
# what do we do in such a case?
|
|
254
|
+
...
|
|
255
|
+
|
|
256
|
+
return Ok(KDict({
|
|
257
|
+
'item': item,
|
|
258
|
+
'popped': popped
|
|
259
|
+
}))
|
|
260
|
+
|
|
261
|
+
@enforceRequirements
|
|
262
|
+
def processAll(self, handler:Callable[...,Response], /, *, popOnHandlerSuccess:bool=True, popOnHandlerError:bool=False) -> Response:
|
|
263
|
+
'''
|
|
264
|
+
process item at `index` by passing it as an argument to `handler`
|
|
265
|
+
Args:
|
|
266
|
+
handler(Callable): a function/method that takes a single argument and returns a `Response` object
|
|
267
|
+
popOnHandlerSuccess(bool): a bool indicating if the item should be poppoed if `handler` returns as `Ok` object
|
|
268
|
+
popOnHandlerError(bool): a bool indicating if the item should be poppoed if `handler` returns as `Error` object
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
`Ok` object with a KDict containing processedCount,PoppedCount,failedCount,failedLogs if all goes well, `Error` object otherwise
|
|
272
|
+
'''
|
|
273
|
+
|
|
274
|
+
index = 0
|
|
275
|
+
|
|
276
|
+
results = KDict({
|
|
277
|
+
'processedCount': 0,
|
|
278
|
+
'PoppedCount': 0,
|
|
279
|
+
'failedCount': 0,
|
|
280
|
+
'failedLogs': [],
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
while index < len(self):
|
|
284
|
+
if not (resp := self.process(index, handler, popOnHandlerSuccess=popOnHandlerSuccess, popOnHandlerError=popOnHandlerError)):
|
|
285
|
+
results.processedCount += 1
|
|
286
|
+
results.failedCount += 1
|
|
287
|
+
index += 1
|
|
288
|
+
results.failedLogs.append(KDict({
|
|
289
|
+
'item': self.peek(index).data,
|
|
290
|
+
'error': resp.log
|
|
291
|
+
}))
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
results.processedCount += 1
|
|
295
|
+
|
|
296
|
+
popped = resp.data.popped
|
|
297
|
+
if popped:
|
|
298
|
+
results.PoppedCount += 1
|
|
299
|
+
else:
|
|
300
|
+
index += 1
|
|
301
|
+
|
|
302
|
+
return Ok(results)
|
|
@@ -3,7 +3,7 @@ this modules handle data structure validation to ensure that
|
|
|
3
3
|
data is passed in expected formats/structures
|
|
4
4
|
'''
|
|
5
5
|
|
|
6
|
-
from typing import Any, get_args, get_origin
|
|
6
|
+
from typing import Any, get_args, get_origin, Callable
|
|
7
7
|
from types import UnionType
|
|
8
8
|
from kisa_utils.structures.utils import Value
|
|
9
9
|
from kisa_utils.response import Response, Ok, Error
|
|
@@ -54,6 +54,14 @@ def validate(instance:Any, structure:Any, path:str='$') -> dict:
|
|
|
54
54
|
result['status'] = True
|
|
55
55
|
return result
|
|
56
56
|
else:
|
|
57
|
+
if isinstance(structure, Callable):
|
|
58
|
+
if not callable(instance):
|
|
59
|
+
result['log'] = f'E07: types not similar:: {path}, expected a Callable but got {str(type(instance))[7:-1]}'
|
|
60
|
+
else:
|
|
61
|
+
result['status'] = True
|
|
62
|
+
|
|
63
|
+
return result
|
|
64
|
+
|
|
57
65
|
# checking in both directions as dict and KDict can fail when you check
|
|
58
66
|
# `isinstance(dict, KDict)` but will pass when the arguments switch positions
|
|
59
67
|
if (not isinstance(instance,type(structure))) and (not isinstance(structure, type(instance))):
|
kisa_utils/threads.py
CHANGED
|
@@ -10,6 +10,7 @@ from concurrent import futures
|
|
|
10
10
|
import time
|
|
11
11
|
import datetime
|
|
12
12
|
import threading
|
|
13
|
+
import inspect
|
|
13
14
|
from . import codes
|
|
14
15
|
from .response import Response, Ok, Error
|
|
15
16
|
from typing import Callable
|
|
@@ -43,8 +44,8 @@ class Group:
|
|
|
43
44
|
add a function to the group
|
|
44
45
|
Args:
|
|
45
46
|
function(Callable): the function to be run
|
|
46
|
-
args(tuple): arguments
|
|
47
|
-
kwargs(dict):
|
|
47
|
+
args(tuple): arguments to be passsed to `function`
|
|
48
|
+
kwargs(dict): key-word arguments to be passsed to `function`
|
|
48
49
|
'''
|
|
49
50
|
if not callable(function):
|
|
50
51
|
return Error(f'`{function}` is not callable')
|
|
@@ -120,8 +121,8 @@ def runOnce(function:Callable, *args:tuple, **kwargs:dict) -> Response:
|
|
|
120
121
|
run a task in a separate thread
|
|
121
122
|
Args:
|
|
122
123
|
function(Callable): the function to be run
|
|
123
|
-
args(tuple): arguments
|
|
124
|
-
kwargs(dict):
|
|
124
|
+
args(tuple): arguments to be passsed to `function`
|
|
125
|
+
kwargs(dict): key-word arguments to be passsed to `function`
|
|
125
126
|
'''
|
|
126
127
|
__initExecutor()
|
|
127
128
|
|
|
@@ -129,7 +130,7 @@ def runOnce(function:Callable, *args:tuple, **kwargs:dict) -> Response:
|
|
|
129
130
|
return Error(f'`{function}` is not callable')
|
|
130
131
|
|
|
131
132
|
try:
|
|
132
|
-
return Ok(__executor.run(function, *args, **kwargs))
|
|
133
|
+
return Ok(__executor.run(function, *args, **kwargs).result())
|
|
133
134
|
except Exception as e:
|
|
134
135
|
return Error(f'failed to run task: {e}')
|
|
135
136
|
|
|
@@ -139,7 +140,11 @@ def __loop(function:Callable, duration:float, *args:tuple, **kwargs:dict) -> Non
|
|
|
139
140
|
'''
|
|
140
141
|
while 1:
|
|
141
142
|
time.sleep(duration)
|
|
142
|
-
|
|
143
|
+
try:
|
|
144
|
+
function(*args, **kwargs)
|
|
145
|
+
except Exception as e:
|
|
146
|
+
print(f'`[run-every ERR] `{inspect.getsourcefile(function)}::{function.__name__}` failed with exception: e`')
|
|
147
|
+
|
|
143
148
|
|
|
144
149
|
def runEvery(function:Callable, duration:float, *args:tuple, **kwargs:dict) -> dict[str,str|bool]:
|
|
145
150
|
'''
|
|
@@ -147,8 +152,8 @@ def runEvery(function:Callable, duration:float, *args:tuple, **kwargs:dict) -> d
|
|
|
147
152
|
Args:
|
|
148
153
|
function(Callable): the function to call every `duration`
|
|
149
154
|
duration(float): the time(in SECONDS) after which to run `function` periodically
|
|
150
|
-
args(tuple): arguments
|
|
151
|
-
kwargs(dict):
|
|
155
|
+
args(tuple): arguments to be passsed to `function`
|
|
156
|
+
kwargs(dict): key-word arguments to be passsed to `function`
|
|
152
157
|
|
|
153
158
|
Returns:
|
|
154
159
|
dict in form
|
|
@@ -178,6 +183,8 @@ def runEvery(function:Callable, duration:float, *args:tuple, **kwargs:dict) -> d
|
|
|
178
183
|
reply['log'] = f'failed to run task: {e}'
|
|
179
184
|
return reply
|
|
180
185
|
|
|
186
|
+
# future.result()
|
|
187
|
+
|
|
181
188
|
reply['status'] = True
|
|
182
189
|
return reply
|
|
183
190
|
|
|
@@ -213,9 +220,10 @@ def __loopRoutineThreads():
|
|
|
213
220
|
|
|
214
221
|
try:
|
|
215
222
|
future = __executor.run(data['function'],*data['args'], **data['kwargs'])
|
|
223
|
+
# future.result()
|
|
216
224
|
currentMinuteData['functionsAlreadyRun'][functionName] = None
|
|
217
225
|
except Exception as e:
|
|
218
|
-
print(f'[routine-loop]: {e}')
|
|
226
|
+
print(f'[routine-loop ERR]: {e}')
|
|
219
227
|
pass
|
|
220
228
|
|
|
221
229
|
def runAt(function:Callable, timesOfDay:list[tuple[int,int]], weekDays:list[int], *args:tuple, tzHoursFromUTC:float = +3.00, **kwargs:dict) -> Response:
|
|
@@ -227,8 +235,8 @@ def runAt(function:Callable, timesOfDay:list[tuple[int,int]], weekDays:list[int]
|
|
|
227
235
|
weekDays(list[int]): a list of `ints` each ranging `0-6, inclusive` indicating a day of the week where `0=sunday` and `6=saturday`
|
|
228
236
|
tzHoursFromUTC(float): hours to add/subtract from UTC. this allows for `timesOfDay` to be seen in a particular timezone.
|
|
229
237
|
the default value is `+3.00` ie `EAT` so times in `timesOfDay` are in EAT
|
|
230
|
-
args(tuple): arguments
|
|
231
|
-
kwargs(dict):
|
|
238
|
+
args(tuple): arguments to be passsed to `function`
|
|
239
|
+
kwargs(dict): key-word arguments to be passsed to `function`
|
|
232
240
|
|
|
233
241
|
'''
|
|
234
242
|
|
|
@@ -282,7 +290,8 @@ def __initExecutor():
|
|
|
282
290
|
if __executor: return
|
|
283
291
|
|
|
284
292
|
__executor = __Executor()
|
|
285
|
-
__executor.run(__loopRoutineThreads)
|
|
293
|
+
future = __executor.run(__loopRoutineThreads)
|
|
294
|
+
# future.result()
|
|
286
295
|
|
|
287
296
|
# futures.as_completed([__executor.run(__loopRoutineThreads)])
|
|
288
297
|
|
|
@@ -13,12 +13,12 @@ kisa_utils/remote.py,sha256=0RDrfC4RUW4m6JLziC0_EXJYqzWp38Rw8NDroJ0MuqI,2149
|
|
|
13
13
|
kisa_utils/response.py,sha256=asETUBkeF5OlSTwa-coa7lZDCKmQlHCmHf6eaZFl8CU,4560
|
|
14
14
|
kisa_utils/standardize.py,sha256=nt-uzHQFoKxGscD_MpDYXw65Teg3724whAqa6Kh_zhE,2231
|
|
15
15
|
kisa_utils/storage.py,sha256=6NdEVrHMS7WB_vmCwiGigIinu-EjxalFJhk1kj-_vWs,5990
|
|
16
|
-
kisa_utils/threads.py,sha256=
|
|
16
|
+
kisa_utils/threads.py,sha256=U1hVCmDoCrWsi8fOJptewJ0Q0hXtGn8UZVT52pbC36E,12979
|
|
17
17
|
kisa_utils/token.py,sha256=Y2qglWYWpmHxoXBh-TH0r1as0uPV5LLqMNcunLvM4vM,7850
|
|
18
18
|
kisa_utils/permissions/__config__.py,sha256=i3ELkOydDnjKx2ozQTxLZdZ8DXSeUncnl2kRxANjFmM,613
|
|
19
19
|
kisa_utils/permissions/__init__.py,sha256=iAsGEf5Ktw3gPJ5ZKL8BnuqX8e_S4QgsCVgfaRYi4Qg,48068
|
|
20
20
|
kisa_utils/queues/__init__.py,sha256=VvhceyN5qeiMel1JFQwLRuVk48oBXaWvDtriCubDOms,48
|
|
21
|
-
kisa_utils/queues/persistent.py,sha256=
|
|
21
|
+
kisa_utils/queues/persistent.py,sha256=b731r1NJkOxlJdkYoxDx2Ojf8loTCY87sd-1_xWn_L4,10431
|
|
22
22
|
kisa_utils/queues/callables/__init__.py,sha256=OJL3AQnaAS1Eek4H6WBH3WefA2wf-x03cwFmRSK8hoU,141
|
|
23
23
|
kisa_utils/queues/callables/enqueueFunctionCalls.py,sha256=VIliaMvw4MUdOqts0dXdZCYNxs-QrOVjIRAR3scGrRM,11786
|
|
24
24
|
kisa_utils/queues/callables/executorQueues.py,sha256=x6bAqxBSZRZ_kL8CK1lSN6JYAYFLxzM84LC1RmwaOLw,6626
|
|
@@ -26,8 +26,8 @@ kisa_utils/servers/__init__.py,sha256=lPqDyGTrFo0qwPZ2WA9Xtcpc5D8AIU4huqgFx1iZf6
|
|
|
26
26
|
kisa_utils/servers/flask.py,sha256=XZYY1pWnP1mSvaS5Uv8G3EFJV5BJBQtU2gDbO8suvLc,40422
|
|
27
27
|
kisa_utils/structures/__init__.py,sha256=JBU1j3A42jQ62ALKnsS1Hav9YXcYwjDw1wQJtohXPbU,83
|
|
28
28
|
kisa_utils/structures/utils.py,sha256=665rXIapGwFqejizeJwy3DryeskCQOdgP25BCdLkGvk,2898
|
|
29
|
-
kisa_utils/structures/validator.py,sha256=
|
|
30
|
-
kisa_utils-0.42.
|
|
31
|
-
kisa_utils-0.42.
|
|
32
|
-
kisa_utils-0.42.
|
|
33
|
-
kisa_utils-0.42.
|
|
29
|
+
kisa_utils/structures/validator.py,sha256=oCSgY_itst6bZdC5g8yVU4-lSH2xnUsOx3X-oPyV7nA,4626
|
|
30
|
+
kisa_utils-0.42.11.dist-info/METADATA,sha256=RRVFT0IudGdenO9WQWlCG9AXy2RBec1YTC7pB-VhAlw,478
|
|
31
|
+
kisa_utils-0.42.11.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
32
|
+
kisa_utils-0.42.11.dist-info/top_level.txt,sha256=GFOLXZYqpBG9xtscGa2uGJAEiZ5NwsqHBH9NylnB29M,11
|
|
33
|
+
kisa_utils-0.42.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|