osbot-utils 1.48.0__py3-none-any.whl → 1.50.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.
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import logging
2
3
  import typing
3
4
 
@@ -8,6 +9,7 @@ from osbot_utils.testing.Stdout import Stdout
8
9
  from osbot_utils.utils.Misc import random_id, lower
9
10
  from osbot_utils.utils.Python_Logger import Python_Logger
10
11
  from osbot_utils.utils.Str import ansis_to_texts
12
+ from osbot_utils.utils.Threads import invoke_async, invoke_in_new_event_loop
11
13
 
12
14
  FLOW__RANDOM_ID__PREFIX = 'flow_id__'
13
15
  FLOW__RANDOM_NAME__PREFIX = 'flow_name__'
@@ -29,9 +31,6 @@ class Flow(Type_Safe):
29
31
  flow_return_value : typing.Any
30
32
  logger : Python_Logger
31
33
  cformat : CFormat
32
- #log_to_console : bool = False
33
- #log_to_memory : bool = True
34
- #print_logs : bool = False
35
34
  executed_tasks : typing.List
36
35
 
37
36
 
@@ -61,7 +60,7 @@ class Flow(Type_Safe):
61
60
  self.debug(f"Executing flow run '{self.f__flow_id()}''")
62
61
  try:
63
62
  with Stdout() as stdout:
64
- self.flow_return_value = self.flow_target(*self.flow_args, **self.flow_kwargs) # todo, capture *args, **kwargs in logs
63
+ self.invoke_flow_target()
65
64
  except Exception as error:
66
65
  self.flow_error = error
67
66
  self.logger.error(self.cformat.red(f"Error executing flow: {error}"))
@@ -87,6 +86,13 @@ class Flow(Type_Safe):
87
86
  def info(self, message):
88
87
  self.logger.info(message)
89
88
 
89
+ def invoke_flow_target(self):
90
+ if asyncio.iscoroutinefunction(self.flow_target):
91
+ #self.flow_return_value = invoke_async(self.flow_target(*self.flow_args, **self.flow_kwargs))
92
+ self.flow_return_value = invoke_in_new_event_loop(self.flow_target(*self.flow_args, **self.flow_kwargs))
93
+ else:
94
+ self.flow_return_value = self.flow_target(*self.flow_args, **self.flow_kwargs)
95
+
90
96
  def log_captured_stdout(self, stdout):
91
97
  for line in stdout.value().splitlines():
92
98
  if line:
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import inspect
2
3
  import typing
3
4
 
@@ -10,12 +11,13 @@ from osbot_utils.base_classes.Type_Safe import Type_Safe
10
11
  from osbot_utils.helpers.flows.Flow import Flow
11
12
 
12
13
 
13
-
14
14
  class Task(Type_Safe):
15
15
  data : dict # dict available to the task to add and collect data
16
16
  task_id : str # todo add a random Id value to this
17
17
  task_name : str # make this the function mame
18
18
  cformat : CFormat
19
+ resolved_args : tuple
20
+ resolved_kwargs : dict
19
21
  task_target : callable # todo refactor this to to Task__Function class
20
22
  task_args : tuple
21
23
  task_kwargs : dict
@@ -24,7 +26,17 @@ class Task(Type_Safe):
24
26
  task_error : Exception = None
25
27
  raise_on_error : bool = True
26
28
 
27
- def execute(self):
29
+ def execute__sync(self):
30
+ self.execute__before()
31
+ self.execute__task_target__sync()
32
+ return self.execute__after()
33
+
34
+ async def execute__async(self):
35
+ self.execute__before()
36
+ await self.execute__task_target__async()
37
+ return self.execute__after()
38
+
39
+ def execute__before(self):
28
40
  self.task_flow = self.find_flow()
29
41
  if self.task_flow is None:
30
42
  raise Exception("No Flow found for Task")
@@ -34,14 +46,30 @@ class Task(Type_Safe):
34
46
 
35
47
  self.task_flow.executed_tasks.append(self)
36
48
  self.task_flow.logger.debug(f"Executing task '{f_blue(self.task_name)}'")
49
+ dependency_manager = Dependency_Manager()
50
+ dependency_manager.add_dependency('this_task', self )
51
+ dependency_manager.add_dependency('this_flow', self.task_flow )
52
+ dependency_manager.add_dependency('task_data', self.data )
53
+ dependency_manager.add_dependency('flow_data', self.task_flow.data)
54
+ self.resolved_args, self.resolved_kwargs = dependency_manager.resolve_dependencies(self.task_target, *self.task_args, **self.task_kwargs)
37
55
 
56
+ def execute__task_target__sync(self):
38
57
  try:
39
58
  with Stdout() as stdout:
40
- self.invoke_task_target()
59
+ self.task_return_value = self.task_target(*self.resolved_args, **self.resolved_kwargs)
41
60
  except Exception as error:
