osbot-utils 1.17.0__py3-none-any.whl → 1.20.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.
- osbot_utils/base_classes/Kwargs_To_Self.py +3 -54
- osbot_utils/base_classes/Type_Safe.py +6 -0
- osbot_utils/context_managers/disable_root_loggers.py +30 -0
- osbot_utils/helpers/CFormat.py +147 -0
- osbot_utils/helpers/CPrint.py +5 -50
- osbot_utils/helpers/Print_Table.py +1 -1
- osbot_utils/helpers/cache_requests/Cache__Requests__Actions.py +23 -0
- osbot_utils/helpers/cache_requests/Cache__Requests__Config.py +32 -0
- osbot_utils/helpers/cache_requests/Cache__Requests__Data.py +105 -0
- osbot_utils/helpers/cache_requests/Cache__Requests__Invoke.py +55 -0
- osbot_utils/helpers/cache_requests/Cache__Requests__Row.py +64 -0
- osbot_utils/helpers/cache_requests/Cache__Requests__Table.py +16 -0
- osbot_utils/helpers/cache_requests/__init__.py +0 -0
- osbot_utils/helpers/cache_requests/flows/flow__Cache__Requests.py +11 -0
- osbot_utils/helpers/flows/Flow.py +145 -0
- osbot_utils/helpers/flows/Task.py +18 -0
- osbot_utils/helpers/flows/__init__.py +0 -0
- osbot_utils/helpers/sqlite/{domains/schemas → cache}/Schema__Table__Requests.py +6 -4
- osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests.py +104 -0
- osbot_utils/helpers/sqlite/{domains → cache}/Sqlite__Cache__Requests__Patch.py +10 -8
- osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Sqlite.py +18 -0
- osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Table.py +48 -0
- osbot_utils/helpers/sqlite/{domains → cache}/Sqlite__DB__Requests.py +8 -7
- osbot_utils/helpers/sqlite/cache/TestCase__Sqlite__Cache__Requests.py +35 -0
- osbot_utils/helpers/sqlite/cache/__init__.py +0 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +6 -2
- osbot_utils/helpers/{SCP.py → ssh/SCP.py} +23 -20
- osbot_utils/helpers/ssh/SSH.py +30 -0
- osbot_utils/helpers/ssh/SSH__Cache__Requests.py +66 -0
- osbot_utils/helpers/ssh/SSH__Execute.py +158 -0
- osbot_utils/helpers/ssh/SSH__Health_Check.py +49 -0
- osbot_utils/helpers/ssh/SSH__Linux.py +106 -0
- osbot_utils/helpers/ssh/SSH__Python.py +48 -0
- osbot_utils/helpers/ssh/TestCase__SSH.py +50 -0
- osbot_utils/helpers/ssh/__init__.py +0 -0
- osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +1 -1
- osbot_utils/testing/Logging.py +15 -5
- osbot_utils/testing/Pytest.py +18 -0
- osbot_utils/utils/Env.py +27 -9
- osbot_utils/utils/Json.py +2 -9
- osbot_utils/utils/Misc.py +16 -18
- osbot_utils/utils/Objects.py +17 -7
- osbot_utils/utils/Python_Logger.py +54 -38
- osbot_utils/utils/Str.py +20 -3
- osbot_utils/utils/Toml.py +33 -0
- osbot_utils/version +1 -1
- {osbot_utils-1.17.0.dist-info → osbot_utils-1.20.0.dist-info}/METADATA +2 -2
- {osbot_utils-1.17.0.dist-info → osbot_utils-1.20.0.dist-info}/RECORD +50 -23
- osbot_utils/helpers/SSH.py +0 -172
- osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests.py +0 -214
- {osbot_utils-1.17.0.dist-info → osbot_utils-1.20.0.dist-info}/LICENSE +0 -0
- {osbot_utils-1.17.0.dist-info → osbot_utils-1.20.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
import logging
|
2
|
+
import typing
|
3
|
+
from functools import wraps
|
4
|
+
|
5
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
6
|
+
from osbot_utils.helpers.CFormat import CFormat, f_dark_grey, f_magenta
|
7
|
+
from osbot_utils.testing.Stdout import Stdout
|
8
|
+
from osbot_utils.utils.Misc import random_id, lower
|
9
|
+
from osbot_utils.utils.Python_Logger import Python_Logger
|
10
|
+
from osbot_utils.utils.Str import ansis_to_texts
|
11
|
+
|
12
|
+
FLOW__RANDOM_ID__PREFIX = 'flow_id__'
|
13
|
+
FLOW__RANDOM_NAME__PREFIX = 'flow_name__'
|
14
|
+
FLOW__LOGGING__LOG_FORMAT = '%(asctime)s.%(msecs)03d | %(levelname)-8s | %(message)s'
|
15
|
+
FLOW__LOGGING__DATE_FORMAT = '%H:%M:%S'
|
16
|
+
|
17
|
+
def flow(**flow_kwargs):
|
18
|
+
|
19
|
+
def decorator(function):
|
20
|
+
@wraps(function)
|
21
|
+
def wrapper(*args, **kwargs):
|
22
|
+
with Flow(**flow_kwargs) as flow:
|
23
|
+
flow.set_flow_target(function)
|
24
|
+
flow.setup()
|
25
|
+
flow.create_flow()
|
26
|
+
flow.execute_flow(*args, **kwargs)
|
27
|
+
return flow.return_value
|
28
|
+
|
29
|
+
return wrapper
|
30
|
+
return decorator
|
31
|
+
|
32
|
+
|
33
|
+
class Flow(Type_Safe):
|
34
|
+
captured_exec_logs : list
|
35
|
+
flow_id : str
|
36
|
+
flow_name : str
|
37
|
+
flow_target : callable
|
38
|
+
logger : Python_Logger
|
39
|
+
cformat : CFormat
|
40
|
+
log_to_console : bool = False
|
41
|
+
log_to_memory : bool = True
|
42
|
+
print_logs : bool = False
|
43
|
+
return_value : typing.Any
|
44
|
+
|
45
|
+
|
46
|
+
def config_logger(self):
|
47
|
+
with self.logger as _:
|
48
|
+
_.set_log_level(logging.DEBUG)
|
49
|
+
_.set_log_format(log_format=FLOW__LOGGING__LOG_FORMAT, date_format=FLOW__LOGGING__DATE_FORMAT)
|
50
|
+
if self.log_to_console:
|
51
|
+
_.add_console_logger()
|
52
|
+
|
53
|
+
|
54
|
+
def debug(self, message):
|
55
|
+
self.logger.debug(message)
|
56
|
+
|
57
|
+
def create_flow(self):
|
58
|
+
self.set_flow_name()
|
59
|
+
self.debug(f"Created flow run '{self.f__flow_id()}' for flow '{self.f__flow_name()}'")
|
60
|
+
|
61
|
+
def execute_flow(self, *args, **kwargs):
|
62
|
+
if self.log_to_memory:
|
63
|
+
self.logger.add_memory_logger() # todo: move to method that does pre-execute tasks
|
64
|
+
|
65
|
+
self.debug(f"Executing flow run '{self.f__flow_id()}''")
|
66
|
+
try:
|
67
|
+
with Stdout() as stdout:
|
68
|
+
self.return_value = self.flow_target(*args, **kwargs) # todo, capture *args, **kwargs in logs
|
69
|
+
except Exception as error:
|
70
|
+
self.logger.error(self.cformat.red(f"Error executing flow: {error}"))
|
71
|
+
self.log_captured_stdout(stdout)
|
72
|
+
self.debug(f"{f_dark_grey('return value')}: {self.return_value}")
|
73
|
+
self.debug(f"Finished flow run '{self.f__flow_id()}''")
|
74
|
+
|
75
|
+
if self.log_to_memory:
|
76
|
+
self.captured_exec_logs = self.log_messages_with_colors()
|
77
|
+
self.logger.remove_memory_logger() # todo: move to method that does post-execute tasks
|
78
|
+
|
79
|
+
def f__flow_id(self):
|
80
|
+
return self.cformat.green(self.flow_id)
|
81
|
+
|
82
|
+
def f__flow_name(self):
|
83
|
+
return self.cformat.blue(self.flow_name)
|
84
|
+
|
85
|
+
def info(self, message):
|
86
|
+
self.logger.info(message)
|
87
|
+
|
88
|
+
def log_captured_stdout(self, stdout):
|
89
|
+
for line in stdout.value().splitlines():
|
90
|
+
if line:
|
91
|
+
self.info(f_magenta(line))
|
92
|
+
if self.print_logs:
|
93
|
+
print()
|
94
|
+
print()
|
95
|
+
self.print_log_messages()
|
96
|
+
|
97
|
+
|
98
|
+
def log_messages(self):
|
99
|
+
return ansis_to_texts(self.log_messages_with_colors())
|
100
|
+
|
101
|
+
def log_messages_with_colors(self):
|
102
|
+
return self.logger.memory_handler_messages()
|
103
|
+
|
104
|
+
def print_log_messages(self, use_colors=True):
|
105
|
+
if use_colors:
|
106
|
+
for message in self.logger.memory_handler_messages():
|
107
|
+
print(message)
|
108
|
+
else:
|
109
|
+
for message in self.log_messages():
|
110
|
+
print(message)
|
111
|
+
return self
|
112
|
+
def random_flow_id(self):
|
113
|
+
return lower(random_id(prefix=FLOW__RANDOM_ID__PREFIX))
|
114
|
+
|
115
|
+
def random_flow_name(self):
|
116
|
+
return lower(random_id(prefix=FLOW__RANDOM_NAME__PREFIX))
|
117
|
+
|
118
|
+
|
119
|
+
def set_flow_target(self, target):
|
120
|
+
self.flow_target = target
|
121
|
+
return self
|
122
|
+
|
123
|
+
def set_flow_name(self, value=None):
|
124
|
+
if value:
|
125
|
+
self.flow_name = value
|
126
|
+
else:
|
127
|
+
if not self.flow_name:
|
128
|
+
if hasattr(self.flow_target, '__name__'):
|
129
|
+
self.flow_name = self.flow_target.__name__
|
130
|
+
else:
|
131
|
+
self.flow_name = self.random_flow_name()
|
132
|
+
def setup(self):
|
133
|
+
with self as _:
|
134
|
+
_.cformat.auto_bold = True
|
135
|
+
_.config_logger()
|
136
|
+
_.setup_flow_run()
|
137
|
+
return self
|
138
|
+
|
139
|
+
def setup_flow_run(self):
|
140
|
+
with self as _:
|
141
|
+
if not _.flow_id:
|
142
|
+
_.flow_id = self.random_flow_id()
|
143
|
+
#if not _.flow_name:
|
144
|
+
# _.flow_name = self.flow_target.__name__
|
145
|
+
#self.random_flow_name()
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import inspect
|
2
|
+
|
3
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
4
|
+
from osbot_utils.helpers.flows.Flow import Flow
|
5
|
+
|
6
|
+
|
7
|
+
class Task(Type_Safe):
|
8
|
+
task_id : str
|
9
|
+
task_name : str
|
10
|
+
|
11
|
+
def find_flow(self):
|
12
|
+
stack = inspect.stack()
|
13
|
+
for frame_info in stack:
|
14
|
+
frame = frame_info.frame
|
15
|
+
if 'self' in frame.f_locals:
|
16
|
+
instance = frame.f_locals['self']
|
17
|
+
if type(instance) is Flow:
|
18
|
+
return instance
|
File without changes
|
@@ -1,12 +1,14 @@
|
|
1
1
|
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
2
2
|
|
3
3
|
class Schema__Table__Requests(Kwargs_To_Self):
|
4
|
+
comments : str
|
5
|
+
metadata : str
|
6
|
+
request_type : str
|
4
7
|
request_hash : str
|
5
8
|
request_data : str
|
9
|
+
response_bytes: bytes
|
6
10
|
response_hash : str
|
7
11
|
response_data : str
|
8
|
-
|
9
|
-
|
12
|
+
response_type : str
|
13
|
+
source : str
|
10
14
|
timestamp : int
|
11
|
-
latest : bool # todo: add native bool support to sqlite
|
12
|
-
comments : str
|
@@ -0,0 +1,104 @@
|
|
1
|
+
import types
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Actions import Cache__Requests__Actions
|
4
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Config import Cache__Requests__Config
|
5
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Data import Cache__Requests__Data
|
6
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Invoke import Cache__Requests__Invoke
|
7
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Row import Cache__Requests__Row
|
8
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__Cache__Requests__Table import Sqlite__Cache__Requests__Table
|
9
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__Cache__Requests__Sqlite import Sqlite__Cache__Requests__Sqlite
|
10
|
+
|
11
|
+
|
12
|
+
class Sqlite__Cache__Requests(Type_Safe):
|
13
|
+
db_path : None
|
14
|
+
db_name : None
|
15
|
+
table_name : None
|
16
|
+
|
17
|
+
def __init__(self, **kwargs):
|
18
|
+
super().__init__(**kwargs)
|
19
|
+
|
20
|
+
# todo refactor this whole section to a DI (DependencyInjection / Type_Registry class, which is the one responsible for creating these objects in the right order of dependency)
|
21
|
+
|
22
|
+
self.cache_config = Cache__Requests__Config()
|
23
|
+
self.config = self.cache_config
|
24
|
+
|
25
|
+
kwargs__cache_sqlite = dict(config=self.cache_config, db_path=self.db_path, db_name=self.db_name, table_name=self.table_name)
|
26
|
+
self.cache_sqlite = Sqlite__Cache__Requests__Sqlite (**kwargs__cache_sqlite)
|
27
|
+
self.sqlite_requests = self.cache_sqlite.sqlite_requests
|
28
|
+
|
29
|
+
#self.cache_table = self.cache_sqlite.cache_table
|
30
|
+
self.cache_table = Sqlite__Cache__Requests__Table(cache_table=self.cache_sqlite.cache_table())
|
31
|
+
|
32
|
+
|
33
|
+
kwargs__cache_table = dict( cache_table = self.cache_table )
|
34
|
+
|
35
|
+
kwargs__cache_data = dict(**kwargs__cache_table, cache_request_data = self.cache_request_data ,
|
36
|
+
config = self.cache_config )
|
37
|
+
self.cache_data = Cache__Requests__Data(**kwargs__cache_data)
|
38
|
+
|
39
|
+
kwargs__cache_row = dict(**kwargs__cache_table, config = self.cache_config )
|
40
|
+
self.cache_row = Cache__Requests__Row (**kwargs__cache_row )
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
kwargs__cache_actions = dict(**kwargs__cache_table, cache_row=self.cache_row)
|
45
|
+
self.cache_actions = Cache__Requests__Actions(**kwargs__cache_actions )
|
46
|
+
|
47
|
+
kwargs__cache_invoke = dict(cache_data = self.cache_data ,
|
48
|
+
cache_actions = self.cache_actions ,
|
49
|
+
config = self.cache_config )
|
50
|
+
self.cache_invoke = Cache__Requests__Invoke(**kwargs__cache_invoke)
|
51
|
+
|
52
|
+
self.apply_refactoring_patches()
|
53
|
+
|
54
|
+
def apply_refactoring_patches(self):
|
55
|
+
self.cache_add = self.cache_actions.cache_add
|
56
|
+
self.cache_delete = self.cache_actions.cache_delete
|
57
|
+
self.create_new_cache_row_data = self.cache_actions.create_new_cache_row_data
|
58
|
+
|
59
|
+
self.cache_entries = self.cache_data.cache_entries
|
60
|
+
self.cache_entry = self.cache_data.cache_entry
|
61
|
+
self.cache_entry_comments = self.cache_data.cache_entry_comments
|
62
|
+
self.cache_entry_comments_update = self.cache_data.cache_entry_comments_update
|
63
|
+
self.cache_entry_for_request_params = self.cache_data.cache_entry_for_request_params
|
64
|
+
self.response_data_for__request_hash = self.cache_data.response_data_for__request_hash
|
65
|
+
self.response_data__all = self.cache_data.response_data__all
|
66
|
+
self.response_data_deserialize = self.cache_data.response_data_deserialize
|
67
|
+
self.response_data_serialize = self.cache_data.response_data_serialize
|
68
|
+
|
69
|
+
self.create_new_cache_obj = self.cache_row.create_new_cache_obj
|
70
|
+
|
71
|
+
self.cache_table__clear = self.cache_table.cache_table__clear
|
72
|
+
self.delete_where_request_data = self.cache_table.delete_where_request_data
|
73
|
+
self.rows_where = self.cache_table.rows_where
|
74
|
+
self.rows_where__request_data = self.cache_table.rows_where__request_data
|
75
|
+
self.rows_where__request_hash = self.cache_table.rows_where__request_hash
|
76
|
+
|
77
|
+
self.disable = self.cache_config.disable
|
78
|
+
self.enable = self.cache_config.enable
|
79
|
+
self.only_from_cache = self.cache_config.only_from_cache
|
80
|
+
self.update = self.cache_config.update
|
81
|
+
self.set__add_timestamp = self.cache_config.set__add_timestamp
|
82
|
+
|
83
|
+
self.invoke = self.cache_invoke.invoke
|
84
|
+
self.invoke_target = self.cache_invoke.invoke_target
|
85
|
+
#self.invoke_with_cache = self.cache_invoke.invoke_with_cache
|
86
|
+
self.invoke_target__and_add_to_cache = self.cache_invoke.invoke_target__and_add_to_cache
|
87
|
+
self.transform_raw_response = self.cache_invoke.transform_raw_response
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
# FOR NOW: these methods cannot be refactored
|
92
|
+
|
93
|
+
# this is the method that is current overwritten to create custom request data
|
94
|
+
def cache_request_data(self, *args, **target_kwargs):
|
95
|
+
return {'args': list(args), 'kwargs': target_kwargs} # convert the args tuple to a list since that is what it will be once it is serialised
|
96
|
+
|
97
|
+
def invoke_with_cache(self, *args, **target_kwargs):
|
98
|
+
return self.cache_invoke.invoke_with_cache(*args, **target_kwargs)
|
99
|
+
|
100
|
+
def set_on_invoke_target(self, on_invoke_target : types.FunctionType):
|
101
|
+
self.cache_invoke.on_invoke_target = on_invoke_target
|
102
|
+
|
103
|
+
def requests_data__all(self): # currently overwritten by Bedrock__Cache
|
104
|
+
return self.cache_data.requests_data__all()
|
@@ -1,20 +1,19 @@
|
|
1
1
|
import types
|
2
2
|
|
3
|
-
from osbot_utils.helpers.sqlite.
|
4
|
-
from osbot_utils.utils.
|
5
|
-
from osbot_utils.utils.Misc import random_text
|
3
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__Cache__Requests import Sqlite__Cache__Requests
|
4
|
+
from osbot_utils.utils.Misc import random_text
|
6
5
|
|
7
6
|
|
8
7
|
class Sqlite__Cache__Requests__Patch(Sqlite__Cache__Requests):
|
9
|
-
db_name : str
|
10
|
-
table_name : str
|
11
|
-
pickle_response : bool = True
|
8
|
+
db_name : str #= random_text('requests_cache_')
|
9
|
+
table_name : str #= random_text('requests_table_') # todo : remove this so that we default to an in memory db
|
12
10
|
target_function : types.FunctionType
|
13
11
|
target_class : object
|
14
12
|
target_function_name: str
|
15
13
|
|
16
|
-
def __init__(self, db_path=None):
|
17
|
-
super().__init__(db_path=db_path, db_name=
|
14
|
+
def __init__(self, db_name=None, table_name=None, db_path=None):
|
15
|
+
super().__init__(db_path=db_path, db_name=db_name, table_name=table_name)
|
16
|
+
self.cache_config.pickle_response = True
|
18
17
|
|
19
18
|
def __enter__(self):
|
20
19
|
self.patch_apply()
|
@@ -24,6 +23,9 @@ class Sqlite__Cache__Requests__Patch(Sqlite__Cache__Requests):
|
|
24
23
|
self.patch_restore()
|
25
24
|
return
|
26
25
|
|
26
|
+
def database(self):
|
27
|
+
return self.cache_table.database
|
28
|
+
|
27
29
|
def delete(self):
|
28
30
|
return self.sqlite_requests.delete()
|
29
31
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
2
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Config import Cache__Requests__Config
|
3
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__DB__Requests import Sqlite__DB__Requests
|
4
|
+
|
5
|
+
|
6
|
+
class Sqlite__Cache__Requests__Sqlite(Type_Safe):
|
7
|
+
sqlite_requests : Sqlite__DB__Requests = None
|
8
|
+
config : Cache__Requests__Config
|
9
|
+
db_path : str
|
10
|
+
db_name : str
|
11
|
+
table_name : str
|
12
|
+
def __init__(self, **kwargs):
|
13
|
+
super().__init__(**kwargs)
|
14
|
+
self.sqlite_requests = Sqlite__DB__Requests(db_path=self.db_path, db_name=self.db_name, table_name=self.table_name)
|
15
|
+
|
16
|
+
def cache_table(self):
|
17
|
+
return self.sqlite_requests.table_requests()
|
18
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from osbot_utils.helpers.cache_requests.Cache__Requests__Table import Cache__Requests__Table
|
2
|
+
from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
|
3
|
+
from osbot_utils.utils.Json import json_dumps
|
4
|
+
|
5
|
+
|
6
|
+
class Sqlite__Cache__Requests__Table(Cache__Requests__Table):
|
7
|
+
cache_table : Sqlite__Table
|
8
|
+
|
9
|
+
def __init__(self, **kwargs):
|
10
|
+
super().__init__( **kwargs)
|
11
|
+
|
12
|
+
self.table_name = self.cache_table.table_name
|
13
|
+
self._table_create = self.cache_table._table_create
|
14
|
+
self.database = self.cache_table.database
|
15
|
+
self.clear = self.cache_table.clear
|
16
|
+
self.exists = self.cache_table.exists
|
17
|
+
self.indexes = self.cache_table.indexes
|
18
|
+
self.new_row_obj = self.cache_table.new_row_obj
|
19
|
+
self.row_add_and_commit = self.cache_table.row_add_and_commit
|
20
|
+
self.row_update = self.cache_table.row_update
|
21
|
+
self.row_schema = self.cache_table.row_schema
|
22
|
+
self.rows = self.cache_table.rows
|
23
|
+
self.rows_delete_where = self.cache_table.rows_delete_where
|
24
|
+
self.schema__by_name_type = self.cache_table.schema__by_name_type
|
25
|
+
self.select_rows_where = self.cache_table.select_rows_where
|
26
|
+
self.size = self.cache_table.size
|
27
|
+
|
28
|
+
def cache_table__clear(self):
|
29
|
+
return self.cache_table.clear()
|
30
|
+
|
31
|
+
def delete_where_request_data(self, request_data): # todo: check if it is ok to use the request_data as a query target, or if we should use the request_hash variable
|
32
|
+
if type(request_data) is dict: # if we get an request_data obj
|
33
|
+
request_data = json_dumps(request_data) # convert it to the json dump
|
34
|
+
if type(request_data) is str: # make sure we have a string
|
35
|
+
if len(self.rows_where__request_data(request_data)) > 0: # make sure there is at least one entry to delete
|
36
|
+
self.cache_table.rows_delete_where(request_data=request_data) # delete it
|
37
|
+
return len(self.rows_where__request_data(request_data)) == 0 # confirm it was deleted
|
38
|
+
return False # if anything was not right, return False
|
39
|
+
|
40
|
+
def rows_where(self, **kwargs):
|
41
|
+
return self.cache_table.select_rows_where(**kwargs)
|
42
|
+
|
43
|
+
def rows_where__request_data(self, request_data):
|
44
|
+
return self.rows_where(request_data=request_data)
|
45
|
+
|
46
|
+
def rows_where__request_hash(self, request_hash):
|
47
|
+
return self.rows_where(request_hash=request_hash)
|
48
|
+
|
@@ -1,7 +1,6 @@
|
|
1
|
-
from osbot_utils.decorators.methods.cache_on_self
|
2
|
-
from osbot_utils.helpers.sqlite.domains.Sqlite__DB__Local
|
3
|
-
from osbot_utils.helpers.sqlite.
|
4
|
-
from osbot_utils.utils.Misc import random_text
|
1
|
+
from osbot_utils.decorators.methods.cache_on_self import cache_on_self
|
2
|
+
from osbot_utils.helpers.sqlite.domains.Sqlite__DB__Local import Sqlite__DB__Local
|
3
|
+
from osbot_utils.helpers.sqlite.cache.Schema__Table__Requests import Schema__Table__Requests
|
5
4
|
|
6
5
|
SQLITE_TABLE__REQUESTS = 'requests'
|
7
6
|
|
@@ -12,11 +11,13 @@ class Sqlite__DB__Requests(Sqlite__DB__Local):
|
|
12
11
|
def __init__(self,db_path=None, db_name=None, table_name=None):
|
13
12
|
self.table_name = table_name or SQLITE_TABLE__REQUESTS
|
14
13
|
self.table_schema = Schema__Table__Requests
|
15
|
-
|
16
|
-
|
17
|
-
# self.table_name = 'temp_table'
|
14
|
+
in_memory = not (db_path or db_name)
|
15
|
+
super().__init__(db_path=db_path, db_name=db_name, in_memory=in_memory)
|
18
16
|
self.setup()
|
19
17
|
|
18
|
+
def __repr__(self):
|
19
|
+
return f'{self.__class__.__name__} [ db_name={self.db_name} | table_name={self.table_name} | in_memory={self.in_memory} ]'
|
20
|
+
|
20
21
|
@cache_on_self
|
21
22
|
def table_requests(self):
|
22
23
|
return self.table(self.table_name)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from unittest import TestCase
|
2
|
+
|
3
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__Cache__Requests import Sqlite__Cache__Requests
|
4
|
+
from osbot_utils.utils.Misc import random_text
|
5
|
+
|
6
|
+
|
7
|
+
class TestCase__Sqlite__Cache__Requests(TestCase):
|
8
|
+
sqlite_cache_requests : Sqlite__Cache__Requests
|
9
|
+
|
10
|
+
@classmethod
|
11
|
+
def setUpClass(cls):
|
12
|
+
cls.sqlite_cache_requests = Sqlite__Cache__Requests()
|
13
|
+
cls.sqlite_cache_requests.set__add_timestamp(False) # disabling timestamp since it complicates the test data verification below
|
14
|
+
assert cls.sqlite_cache_requests.sqlite_requests.in_memory is True # confirm we have an in-memory db
|
15
|
+
|
16
|
+
def tearDown(self):
|
17
|
+
self.sqlite_cache_requests.cache_table.clear()
|
18
|
+
|
19
|
+
def add_test_requests(self, count=10):
|
20
|
+
def invoke_target(*args, **target_kwargs):
|
21
|
+
return {'type' : 'response' ,
|
22
|
+
'source' : 'add_test_requests.invoke_target',
|
23
|
+
'request_args' : args ,
|
24
|
+
'request_kwargs': target_kwargs }
|
25
|
+
|
26
|
+
for i in range(count):
|
27
|
+
an_key = random_text('an_key')
|
28
|
+
an_dict = {'the': random_text('random_request')}
|
29
|
+
target = invoke_target
|
30
|
+
target_args = ['abc']
|
31
|
+
target_kwargs = {'an_key': an_key, 'an_dict': an_dict}
|
32
|
+
response = self.sqlite_cache_requests.invoke(target, target_args, target_kwargs)
|
33
|
+
# todo add comments to the entry
|
34
|
+
#self.sqlite_cache_requests.cache_entry_comments_update()
|
35
|
+
#pprint(response)
|
File without changes
|
@@ -9,10 +9,14 @@ ENV_NAME_PATH_LOCAL_DBS = 'PATH_LOCAL_DBS'
|
|
9
9
|
class Sqlite__DB__Local(Sqlite__Database):
|
10
10
|
db_name: str
|
11
11
|
|
12
|
-
def __init__(self, db_path=None, db_name=None):
|
12
|
+
def __init__(self, db_path=None, db_name=None, in_memory=False):
|
13
|
+
|
13
14
|
if hasattr(self, 'db_name') is False:
|
14
15
|
self.db_name = db_name or random_text('db_local') + '.sqlite'
|
15
|
-
|
16
|
+
if in_memory:
|
17
|
+
super().__init__()
|
18
|
+
else:
|
19
|
+
super().__init__(db_path=db_path or self.path_local_db()) # todo: add option to run this in memory, without creating a temp file
|
16
20
|
|
17
21
|
def path_db_folder(self):
|
18
22
|
return environ.get(ENV_NAME_PATH_LOCAL_DBS) or current_temp_folder()
|
@@ -1,14 +1,13 @@
|
|
1
|
-
from osbot_utils.context_managers.capture_duration
|
2
|
-
from osbot_utils.helpers.
|
3
|
-
from osbot_utils.testing.Temp_Zip
|
4
|
-
from osbot_utils.utils.
|
5
|
-
from osbot_utils.utils.
|
6
|
-
from osbot_utils.utils.
|
7
|
-
from osbot_utils.utils.Status import status_error
|
8
|
-
from osbot_utils.utils.Zip import zip_folder
|
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
|
9
7
|
|
10
8
|
|
11
|
-
|
9
|
+
|
10
|
+
class SCP(SSH__Execute):
|
12
11
|
|
13
12
|
def copy_file_to_host(self, local_file, host_file=None):
|
14
13
|
if file_not_exists(local_file):
|
@@ -31,20 +30,24 @@ class SCP(SSH):
|
|
31
30
|
if file_not_exists(local_folder):
|
32
31
|
return status_error(error="in copy_folder_as_zip_to_host, local_folder provided doesn't exist in current host", data={'local_folder':local_folder})
|
33
32
|
with Temp_Zip(target=local_folder) as temp_zip:
|
34
|
-
host_file
|
35
|
-
kwargs
|
36
|
-
|
37
|
-
|
38
|
-
self.
|
39
|
-
|
40
|
-
self.execute_command(
|
41
|
-
self.rm(host_file)
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
host_file = temp_zip.file_name()
|
34
|
+
kwargs = dict(local_file = temp_zip.path(),
|
35
|
+
host_file = host_file )
|
36
|
+
command_unzip = f'unzip {host_file} -d {unzip_to_folder}'
|
37
|
+
result_ssh_mkdir = self.mkdir(unzip_to_folder)
|
38
|
+
result_scp_zip = self.copy_file_to_host(**kwargs)
|
39
|
+
result_ssh_unzip = self.execute_command(command_unzip)
|
40
|
+
result_rm_zip = self.rm(host_file)
|
41
|
+
return dict(result_ssh_mkdir=result_ssh_mkdir ,
|
42
|
+
result_scp_zip =result_scp_zip ,
|
43
|
+
result_ssh_unzip=result_ssh_unzip ,
|
44
|
+
result_rm_zip =result_rm_zip )
|
45
45
|
|
46
46
|
def execute_scp_command(self, scp_args):
|
47
47
|
if self.ssh_host and self.ssh_key_file and self.ssh_key_user and scp_args:
|
48
|
+
if scp_args[0] == '-p': # todo refactor this to a better method/class to create the ssh and scp args
|
49
|
+
scp_args[0] = '-P' # this hack is to handle the fact that ssh and scp use different flags for the port!! WTF!! :)
|
50
|
+
|
48
51
|
with capture_duration() as duration:
|
49
52
|
result = start_process("scp", scp_args) # execute scp command using subprocess.run(...)
|
50
53
|
result['duration'] = duration.data()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
2
|
+
from osbot_utils.decorators.methods.cache_on_self import cache_on_self
|
3
|
+
from osbot_utils.helpers.ssh.SCP import SCP
|
4
|
+
from osbot_utils.helpers.ssh.SSH__Execute import SSH__Execute
|
5
|
+
from osbot_utils.helpers.ssh.SSH__Linux import SSH__Linux
|
6
|
+
from osbot_utils.helpers.ssh.SSH__Python import SSH__Python
|
7
|
+
|
8
|
+
class SSH(Kwargs_To_Self):
|
9
|
+
|
10
|
+
def setup(self):
|
11
|
+
self.ssh_execute().setup()
|
12
|
+
return self
|
13
|
+
|
14
|
+
@cache_on_self
|
15
|
+
def scp(self):
|
16
|
+
kwargs = self.ssh_execute().__locals__() # get the current ssh config details
|
17
|
+
scp = SCP(**kwargs) # use it in the ctor of SCP
|
18
|
+
return scp
|
19
|
+
|
20
|
+
@cache_on_self
|
21
|
+
def ssh_execute(self):
|
22
|
+
return SSH__Execute()
|
23
|
+
|
24
|
+
@cache_on_self
|
25
|
+
def ssh_linux(self):
|
26
|
+
return SSH__Linux(ssh_execute = self.ssh_execute())
|
27
|
+
|
28
|
+
@cache_on_self
|
29
|
+
def ssh_python(self):
|
30
|
+
return SSH__Python(ssh_execute = self.ssh_execute(), ssh_linux = self.ssh_linux())
|
@@ -0,0 +1,66 @@
|
|
1
|
+
from osbot_utils.helpers.sqlite.cache.Sqlite__Cache__Requests__Patch import Sqlite__Cache__Requests__Patch
|
2
|
+
from osbot_utils.helpers.ssh.SSH__Execute import SSH__Execute
|
3
|
+
from osbot_utils.utils.Call_Stack import call_stack_frames_data
|
4
|
+
from osbot_utils.utils.Dev import pprint
|
5
|
+
from osbot_utils.utils.Json import json_to_str, json_loads
|
6
|
+
from osbot_utils.utils.Python_Logger import Python_Logger
|
7
|
+
from osbot_utils.utils.Toml import dict_to_toml, toml_to_dict
|
8
|
+
|
9
|
+
SQLITE_DB_NAME__SSH_REQUESTS_CACHE = 'ssh_requests_cache.sqlite'
|
10
|
+
SQLITE_TABLE_NAME__SSH_REQUESTS = 'ssh_requests'
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
class SSH__Cache__Requests(Sqlite__Cache__Requests__Patch):
|
15
|
+
db_path : str
|
16
|
+
db_name : str = SQLITE_DB_NAME__SSH_REQUESTS_CACHE
|
17
|
+
table_name : str = SQLITE_TABLE_NAME__SSH_REQUESTS
|
18
|
+
add_caller_signature_to_cache_key : bool = True
|
19
|
+
print_ssh_execution_stdout : bool = False
|
20
|
+
logging : Python_Logger
|
21
|
+
|
22
|
+
def __init__(self, **kwargs):
|
23
|
+
super().__init__(**kwargs)
|
24
|
+
self.target_class = SSH__Execute
|
25
|
+
self.target_function = SSH__Execute.execute_command
|
26
|
+
self.target_function_name = "execute_command"
|
27
|
+
self.print_requests = False
|
28
|
+
self.logging.add_console_logger()
|
29
|
+
|
30
|
+
|
31
|
+
def invoke_target(self, target, target_args, target_kwargs):
|
32
|
+
if self.print_requests:
|
33
|
+
print(f'[invoke_target]: {target_args}')
|
34
|
+
return super().invoke_target(target, target_args, target_kwargs)
|
35
|
+
|
36
|
+
def invoke_with_cache(self, **invoke_kwargs):
|
37
|
+
result = super().invoke_with_cache(**invoke_kwargs)
|
38
|
+
stdout = result.get('stdout')
|
39
|
+
if self.print_ssh_execution_stdout and stdout:
|
40
|
+
#print(stdout)
|
41
|
+
self.logging.info('\n\n' + stdout)
|
42
|
+
return result
|
43
|
+
|
44
|
+
def request_data(self, *args, **kwargs):
|
45
|
+
ssh = args[0]
|
46
|
+
ssh_host = ssh.ssh_host
|
47
|
+
args_with_out_self = args[1:]
|
48
|
+
request_data = dict(args = args_with_out_self,
|
49
|
+
kwargs = kwargs ,
|
50
|
+
ssh_host = ssh_host )
|
51
|
+
if self.add_caller_signature_to_cache_key:
|
52
|
+
frames = call_stack_frames_data(8) # todo: refactor this to separate method
|
53
|
+
caller_signature = (f"{frames[0].get('name')}:{frames[0].get('lineno')} | "
|
54
|
+
f"{frames[1].get('name')}:{frames[1].get('lineno')} | "
|
55
|
+
f"{frames[2].get('name')}:{frames[2].get('lineno')}'")
|
56
|
+
request_data['caller_signature'] = caller_signature # this adds support for different caches to the same method call (main limitation is that it is directly tied with the line numbers)
|
57
|
+
|
58
|
+
return dict_to_toml(request_data)
|
59
|
+
|
60
|
+
def requests_data__all(self):
|
61
|
+
requests_data__all = super().requests_data__all()
|
62
|
+
for item in requests_data__all:
|
63
|
+
request_data_raw = item.get('request_data')
|
64
|
+
request_data_original = toml_to_dict(json_loads(request_data_raw))
|
65
|
+
item['request_data'] = request_data_original
|
66
|
+
return requests_data__all
|