osbot-utils 2.29.0__py3-none-any.whl → 2.31.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.
Files changed (26) hide show
  1. osbot_utils/{testing → helpers/duration}/Duration.py +14 -26
  2. osbot_utils/helpers/duration/__init__.py +0 -0
  3. osbot_utils/helpers/duration/decorators/__init__.py +0 -0
  4. osbot_utils/helpers/duration/decorators/duration.py +21 -0
  5. osbot_utils/{context_managers → helpers/duration/decorators}/print_duration.py +1 -1
  6. osbot_utils/helpers/duration/schemas/Schema__Duration.py +8 -0
  7. osbot_utils/helpers/duration/schemas/__init__.py +0 -0
  8. osbot_utils/helpers/flows/Flow.py +19 -16
  9. osbot_utils/helpers/flows/Task.py +18 -8
  10. osbot_utils/helpers/flows/actions/Flow__Data.py +0 -1
  11. osbot_utils/helpers/flows/actions/Flow__Stats__Collector.py +47 -0
  12. osbot_utils/helpers/flows/actions/Task__Stats__Collector.py +34 -0
  13. osbot_utils/helpers/flows/schemas/Schema__Flow__Stats.py +16 -0
  14. osbot_utils/helpers/flows/schemas/Schema__Flow__Status.py +7 -0
  15. osbot_utils/helpers/flows/schemas/Schema__Task__Stats.py +13 -0
  16. osbot_utils/helpers/ssh/SCP.py +6 -6
  17. osbot_utils/helpers/ssh/SSH__Execute.py +10 -10
  18. osbot_utils/testing/Hook_Method.py +4 -3
  19. osbot_utils/type_safe/shared/Type_Safe__Shared__Variables.py +5 -1
  20. osbot_utils/type_safe/steps/Type_Safe__Step__From_Json.py +9 -4
  21. osbot_utils/version +1 -1
  22. {osbot_utils-2.29.0.dist-info → osbot_utils-2.31.0.dist-info}/METADATA +2 -2
  23. {osbot_utils-2.29.0.dist-info → osbot_utils-2.31.0.dist-info}/RECORD +26 -16
  24. /osbot_utils/{context_managers → helpers/duration/decorators}/capture_duration.py +0 -0
  25. {osbot_utils-2.29.0.dist-info → osbot_utils-2.31.0.dist-info}/LICENSE +0 -0
  26. {osbot_utils-2.29.0.dist-info → osbot_utils-2.31.0.dist-info}/WHEEL +0 -0
@@ -1,32 +1,11 @@
1
- import inspect
2
- from datetime import timedelta
3
- from functools import wraps
1
+ from datetime import timedelta
4
2
 
5
- from osbot_utils.utils.Call_Stack import Call_Stack
3
+ from osbot_utils.helpers.duration.schemas.Schema__Duration import Schema__Duration
4
+ from osbot_utils.utils.Call_Stack import Call_Stack
5
+ from osbot_utils.utils.Misc import date_time_now, time_delta_to_str
6
6
 
7
- from osbot_utils.utils.Misc import date_time_now, time_delta_to_str
8
7
 
9
-
10
- def duration(func):
11
- if inspect.iscoroutinefunction(func):
12
- # It's an async function
13
- @wraps(func)
14
- async def async_wrapper(*args, **kwargs):
15
- with Duration(prefix=f'.{func.__name__} took'):
16
- return await func(*args, **kwargs)
17
- return async_wrapper
18
- else:
19
- # It's a regular function
20
- @wraps(func)
21
- def sync_wrapper(*args, **kwargs):
22
- with Duration(prefix=f'.{func.__name__} took'):
23
- return func(*args, **kwargs)
24
- return sync_wrapper
25
-
26
- class Duration:
27
- """
28
- Helper class for to capture time duration
29
- """
8
+ class Duration: # Helper class for to capture time duration
30
9
  def __init__(self, prefix="\nDuration:", print_result=True, use_utc=True, print_stack=False):
31
10
  self.use_utc = use_utc
32
11
  self.print_result = print_result
@@ -47,6 +26,15 @@ class Duration:
47
26
  def __exit__(self, exception_type, exception_value, exception_traceback):
48
27
  self.end()
49
28
 
29
+ def data(self) -> Schema__Duration: # Returns the duration data in Schema__Duration format.
30
+ if not self.duration:
31
+ raise ValueError("Duration has not been calculated yet. Call end() first.")
32
+
33
+ return Schema__Duration( utc = self.use_utc ,
34
+ timestamp_start = self.start_time.timestamp(),
35
+ timestamp_end = self.end_time .timestamp(),
36
+ duration_seconds = self.seconds ())
37
+
50
38
  def start(self):
51
39
  self.start_time = date_time_now(use_utc=self.use_utc, return_str=False)
52
40
 