42
61
  self.task_error = error
62
+ self.task_flow.log_captured_stdout(stdout)
43
63
 
64
+ async def execute__task_target__async(self):
65
+ try:
66
+ with Stdout() as stdout:
67
+ self.task_return_value = await self.task_target(*self.resolved_args, **self.resolved_kwargs)
68
+ except Exception as error:
69
+ self.task_error = error
44
70
  self.task_flow.log_captured_stdout(stdout)
71
+
72
+ def execute__after(self):
45
73
  self.print_task_return_value()
46
74
 
47
75
  if self.task_error:
@@ -52,14 +80,6 @@ class Task(Type_Safe):
52
80
  self.print_task_finished_message()
53
81
  return self.task_return_value
54
82
 
55
- def invoke_task_target(self):
56
- dependency_manager = Dependency_Manager()
57
- dependency_manager.add_dependency('this_task', self )
58
- dependency_manager.add_dependency('this_flow', self.task_flow )
59
- dependency_manager.add_dependency('task_data', self.data )
60
- dependency_manager.add_dependency('flow_data', self.task_flow.data)
61
- resolved_args, resolved_kwargs = dependency_manager.resolve_dependencies(self.task_target, *self.task_args, **self.task_kwargs)
62
- self.task_return_value = self.task_target(*resolved_args, **resolved_kwargs)
63
83
 
64
84
  def find_flow(self):
65
85
  stack = inspect.stack()
@@ -1,11 +1,23 @@
1
- from functools import wraps
1
+ from functools import wraps
2
+ import asyncio
2
3
  from osbot_utils.helpers.flows.Task import Task
3
4
 
5
+
4
6
  def task(**task_kwargs):
5
7
  def decorator(function):
6
8
  @wraps(function)
7
- def wrapper(*args, **kwargs):
9
+ async def async_wrapper(*args, **kwargs):
10
+ with Task(task_target=function, task_args=args, task_kwargs=kwargs, **task_kwargs) as _:
11
+ return await _.execute__async()
12
+
13
+ @wraps(function)
14
+ def sync_wrapper(*args, **kwargs):
8
15
  with Task(task_target=function, task_args=args, task_kwargs=kwargs, **task_kwargs) as _:
9
- return _.execute()
10
- return wrapper
11
- return decorator
16
+ return _.execute__sync()
17
+
18
+ if asyncio.iscoroutinefunction(function):
19
+ return async_wrapper
20
+ else:
21
+ return sync_wrapper
22
+
23
+ return decorator
@@ -42,5 +42,18 @@ def invoke_in_new_event_loop(target: typing.Coroutine): # Runs a cor
42
42
  result = future.result() # Wait for the result of the future
43
43
  return result # Return the result from the coroutine
44
44
 
45
+ # in the use cases when I tried to use this, it hanged
46
+ # def invoke_in_current_loop(target: typing.Coroutine):
47
+ # try:
48
+ # current_loop = asyncio.get_running_loop() # Get the current running loop, if any
49
+ # except RuntimeError: # There is no running event loop
50
+ # current_loop = None
51
+ #
52
+ # if current_loop and current_loop.is_running(): # If there's an event loop currently running, we can use asyncio.run_coroutine_threadsafe to run it
53
+ # future = asyncio.run_coroutine_threadsafe(target, current_loop)
54
+ # return future.result()
55
+ # else:
56
+ # return asyncio.run(target) # If there's no event loop running, we create a new one and use run_until_complete
57
+
45
58
  async_invoke_in_new_loop = invoke_in_new_event_loop
46
59
  invoke_async = invoke_async_function # todo: see if this is best use of this function name
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v1.48.0
1
+ v1.50.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: osbot_utils
3
- Version: 1.48.0
3
+ Version: 1.50.0
4
4
  Summary: OWASP Security Bot - Utils
5
5
  Home-page: https://github.com/owasp-sbot/OSBot-Utils
6
6
  License: MIT
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  Powerful Python util methods and classes that simplify common apis and tasks.
24
24
 