File without changes
File without changes
@@ -0,0 +1,21 @@
1
+ import inspect
2
+ from functools import wraps
3
+
4
+ from osbot_utils.helpers.duration.Duration import Duration
5
+
6
+
7
+ def duration(func):
8
+ if inspect.iscoroutinefunction(func):
9
+ # It's an async function
10
+ @wraps(func)
11
+ async def async_wrapper(*args, **kwargs):
12
+ with Duration(prefix=f'.{func.__name__} took'):
13
+ return await func(*args, **kwargs)
14
+ return async_wrapper
15
+ else:
16
+ # It's a regular function
17
+ @wraps(func)
18
+ def sync_wrapper(*args, **kwargs):
19
+ with Duration(prefix=f'.{func.__name__} took'):
20
+ return func(*args, **kwargs)
21
+ return sync_wrapper
@@ -1,4 +1,4 @@
1
- from osbot_utils.context_managers.capture_duration import capture_duration
1
+ from osbot_utils.helpers.duration.decorators.capture_duration import capture_duration
2
2
 
3
3
 
4
4
  class print_duration(capture_duration):
@@ -0,0 +1,8 @@
1
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
2
+
3
+
4
+ class Schema__Duration(Type_Safe):
5
+ utc : bool = True
6
+ timestamp_start : float
7
+ timestamp_end : float
8
+ duration_seconds: float
File without changes
@@ -1,21 +1,21 @@
1
1
  import asyncio
2
2
  import logging
3
3
  import typing
4
-
5
- from osbot_utils.helpers.Dependency_Manager import Dependency_Manager
6
- from osbot_utils.helpers.flows.actions.Flow__Data import Flow__Data
7
- from osbot_utils.helpers.flows.models.Flow_Run__Event import Flow_Run__Event
8
- from osbot_utils.type_safe.Type_Safe import Type_Safe
9
- from osbot_utils.helpers.CFormat import CFormat, f_dark_grey, f_magenta, f_bold
10
- from osbot_utils.helpers.flows.models.Flow_Run__Config import Flow_Run__Config
11
- from osbot_utils.helpers.flows.actions.Flow__Events import flow_events
12
- from osbot_utils.helpers.flows.models.Flow_Run__Event_Data import Flow_Run__Event_Data
13
- from osbot_utils.testing.Stdout import Stdout
14
- from osbot_utils.utils.Dev import pprint
15
- from osbot_utils.utils.Misc import random_id, lower, time_now
16
- from osbot_utils.utils.Python_Logger import Python_Logger
17
- from osbot_utils.utils.Str import ansis_to_texts
18
- from osbot_utils.utils.Threads import invoke_in_new_event_loop
4
+ from osbot_utils.helpers.Dependency_Manager import Dependency_Manager
5
+ from osbot_utils.helpers.flows.actions.Flow__Data import Flow__Data
6
+ from osbot_utils.helpers.flows.actions.Flow__Stats__Collector import Flow__Stats__Collector
7
+ from osbot_utils.helpers.flows.models.Flow_Run__Event import Flow_Run__Event
8
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
9
+ from osbot_utils.helpers.CFormat import CFormat, f_dark_grey, f_magenta, f_bold
10
+ from osbot_utils.helpers.flows.models.Flow_Run__Config import Flow_Run__Config
11
+ from osbot_utils.helpers.flows.actions.Flow__Events import flow_events
12
+ from osbot_utils.helpers.flows.models.Flow_Run__Event_Data import Flow_Run__Event_Data
13
+ from osbot_utils.testing.Stdout import Stdout
14
+ from osbot_utils.utils.Dev import pprint
15
+ from osbot_utils.utils.Misc import random_id, lower, time_now
16
+ from osbot_utils.utils.Python_Logger import Python_Logger
17
+ from osbot_utils.utils.Str import ansis_to_texts
18
+ from osbot_utils.utils.Threads import invoke_in_new_event_loop
19
19
 
20
20
  FLOW__RANDOM_ID__PREFIX = 'flow_id__'
21
21
  FLOW__RANDOM_NAME__PREFIX = 'flow_name__'
@@ -23,9 +23,10 @@ FLOW__LOGGING__LOG_FORMAT = '%(asctime)s.%(msecs)03d | %(levelname)-8s | %(mess
23
23
  FLOW__LOGGING__DATE_FORMAT = '%H:%M:%S'
24
24
 
25
25
 
26
- # todo: add flow duration
26
+ # todo: replace the flow_id (and task_id) with either Obj_Id or Safe_Id
27
27
  class Flow(Type_Safe):
28
28
  flow_data : Flow__Data
29
+ flow_stats : Flow__Stats__Collector
29
30
  captured_exec_logs : list
30
31
  data : dict # dict available to the tasks to add and collect data
31
32
  flow_id : str # rename to flow_run_id (or also capture the flow_run_id)
@@ -82,6 +83,7 @@ class Flow(Type_Safe):
82
83
 
83
84
  def execute_flow(self, flow_run_params=None): # todo: see if it makes more sense to call this start_flow_run
84
85
  self.check_setup()
86
+ self.flow_stats.start(flow_id=self.flow_id, flow_name=self.flow_name) # start the flow stats collector
85
87
  flow_events.on__flow__start(self.flow_event_data())
86
88
  self.log_debug(f"Created flow run '{self.f__flow_id()}' for flow '{self.f__flow_name()}'")
87
89
  self.set_flow_run_params(flow_run_params)
@@ -101,6 +103,7 @@ class Flow(Type_Safe):
101
103
  self.log_error(self.cformat.red(f"Error executing flow: {error}"))
102
104
  self.flow_data.set_error(error)
103
105
 
106
+ self.flow_stats.end (self.flow_error)
104
107
  self.log_captured_stdout (stdout)
105
108
  self.print_flow_return_value ()
106
109
  self.print_flow_finished_message()
@@ -2,14 +2,15 @@ import inspect
2
2
  import traceback
3
3
  import typing
4
4
 
5
- from osbot_utils.helpers.flows.models.Flow_Run__Event_Data import Flow_Run__Event_Data
6
- from osbot_utils.utils.Misc import random_id, lower
7
- from osbot_utils.helpers.Dependency_Manager import Dependency_Manager
8
- from osbot_utils.helpers.flows.actions.Flow__Events import flow_events
9
- from osbot_utils.testing.Stdout import Stdout
10
- from osbot_utils.helpers.CFormat import CFormat, f_dark_grey, f_red, f_blue, f_bold
11
- from osbot_utils.type_safe.Type_Safe import Type_Safe
12
- from osbot_utils.helpers.flows.Flow import Flow
5
+ from osbot_utils.helpers.flows.actions.Task__Stats__Collector import Task__Stats__Collector
6
+ from osbot_utils.helpers.flows.models.Flow_Run__Event_Data import Flow_Run__Event_Data
7
+ from osbot_utils.utils.Misc import random_id, lower
8
+ from osbot_utils.helpers.Dependency_Manager import Dependency_Manager
9
+ from osbot_utils.helpers.flows.actions.Flow__Events import flow_events
10
+ from osbot_utils.testing.Stdout import Stdout
11
+ from osbot_utils.helpers.CFormat import CFormat, f_dark_grey, f_red, f_blue, f_bold
12
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
13
+ from osbot_utils.helpers.flows.Flow import Flow
13
14
 
14
15
  TASK__RANDOM_ID__PREFIX = 'task_id__'
15
16
 
@@ -18,6 +19,7 @@ TASK__RANDOM_ID__PREFIX = 'task_id__'
18
19
  class Task(Type_Safe):
19
20
  data : dict # dict available to the task to add and collect data
20
21
  task_id : str
22
+ task_stats : Task__Stats__Collector
21
23
  task_name : str # make this the function mame
22
24
  cformat : CFormat
23
25
  resolved_args : tuple
@@ -63,6 +65,9 @@ class Task(Type_Safe):
63
65
  if not self.task_id:
64
66
  self.task_id = self.random_task_id()
65
67
 
68
+ execution_order = self.task_flow.flow_stats.get_next_execution_order()
69
+ self.task_stats.start(flow_id=self.task_flow.flow_id, task_id=self.task_id, task_name=self.task_name, execution_order=execution_order)
70
+
66
71
  self.on_task_start()
67
72
  flow_events.on__task__start(self.task_event_data())
68
73
 
@@ -105,6 +110,11 @@ class Task(Type_Safe):
105
110
  self.task_flow.log_captured_stdout(stdout)
106
111
 
107
112
  def execute__after(self):
113
+
114
+ self.task_stats.end(task_error=self.task_error)
115
+ self.task_flow.flow_stats.add_task_stats(self.task_stats.stats)
116
+
117
+
108
118
  self.print_task_return_value()
109
119
 
110
120
  if self.task_error:
@@ -5,7 +5,6 @@ from osbot_utils.helpers.flows.models.Schema__Flow__Artifact import Schema__F
5
5
  from osbot_utils.helpers.flows.models.Schema__Flow__Result import Schema__Flow__Result
6
6
  from osbot_utils.helpers.flows.schemas.Schema__Flow import Schema__Flow
7
7
  from osbot_utils.helpers.flows.schemas.Schema__Flow__Data import Schema__Flow__Data
8
- #from osbot_utils.helpers.flows.schemas.Schema__Flow__Event import Schema__Flow__Event
9
8
  from osbot_utils.helpers.flows.schemas.Schema__Flow__Log import Schema__Flow__Log
10
9
  from osbot_utils.helpers.flows.schemas.Schema__Flow__Task__Data import Schema__Flow__Task__Data
11
10
  from osbot_utils.type_safe.Type_Safe import Type_Safe