25
- ![Current Release](https://img.shields.io/badge/release-v1.48.0-blue)
25
+ ![Current Release](https://img.shields.io/badge/release-v1.50.0-blue)
26
26
  [![codecov](https://codecov.io/gh/owasp-sbot/OSBot-Utils/graph/badge.svg?token=GNVW0COX1N)](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
27
27
 
28
28
 
@@ -154,13 +154,13 @@ osbot_utils/helpers/cache_requests/Cache__Requests__Row.py,sha256=h-yc7NkpScbHww
154
154
  osbot_utils/helpers/cache_requests/Cache__Requests__Table.py,sha256=RgxAYhm-FIrXXteQRtD91pOLq8JXhSzxb51Jb6MTUdY,391
155
155
  osbot_utils/helpers/cache_requests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
156
  osbot_utils/helpers/cache_requests/flows/flow__Cache__Requests.py,sha256=xgx_oExxkcvRwQN1UCobimECIMUKGoIX5oGdCmp8Nyw,243
157
- osbot_utils/helpers/flows/Flow.py,sha256=hVIjIzotQyHc4Ms0K_Rh1Jtb5rg1zYWdfaUnBROLYxI,5747
157
+ osbot_utils/helpers/flows/Flow.py,sha256=hoUaMQzzf38VZm01CIUGWtY3hhdTFizf5aTiKKA0EFY,6032
158
158
  osbot_utils/helpers/flows/Flow__Config.py,sha256=PE8hH8KXDHz1Ex93cPMuR9nkv8AoXzXQwVxleSDkU7k,341
159
- osbot_utils/helpers/flows/Task.py,sha256=edbvtd78kzz5ghKp-awyOWop2QYxqDB0-aupcz0sjVM,3530
159
+ osbot_utils/helpers/flows/Task.py,sha256=b-EKKM4ZEXQcNDOjWHLcxkC0orhIxCOYs7Ij2aCsE7Y,4265
160
160
  osbot_utils/helpers/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
161
161
  osbot_utils/helpers/flows/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
162
  osbot_utils/helpers/flows/decorators/flow.py,sha256=LUL7bHjZ_lC3QoTNh-KsDZHzjE2u4mU-5EpZnfsEGuc,738
163
- osbot_utils/helpers/flows/decorators/task.py,sha256=2Eg8abx7ky8PVKVQijy6Oji60UKW31nXmtYftqBDB0k,394
163
+ osbot_utils/helpers/flows/decorators/task.py,sha256=9bhQBPJU1dO-J4FAsFkmxqQMBNtay4FT_b1BdpHJ9sA,734
164
164
  osbot_utils/helpers/html/Dict_To_Css.py,sha256=u6B4Mx7PXr-gDrTrs1hgknnvsZVK4Fic5LqedKjo-lk,1097
165
165
  osbot_utils/helpers/html/Dict_To_Html.py,sha256=OlRSaDGOeseBNTxRB2ho5whqEacMXeAXWOfeVSEYqC4,3355
166
166
  osbot_utils/helpers/html/Dict_To_Tags.py,sha256=L8O8c0RPzP92EfeACk3pjXJfnlz-Rg38o2Gf9tS2UfM,3745
@@ -292,13 +292,13 @@ osbot_utils/utils/Python_Logger.py,sha256=tx8N6wRKL3RDHboDRKZn8SirSJdSAE9cACyJkx
292
292
  osbot_utils/utils/Regex.py,sha256=0ubgp8HKsS3PNe2H6XlzMIcUuV7jhga3VkQVDNOJWuA,866
293
293
  osbot_utils/utils/Status.py,sha256=Yq4s0TelXgn0i2QjCP9V8mP30GabXp_UL-jjM6Iwiw4,4305
294
294
  osbot_utils/utils/Str.py,sha256=kxdY8ROX4FdJtCaMTfOc8fK_xcDICprNkefHu2MMNU4,2585
295
- osbot_utils/utils/Threads.py,sha256=bClwSZ1T_A92o4LRiNwIN2rn5oKfPLupqzy4ozdPdNw,2297
295
+ osbot_utils/utils/Threads.py,sha256=lnh4doZWYUIoWBZRU_780QPeAIKGDh7INuqmU8Fzmdc,3042
296
296
  osbot_utils/utils/Toml.py,sha256=SD6IA4-mrtoBXcI0dIGKV9POMQNd6WYKvmDQq7GQ6ZQ,1438
297
297
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
298
298
  osbot_utils/utils/Zip.py,sha256=G6Hk_hDcm9yvWzhTKzhT0R_6f0NBIAchHqMxGb3kfh4,14037
299
299
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
300
- osbot_utils/version,sha256=JsJP7WaornLYr7vvK7_49I4Wp8WPCrP0NyymiaWWpo8,8
301
- osbot_utils-1.48.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
302
- osbot_utils-1.48.0.dist-info/METADATA,sha256=kOiwLvKz80E0wYnMTficj6h8wQBQliYBLvDZ81X7WeM,1266
303
- osbot_utils-1.48.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
304
- osbot_utils-1.48.0.dist-info/RECORD,,
300
+ osbot_utils/version,sha256=TTSKY3YuToISlvvqqW7SM_vwsiPAbV3E3YaOsgqc53E,8
301
+ osbot_utils-1.50.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
302
+ osbot_utils-1.50.0.dist-info/METADATA,sha256=q9e12MtAPU8nlYVNwbazLfvD7dEB6lIDOp74iyx8KAA,1266
303
+ osbot_utils-1.50.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
304
+ osbot_utils-1.50.0.dist-info/RECORD,,