@@ -0,0 +1,47 @@
1
+ from typing import Dict
2
+ from osbot_utils.helpers.duration.Duration import Duration
3
+ from osbot_utils.helpers.flows.schemas.Schema__Flow__Status import Schema__Flow__Status
4
+ from osbot_utils.helpers.flows.schemas.Schema__Task__Stats import Schema__Task__Stats
5
+ from osbot_utils.helpers.flows.schemas.Schema__Flow__Stats import Schema__Flow__Stats
6
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
7
+
8
+
9
+ class Flow__Stats__Collector(Type_Safe):
10
+ duration : Duration
11
+ stats : Schema__Flow__Stats
12
+ task_execution_counter : int
13
+
14
+ def start(self, flow_id: str, flow_name:str):
15
+ self.duration.print_result = False
16
+ self.duration.start()
17
+ self.task_execution_counter = 0
18
+ with self.stats as _:
19
+ _.flow_id = flow_id
20
+ _.flow_name = flow_name
21
+ _.status = Schema__Flow__Status.RUNNING
22
+ return self
23
+
24
+ def end(self, flow_error:Exception):
25
+ self.duration.end()
26
+ with self.stats as _:
27
+ _.duration = self.duration.data()
28
+ _.total_tasks = len(self.stats.tasks_stats)
29
+ _.failed_tasks = sum(1 for task in self.stats.tasks_stats.values() if task.status == Schema__Flow__Status.FAILED)
30
+
31
+ if flow_error:
32
+ _.status = Schema__Flow__Status.FAILED
33
+ _.error_message = str(flow_error)
34
+ else:
35
+ _.status = Schema__Flow__Status.COMPLETED
36
+ return self
37
+
38
+ def get_next_execution_order(self): # Get the next execution order number and increment the counter."""
39
+ self.task_execution_counter += 1
40
+ return self.task_execution_counter
41
+
42
+ def add_task_stats(self, task_stats: Schema__Task__Stats): # Add task stats to the collection.
43
+ self.stats.tasks_stats[task_stats.task_id] = task_stats
44
+ return self
45
+
46
+ def json(self): # Return JSON representation of the stats.
47
+ return self.stats.json()
@@ -0,0 +1,34 @@
1
+ from osbot_utils.helpers.duration.Duration import Duration
2
+ from osbot_utils.helpers.flows.schemas.Schema__Flow__Status import Schema__Flow__Status
3
+ from osbot_utils.helpers.flows.schemas.Schema__Task__Stats import Schema__Task__Stats
4
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
5
+
6
+ class Task__Stats__Collector(Type_Safe):
7
+ duration : Duration
8
+ stats : Schema__Task__Stats
9
+
10
+ def start(self, flow_id: str, task_id: str, task_name: str , execution_order:int):
11
+ self.duration.print_result = False
12
+ self.duration.start()
13
+ with self.stats as _:
14
+ _.parent_flow_id = flow_id
15
+ _.execution_order = execution_order
16
+ _.status = Schema__Flow__Status.RUNNING
17
+ _.task_id = task_id
18
+ _.task_name = task_name
19
+ return self
20
+
21
+ def end(self, task_error: Exception):
22
+ self.duration.end()
23
+ with self.stats as _:
24
+ _.duration = self.duration.data()
25
+ if task_error:
26
+ _.status = Schema__Flow__Status.FAILED
27
+ _.error_message = str(task_error)
28
+ else:
29
+ _.status = Schema__Flow__Status.COMPLETED
30
+ return self
31
+
32
+
33
+ def json(self): # Return JSON representation of the stats.
34
+ return self.stats.json()
@@ -0,0 +1,16 @@
1
+ from typing import Dict
2
+ from osbot_utils.helpers.duration.schemas.Schema__Duration import Schema__Duration
3
+ from osbot_utils.helpers.flows.schemas.Schema__Flow__Status import Schema__Flow__Status
4
+ from osbot_utils.helpers.flows.schemas.Schema__Task__Stats import Schema__Task__Stats
5
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
6
+
7
+
8
+ class Schema__Flow__Stats(Type_Safe):
9
+ duration : Schema__Duration # How long the flow took to execute
10
+ error_message: str = None # Error message if flow failed
11
+ failed_tasks : int # Number of failed tasks
12
+ flow_id : str # Unique identifier for the flow
13
+ flow_name : str # Name of the flow
14
+ status : Schema__Flow__Status # 'completed', 'failed', 'running'
15
+ tasks_stats : Dict[str, Schema__Task__Stats] # Map of task_id to task stats
16
+ total_tasks : int # Total number of tasks executed
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+ class Schema__Flow__Status(Enum):
4
+ COMPLETED: str = 'completed'
5
+ FAILED : str = 'failed'
6
+ STOPPED : str = 'stopped'
7
+ RUNNING : str = 'running'
@@ -0,0 +1,13 @@
1
+ from osbot_utils.helpers.duration.schemas.Schema__Duration import Schema__Duration
2
+ from osbot_utils.helpers.flows.schemas.Schema__Flow__Status import Schema__Flow__Status
3
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
4
+
5
+
6
+ class Schema__Task__Stats(Type_Safe):
7
+ task_id : str # Unique identifier for the task
8
+ task_name : str # Name of the task
9
+ execution_order: int # Order in which the task was executed
10
+ duration : Schema__Duration # How long the task took to execute
11
+ status : Schema__Flow__Status # 'completed', 'failed', 'running'
12
+ parent_flow_id : str # ID of the flow that contains this task
13
+ error_message : str = None # Error message if task failed
@@ -1,9 +1,9 @@
1
- from osbot_utils.context_managers.capture_duration import capture_duration
2
- from osbot_utils.helpers.ssh.SSH__Execute import SSH__Execute
3
- from osbot_utils.testing.Temp_Zip import Temp_Zip
4
- from osbot_utils.utils.Files import file_not_exists, file_name
5
- from osbot_utils.utils.Process import start_process
6
- from osbot_utils.utils.Status import status_error
1
+ from osbot_utils.helpers.duration.decorators.capture_duration import capture_duration
2
+ from osbot_utils.helpers.ssh.SSH__Execute import SSH__Execute
3
+ from osbot_utils.testing.Temp_Zip import Temp_Zip
4
+ from osbot_utils.utils.Files import file_not_exists, file_name
5
+ from osbot_utils.utils.Process import start_process
6
+ from osbot_utils.utils.Status import status_error
7
7
 
8
8
 
9
9
 
@@ -1,13 +1,13 @@
1
- from osbot_utils.type_safe.Type_Safe import Type_Safe
2
- from osbot_utils.context_managers.capture_duration import capture_duration
3
- from osbot_utils.decorators.lists.group_by import group_by
4
- from osbot_utils.decorators.lists.index_by import index_by
5
- from osbot_utils.utils.Dev import pprint
6
- from osbot_utils.utils.Env import get_env
7
- from osbot_utils.utils.Http import is_port_open
8
- from osbot_utils.utils.Misc import str_to_int, str_to_bool
9
- from osbot_utils.utils.Process import start_process, run_process
10
- from osbot_utils.utils.Status import status_error
1
+ from osbot_utils.type_safe.Type_Safe import Type_Safe
2
+ from osbot_utils.helpers.duration.decorators.capture_duration import capture_duration
3
+ from osbot_utils.decorators.lists.group_by import group_by
4
+ from osbot_utils.decorators.lists.index_by import index_by
5
+ from osbot_utils.utils.Dev import pprint
6
+ from osbot_utils.utils.Env import get_env
7
+ from osbot_utils.utils.Http import is_port_open
8
+ from osbot_utils.utils.Misc import str_to_int, str_to_bool
9
+ from osbot_utils.utils.Process import start_process, run_process
10
+ from osbot_utils.utils.Status import status_error
11
11
 
12
12
  ENV_VAR__SSH__HOST = 'SSH__HOST'
13
13
  ENV_VAR__SSH__PORT = 'SSH__PORT'
@@ -1,7 +1,8 @@
1
- from osbot_utils.helpers.Print_Table import Print_Table
2
- from osbot_utils.utils.Call_Stack import Call_Stack
1
+ from osbot_utils.helpers.Print_Table import Print_Table
2
+ from osbot_utils.helpers.duration.Duration import Duration
3
+ from osbot_utils.utils.Call_Stack import Call_Stack
4
+
3
5
 
4
- from osbot_utils.testing.Duration import Duration
5
6
 
6
7
  class Hook_Method:
7
8
 
@@ -1,4 +1,8 @@
1
1
  import types
2
2
  from enum import EnumMeta
3
3
 
4
- IMMUTABLE_TYPES = (bool, int, float, complex, str, bytes, types.NoneType, EnumMeta, type)
4
+ from osbot_utils.helpers.Safe_Id import Safe_Id
5
+
6
+ IMMUTABLE_TYPES = (bool, int, float, complex, str, bytes, types.NoneType, EnumMeta, type,
7
+ Safe_Id # ok to add since these classes use str as a base class
8
+ )
@@ -141,9 +141,14 @@ class Type_Safe__Step__From_Json:
141
141
  if key_origin is type:
142
142
  if type(dict_key) is str:
143
143
  dict_key = self.deserialize_type__using_value(dict_key)
144
- expected_dict_type = get_args(key_class)[0]
145
- if dict_key != expected_dict_type and not issubclass(dict_key,expected_dict_type):
146
- raise TypeError(f"Expected {expected_dict_type} class for key but got instance: {dict_key}")
144
+ key_class_args = get_args(key_class)
145
+ if key_class_args:
146
+ expected_dict_type = key_class_args[0]
147
+ if dict_key != expected_dict_type and not issubclass(dict_key,expected_dict_type):
148
+ raise TypeError(f"Expected {expected_dict_type} class for key but got instance: {dict_key}")
149
+ else:
150
+ if not isinstance(dict_key, key_class):
151
+ raise TypeError(f"Expected {key_class} class for key but got instance: {dict_key}")
147
152
  new__dict_key = dict_key
148
153
  elif issubclass(key_class, Type_Safe):
149
154
  new__dict_key = self.deserialize_from_dict(key_class(), dict_key)
@@ -171,7 +176,7 @@ class Type_Safe__Step__From_Json:
171
176
  if type(json_data) is str:
172
177
  json_data = json_parse(json_data)
173
178
  if json_data: # if there is no data or is {} then don't create an object (since this could be caused by bad data being provided)
174
- return self.deserialize_from_dict(_cls(), json_data,raise_on_not_found=raise_on_not_found)
179
+ return self.deserialize_from_dict(_cls(), json_data, raise_on_not_found=raise_on_not_found)
175
180
  return _cls()
176
181
 
177
182
  type_safe_step_from_json = Type_Safe__Step__From_Json()
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v2.29.0
1
+ v2.31.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: osbot_utils
3
- Version: 2.29.0
3
+ Version: 2.31.0
4
4
  Summary: OWASP Security Bot - Utils
5
5
  License: MIT
6
6
  Author: Dinis Cruz
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
23
23
 
24
24
  Powerful Python util methods and classes that simplify common apis and tasks.
25
25
 
26
- ![Current Release](https://img.shields.io/badge/release-v2.29.0-blue)
26
+ ![Current Release](https://img.shields.io/badge/release-v2.31.0-blue)
27
27
  [![codecov](https://codecov.io/gh/owasp-sbot/OSBot-Utils/graph/badge.svg?token=GNVW0COX1N)](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
28
28
 
29
29
 
@@ -5,9 +5,7 @@ osbot_utils/base_classes/Kwargs_To_Self.py,sha256=3LRFpxdg9RBuUlIacF1Bwq014NXtJm
5
5
  osbot_utils/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  osbot_utils/context_managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  osbot_utils/context_managers/async_invoke.py,sha256=-ja3K8orLy8Of54CIYSK-zn443pOIDY2hnFBjVELrXc,829
8
- osbot_utils/context_managers/capture_duration.py,sha256=8ObmbP9_qfYtxx30NGXThRE_E1XZ5IXtX9PHWqtLGfs,1240
9
8
  osbot_utils/context_managers/disable_root_loggers.py,sha256=0-zQk11TBqwhTHCN4vNhDApojtJ4oR0oMPRcwclcXZA,960
10
- osbot_utils/context_managers/print_duration.py,sha256=jleIYxmz-vbWbcZZPuTWMNavJgxYkATwrVk5H-2SHj4,272
11
9
  osbot_utils/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
10
  osbot_utils/decorators/classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
11
  osbot_utils/decorators/classes/singleton.py,sha256=ZBYw2W4Qmo0mlHQQqDJyScaXO6pmbftru9YBBdUowjY,332
@@ -136,11 +134,21 @@ osbot_utils/helpers/cache_requests/Cache__Requests__Row.py,sha256=Sb7E_zDB-LPlWI
136
134
  osbot_utils/helpers/cache_requests/Cache__Requests__Table.py,sha256=BW7tXM0TFYma3Db4M-58IKpx0vevLuFsH7QQeiggPaI,388
137
135
  osbot_utils/helpers/cache_requests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
136
  osbot_utils/helpers/cache_requests/flows/flow__Cache__Requests.py,sha256=xgx_oExxkcvRwQN1UCobimECIMUKGoIX5oGdCmp8Nyw,243
139
- osbot_utils/helpers/flows/Flow.py,sha256=eSqv_pY7vDC1XmX65RyW4swnhQNtMwZXkXnc4De2oc0,13239
140
- osbot_utils/helpers/flows/Task.py,sha256=AQ69b97woemCZxxBxluV5pqOlBU0KW4OpculC5Ix4nw,6605
137
+ osbot_utils/helpers/duration/Duration.py,sha256=KvHaAB6NWa40DXQl2gC9m98gM-arVP-aYqFrmAyQQzM,2306
138
+ osbot_utils/helpers/duration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
139
+ osbot_utils/helpers/duration/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
+ osbot_utils/helpers/duration/decorators/capture_duration.py,sha256=8ObmbP9_qfYtxx30NGXThRE_E1XZ5IXtX9PHWqtLGfs,1240
141
+ osbot_utils/helpers/duration/decorators/duration.py,sha256=ucJP1fCQEN8ALCDCG9CPzPn1KqojD4ttFc3HLke-nvY,651
142
+ osbot_utils/helpers/duration/decorators/print_duration.py,sha256=w7k3OPiRkL5KqLv0S5o1NVo2y_TeOOvDOb-51YbJjAc,283
143
+ osbot_utils/helpers/duration/schemas/Schema__Duration.py,sha256=-h32wBcpiVRkEbc_sZoamnRFNGaQQM4YsxqoVzPGe38,209
144
+ osbot_utils/helpers/duration/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
+ osbot_utils/helpers/flows/Flow.py,sha256=dFjD3czAZDKvcCCk5yeVdpOWCVWvsn5D_q2AnO8340k,13653
146
+ osbot_utils/helpers/flows/Task.py,sha256=RfccOCev5XTsNoKuDJzK1JItF-Lm7P6FGCGZyh9swyY,7116
141
147
  osbot_utils/helpers/flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- osbot_utils/helpers/flows/actions/Flow__Data.py,sha256=h9h5yVFIK0ZdXukNFgfRVV1XW0YQartVMcJTakwVqKY,5155
148
+ osbot_utils/helpers/flows/actions/Flow__Data.py,sha256=rgUggQo_z6KLtNa92KfzRG6ORdT_8ic5zJVuhk_st38,5064
143
149
  osbot_utils/helpers/flows/actions/Flow__Events.py,sha256=g7KBafFeA7tV-v31v_m3MT__cZEX63gh8CehnZwRYU0,2840
150
+ osbot_utils/helpers/flows/actions/Flow__Stats__Collector.py,sha256=GOxXUjDXCQs6cx1BQ9Z_a5KpUI4ztZHaQ-L7-85Ybpc,2276
151
+ osbot_utils/helpers/flows/actions/Task__Stats__Collector.py,sha256=rDYABaHpikIAK0Odleu8-dZ9ECJZYDmgFdd0KvsbByI,1462
144
152
  osbot_utils/helpers/flows/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
153
  osbot_utils/helpers/flows/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
154
  osbot_utils/helpers/flows/decorators/flow.py,sha256=7wj5TtUO_ffbACnagZtZ6LfFgclmbQSfn2lKkMMrnJI,670
@@ -157,7 +165,10 @@ osbot_utils/helpers/flows/schemas/Schema__Flow__Data.py,sha256=cqSreXlumqPnM_DfF
157
165
  osbot_utils/helpers/flows/schemas/Schema__Flow__Event.py,sha256=aeoJotmkYgtEsxyLp6YxoblQFscdAzadI5WOsfYG6-s,616
158
166
  osbot_utils/helpers/flows/schemas/Schema__Flow__Event__Data.py,sha256=ugevIeeNIcXiusQiw8BqXikpl_BXvKZrZLZjYg5J9SQ,567
159
167
  osbot_utils/helpers/flows/schemas/Schema__Flow__Log.py,sha256=OUjnExtlHlDZYQ8o2wLl_oRCUBu7rEoAjX_5__yaRI8,392
168
+ osbot_utils/helpers/flows/schemas/Schema__Flow__Stats.py,sha256=2YeYHTs7rlA5wGt9Jowr0z3b4ZzZF-0GGx_tCSttjOs,1171
169
+ osbot_utils/helpers/flows/schemas/Schema__Flow__Status.py,sha256=3DSUTPqggnJhpHQAtGhiWj8zT2yRbq6MIQk31ap_5ds,181
160
170
  osbot_utils/helpers/flows/schemas/Schema__Flow__Task__Data.py,sha256=BQQvR02n1YAT59I70GT06MBdJbgaDnZBGhaV9Q90oBQ,657
171
+ osbot_utils/helpers/flows/schemas/Schema__Task__Stats.py,sha256=DSja48dPeQPBzzJMtKjJrwEEHb4MqBv0nvm2YC_pTpk,858
161
172
  osbot_utils/helpers/flows/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
162
173
  osbot_utils/helpers/generators/Generator_Context_Manager.py,sha256=STpCn2Zh5G2TmyYMjeLMjfpkSYUUeU6mzV_O6Hu4g4Q,863
163
174
  osbot_utils/helpers/generators/Generator_Manager.py,sha256=XxE7ZZvziorolEM5FoMq-5yOFUi3yVaWcPB_XWHtm30,11728
@@ -233,10 +244,10 @@ osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py,sha256=YwlWj9GYBDeotqD
233
244
  osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py,sha256=4YguiuqzcfTadPWV67lN4IU_8xJzJF--ZRMqbEyzXqw,3800
234
245
  osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py,sha256=GT8h3wD4hGvEtqQuBs0sBbcu2ydktRHTi95PEL2ffHQ,1721
235
246
  osbot_utils/helpers/sqlite/tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
236
- osbot_utils/helpers/ssh/SCP.py,sha256=9PgJbyWKfxJj00Ijaj7o6ffxPXuNoureb6JlHMPbHww,3330
247
+ osbot_utils/helpers/ssh/SCP.py,sha256=pMrb0S3xTFNrJsGLlTe6OnvAWVXiXgVv3Q5VWs_J52I,3396
237
248
  osbot_utils/helpers/ssh/SSH.py,sha256=KPmIewh-ucGqubrwZoZILhX60MCV9UEw8do8JKrZ91s,1542
238
249
  osbot_utils/helpers/ssh/SSH__Cache__Requests.py,sha256=Dqh4biVcuaXbQVvn3Tx-kSGBGHiF-2wVsgu96EhD6gU,3359
239
- osbot_utils/helpers/ssh/SSH__Execute.py,sha256=xmJe7JySTX2TG9TuL_fGFDkz91Yz1TL6ntubE1Myh5Q,6966
250
+ osbot_utils/helpers/ssh/SSH__Execute.py,sha256=Z0W-cgVxwwSwVTBCrycRe6kyTPz19AgpcWmPVxbAO_w,7090
240
251
  osbot_utils/helpers/ssh/SSH__Health_Check.py,sha256=WDmBD6ejNcBeicXfjpsiNzH-WR3Jejx0re3WfwjSWyQ,2083
241
252
  osbot_utils/helpers/ssh/SSH__Linux.py,sha256=O1uyKcklaj2tHqQZln7dVinzjl9-EI52KzP8ojQr244,4330
242
253
  osbot_utils/helpers/ssh/SSH__Linux__Amazon.py,sha256=ZJFb7LFTvclAuhH5OoOtJ361NoX9ecHTaFX-iSmnzmk,596
@@ -269,8 +280,7 @@ osbot_utils/helpers/xml/rss/RSS__Image.py,sha256=13k8K03VTZbP0efeDL07oZF7Lg0CQcc
269
280
  osbot_utils/helpers/xml/rss/RSS__Item.py,sha256=K6YF3EVUu6E-_ISke98QXgnJlfOI5YAIO4pBzUZq7gE,608
270
281
  osbot_utils/testing/Catch.py,sha256=HdNoKnrPBjvVj87XYN-Wa1zpo5z3oByURT6TKbd5QpQ,2229
271
282
  osbot_utils/testing/Custom_Handler_For_Http_Tests.py,sha256=LKscFEcuwTQQ9xl4q71PR5FA8U-q8OtfTkCJoIgQIoQ,5358
272
- osbot_utils/testing/Duration.py,sha256=iBrczAuw6j3jXtG7ZPraT0PXbCILEcCplJbqei96deA,2217
273
- osbot_utils/testing/Hook_Method.py,sha256=uCpc89ZhMCfWiyt3tFhIGIInXiY6wTuwAZ1I8UQVRuw,4365
283
+ osbot_utils/testing/Hook_Method.py,sha256=QoxdbxnVLa4-VYrMCMmo66BoR6nR2BP0Q15asaJXacs,4405
274
284
  osbot_utils/testing/Log_To_Queue.py,sha256=pZQ7I1ne-H365a4WLS60oAD-B16pxIZO4suvCdaTW8U,1703
275
285
  osbot_utils/testing/Log_To_String.py,sha256=hkjWsJfV68uqgX9nvVqUN3mVPxZQDb-6UBwsSEbQnkA,1216
276
286
  osbot_utils/testing/Logging.py,sha256=rzO1cCwty1oTucbV1q6U2QBIF87oOcvZoAY_R8SQB8A,3300
@@ -313,13 +323,13 @@ osbot_utils/type_safe/shared/Type_Safe__Json_Compressor.py,sha256=TDbot_NNzCPXBQ
313
323
  osbot_utils/type_safe/shared/Type_Safe__Json_Compressor__Type_Registry.py,sha256=wYOCg7F1nTrRn8HlnZvrs_8A8WL4gxRYRLnXZpGIiuk,1119
314
324
  osbot_utils/type_safe/shared/Type_Safe__Not_Cached.py,sha256=25FAl6SOLxdStco_rm9tgOYLfuKyBWheGdl7vVa56UU,800
315
325
  osbot_utils/type_safe/shared/Type_Safe__Raise_Exception.py,sha256=pbru8k8CTQMNUfmFBndiJhg2KkqEYzFvJAPcNZHeHfQ,829
316
- osbot_utils/type_safe/shared/Type_Safe__Shared__Variables.py,sha256=SuZGl9LryQX6IpOE0I_lbzClT-h17UNylC__-M8ltTY,129
326
+ osbot_utils/type_safe/shared/Type_Safe__Shared__Variables.py,sha256=A2ztu-9EYjkzrW2NqCl7cdr2ivVl0n9nZXCZHWfl8W4,302
317
327
  osbot_utils/type_safe/shared/Type_Safe__Validation.py,sha256=1oamgApW2Pug0vvTqMLPxBLFvtcnp1bFnjSUByfJBrs,19192
318
328
  osbot_utils/type_safe/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
319
329
  osbot_utils/type_safe/steps/Type_Safe__Step__Class_Kwargs.py,sha256=snoyJKvZ1crgF2fp0zexwNPnV_E63RfyRIsMAZdrKNY,6995
320
330
  osbot_utils/type_safe/steps/Type_Safe__Step__Default_Kwargs.py,sha256=tzKXDUc0HVP5QvCWsmcPuuZodNvQZ9FeMDNI2x00Ngw,1943
321
331
  osbot_utils/type_safe/steps/Type_Safe__Step__Default_Value.py,sha256=K_tkVQyLUbbWYzDnzoPLCgDBAFYyUjAG4VdLsvjzL1g,4485
322
- osbot_utils/type_safe/steps/Type_Safe__Step__From_Json.py,sha256=Be3hZhmQCDKqRBERPfopeDH-re6fyOXM8lRkx5Ndzb8,12757
332
+ osbot_utils/type_safe/steps/Type_Safe__Step__From_Json.py,sha256=mf0HvluDy-TgNiQy-SCdZcG2v3MXP7GHhmsrgyq8WfM,13043
323
333
  osbot_utils/type_safe/steps/Type_Safe__Step__Init.py,sha256=v4FD7zxQiOFLiOF1Ma8wZMP8aLgRlXwJZnsIfBu2zeg,1266
324
334
  osbot_utils/type_safe/steps/Type_Safe__Step__Set_Attr.py,sha256=VuKHH9QEYlbAL9R4zwQ5dwexx2sFY6wMx52QmF7eqcg,5219
325
335
  osbot_utils/type_safe/steps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -355,8 +365,8 @@ osbot_utils/utils/Toml.py,sha256=Rxl8gx7mni5CvBAK-Ai02EKw-GwtJdd3yeHT2kMloik,166
355
365
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
356
366
  osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
357
367
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
358
- osbot_utils/version,sha256=ON8CcGgOzXQTBlj0GoLWU4kJJ4NSmn3tfF8hCE1vYZ4,8
359
- osbot_utils-2.29.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
360
- osbot_utils-2.29.0.dist-info/METADATA,sha256=bP7-jWt9xctBc_Fa8lXhfnqxaWkMYRCAK6zwNCxx_Sg,1329
361
- osbot_utils-2.29.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
362
- osbot_utils-2.29.0.dist-info/RECORD,,
368
+ osbot_utils/version,sha256=HCRke6XnsWX14IEkvcnr363MBi6BbkbVDkvEZXWN1Dg,8
369
+ osbot_utils-2.31.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
370
+ osbot_utils-2.31.0.dist-info/METADATA,sha256=cA1LigYUC3D4O8kl4ofRRahn_BQ0MwTtvIIbPSSwf3k,1329
371
+ osbot_utils-2.31.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
372
+ osbot_utils-2.31.0.dist-info/RECORD,,