osbot-utils 1.7.7__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/__init__.py +1 -0
- osbot_utils/base_classes/Cache_Pickle.py +129 -0
- osbot_utils/base_classes/Kwargs_To_Disk.py +27 -0
- osbot_utils/base_classes/Kwargs_To_Self.py +308 -0
- osbot_utils/base_classes/Type_Safe__List.py +14 -0
- osbot_utils/base_classes/__init__.py +0 -0
- osbot_utils/context_managers/__init__.py +0 -0
- osbot_utils/context_managers/capture_duration.py +33 -0
- osbot_utils/decorators/__init__.py +0 -0
- osbot_utils/decorators/classes/__init__.py +0 -0
- osbot_utils/decorators/classes/singleton.py +9 -0
- osbot_utils/decorators/lists/__init__.py +0 -0
- osbot_utils/decorators/lists/filter_list.py +12 -0
- osbot_utils/decorators/lists/group_by.py +21 -0
- osbot_utils/decorators/lists/index_by.py +27 -0
- osbot_utils/decorators/methods/__init__.py +0 -0
- osbot_utils/decorators/methods/cache.py +19 -0
- osbot_utils/decorators/methods/cache_on_function.py +56 -0
- osbot_utils/decorators/methods/cache_on_self.py +78 -0
- osbot_utils/decorators/methods/cache_on_tmp.py +71 -0
- osbot_utils/decorators/methods/capture_exception.py +37 -0
- osbot_utils/decorators/methods/capture_status.py +20 -0
- osbot_utils/decorators/methods/catch.py +13 -0
- osbot_utils/decorators/methods/context.py +11 -0
- osbot_utils/decorators/methods/depreciated.py +79 -0
- osbot_utils/decorators/methods/function_type_check.py +62 -0
- osbot_utils/decorators/methods/obj_as_context.py +6 -0
- osbot_utils/decorators/methods/remove_return_value.py +22 -0
- osbot_utils/decorators/methods/required_fields.py +19 -0
- osbot_utils/fluent/Fluent_Dict.py +19 -0
- osbot_utils/fluent/Fluent_List.py +44 -0
- osbot_utils/fluent/__init__.py +1 -0
- osbot_utils/graphs/__init__.py +0 -0
- osbot_utils/graphs/mermaid/Mermaid.py +75 -0
- osbot_utils/graphs/mermaid/Mermaid__Edge.py +49 -0
- osbot_utils/graphs/mermaid/Mermaid__Graph.py +93 -0
- osbot_utils/graphs/mermaid/Mermaid__Node.py +69 -0
- osbot_utils/graphs/mermaid/Mermaid__Renderer.py +54 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Edge__Config.py +7 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Node__Config.py +9 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Render__Config.py +7 -0
- osbot_utils/graphs/mermaid/examples/Mermaid_Examples__FlowChart.py +98 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Diagram_Direction.py +9 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Diagram__Type.py +17 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Node__Shape.py +30 -0
- osbot_utils/graphs/mgraph/MGraph.py +53 -0
- osbot_utils/graphs/mgraph/MGraph__Config.py +7 -0
- osbot_utils/graphs/mgraph/MGraph__Data.py +139 -0
- osbot_utils/graphs/mgraph/MGraph__Edge.py +27 -0
- osbot_utils/graphs/mgraph/MGraph__Node.py +33 -0
- osbot_utils/graphs/mgraph/MGraph__Random_Graphs.py +27 -0
- osbot_utils/graphs/mgraph/MGraph__Serializer.py +43 -0
- osbot_utils/graphs/mgraph/MGraphs.py +17 -0
- osbot_utils/graphs/mgraph/__init__.py +0 -0
- osbot_utils/helpers/CPrint.py +98 -0
- osbot_utils/helpers/Dict_To_Attr.py +7 -0
- osbot_utils/helpers/Local_Cache.py +111 -0
- osbot_utils/helpers/Local_Caches.py +54 -0
- osbot_utils/helpers/Print_Table.py +369 -0
- osbot_utils/helpers/Python_Audit.py +45 -0
- osbot_utils/helpers/Random_Seed.py +27 -0
- osbot_utils/helpers/SCP.py +58 -0
- osbot_utils/helpers/SSH.py +151 -0
- osbot_utils/helpers/Type_Registry.py +16 -0
- osbot_utils/helpers/__init__.py +0 -0
- osbot_utils/helpers/ast/Ast.py +35 -0
- osbot_utils/helpers/ast/Ast_Base.py +124 -0
- osbot_utils/helpers/ast/Ast_Data.py +28 -0
- osbot_utils/helpers/ast/Ast_Load.py +62 -0
- osbot_utils/helpers/ast/Ast_Merge.py +26 -0
- osbot_utils/helpers/ast/Ast_Node.py +117 -0
- osbot_utils/helpers/ast/Ast_Visit.py +85 -0
- osbot_utils/helpers/ast/Call_Tree.py +38 -0
- osbot_utils/helpers/ast/__init__.py +145 -0
- osbot_utils/helpers/ast/nodes/Ast_Add.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Alias.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_And.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Argument.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Arguments.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Assert.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Assign.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Attribute.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Aug_Assign.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Bin_Op.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Bool_Op.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Break.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Call.py +17 -0
- osbot_utils/helpers/ast/nodes/Ast_Class_Def.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Compare.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Comprehension.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Constant.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Continue.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Dict.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Eq.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Except_Handler.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Expr.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_For.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Function_Def.py +17 -0
- osbot_utils/helpers/ast/nodes/Ast_Generator_Exp.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Gt.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_GtE.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_If.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_If_Exp.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Import.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Import_From.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_In.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Is.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Is_Not.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Keyword.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Lambda.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_List.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_List_Comp.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Load.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Lt.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_LtE.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Mod.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Module.py +20 -0
- osbot_utils/helpers/ast/nodes/Ast_Mult.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Name.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Not.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Not_Eq.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Not_In.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Or.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Pass.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Pow.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Raise.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Return.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Set.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Slice.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Starred.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Store.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Sub.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Subscript.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Try.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Tuple.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Unary_Op.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_While.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_With.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_With_Item.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Yield.py +7 -0
- osbot_utils/helpers/ast/nodes/__init__.py +0 -0
- osbot_utils/helpers/html/Dict_To_Css.py +20 -0
- osbot_utils/helpers/html/Dict_To_Html.py +59 -0
- osbot_utils/helpers/html/Dict_To_Tags.py +88 -0
- osbot_utils/helpers/html/Html_To_Dict.py +75 -0
- osbot_utils/helpers/html/Html_To_Tag.py +20 -0
- osbot_utils/helpers/html/Tag__Base.py +91 -0
- osbot_utils/helpers/html/Tag__Body.py +5 -0
- osbot_utils/helpers/html/Tag__Div.py +5 -0
- osbot_utils/helpers/html/Tag__H.py +9 -0
- osbot_utils/helpers/html/Tag__HR.py +5 -0
- osbot_utils/helpers/html/Tag__Head.py +32 -0
- osbot_utils/helpers/html/Tag__Html.py +42 -0
- osbot_utils/helpers/html/Tag__Link.py +17 -0
- osbot_utils/helpers/html/Tag__Style.py +25 -0
- osbot_utils/helpers/html/__init__.py +0 -0
- osbot_utils/helpers/pubsub/Event__Queue.py +95 -0
- osbot_utils/helpers/pubsub/PubSub__Client.py +53 -0
- osbot_utils/helpers/pubsub/PubSub__Room.py +13 -0
- osbot_utils/helpers/pubsub/PubSub__Server.py +94 -0
- osbot_utils/helpers/pubsub/PubSub__Sqlite.py +24 -0
- osbot_utils/helpers/pubsub/__init__.py +0 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event.py +15 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Disconnect.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Join_Room.py +8 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Leave_Room.py +8 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Message.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py +8 -0
- osbot_utils/helpers/pubsub/schemas/__init__.py +0 -0
- osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py +51 -0
- osbot_utils/helpers/sqlite/Sqlite__Cursor.py +87 -0
- osbot_utils/helpers/sqlite/Sqlite__Database.py +137 -0
- osbot_utils/helpers/sqlite/Sqlite__Field.py +70 -0
- osbot_utils/helpers/sqlite/Sqlite__Globals.py +5 -0
- osbot_utils/helpers/sqlite/Sqlite__Table.py +293 -0
- osbot_utils/helpers/sqlite/Sqlite__Table__Create.py +96 -0
- osbot_utils/helpers/sqlite/Temp_Sqlite__Database__Disk.py +17 -0
- osbot_utils/helpers/sqlite/Temp_Sqlite__Table.py +23 -0
- osbot_utils/helpers/sqlite/__init__.py +0 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests.py +214 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests__Patch.py +63 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Files.py +23 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Graph.py +47 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Json.py +83 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +20 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Requests.py +39 -0
- osbot_utils/helpers/sqlite/domains/__init__.py +0 -0
- osbot_utils/helpers/sqlite/domains/schemas/Schema__Table__Requests.py +12 -0
- osbot_utils/helpers/sqlite/domains/schemas/__init__.py +0 -0
- osbot_utils/helpers/sqlite/models/Sqlite__Field__Type.py +37 -0
- osbot_utils/helpers/sqlite/models/__init__.py +0 -0
- osbot_utils/helpers/sqlite/sample_data/Sqlite__Sample_Data__Chinook.py +116 -0
- osbot_utils/helpers/sqlite/sample_data/__init__.py +0 -0
- osbot_utils/helpers/sqlite/sql_builder/SQL_Builder.py +159 -0
- osbot_utils/helpers/sqlite/sql_builder/SQL_Builder__Select.py +12 -0
- osbot_utils/helpers/sqlite/sql_builder/__init__.py +0 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Config.py +63 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py +46 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py +45 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py +52 -0
- osbot_utils/helpers/sqlite/tables/__init__.py +0 -0
- osbot_utils/helpers/trace/Trace_Call.py +120 -0
- osbot_utils/helpers/trace/Trace_Call__Config.py +94 -0
- osbot_utils/helpers/trace/Trace_Call__Graph.py +26 -0
- osbot_utils/helpers/trace/Trace_Call__Handler.py +215 -0
- osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +85 -0
- osbot_utils/helpers/trace/Trace_Call__Print_Traces.py +170 -0
- osbot_utils/helpers/trace/Trace_Call__Stack.py +166 -0
- osbot_utils/helpers/trace/Trace_Call__Stack_Node.py +59 -0
- osbot_utils/helpers/trace/Trace_Call__Stats.py +71 -0
- osbot_utils/helpers/trace/Trace_Call__View_Model.py +75 -0
- osbot_utils/helpers/trace/Trace_Files.py +33 -0
- osbot_utils/helpers/trace/__init__.py +0 -0
- osbot_utils/testing/Catch.py +54 -0
- osbot_utils/testing/Duration.py +69 -0
- osbot_utils/testing/Hook_Method.py +118 -0
- osbot_utils/testing/Log_To_Queue.py +46 -0
- osbot_utils/testing/Log_To_String.py +37 -0
- osbot_utils/testing/Logging.py +81 -0
- osbot_utils/testing/Patch_Print.py +52 -0
- osbot_utils/testing/Profiler.py +89 -0
- osbot_utils/testing/Stderr.py +19 -0
- osbot_utils/testing/Stdout.py +19 -0
- osbot_utils/testing/Temp_File.py +46 -0
- osbot_utils/testing/Temp_Folder.py +114 -0
- osbot_utils/testing/Temp_Sys_Path.py +13 -0
- osbot_utils/testing/Temp_Web_Server.py +83 -0
- osbot_utils/testing/Temp_Zip.py +45 -0
- osbot_utils/testing/Temp_Zip_In_Memory.py +90 -0
- osbot_utils/testing/Unit_Test.py +34 -0
- osbot_utils/testing/Unzip_File.py +30 -0
- osbot_utils/testing/__init__.py +0 -0
- osbot_utils/utils/Assert.py +52 -0
- osbot_utils/utils/Call_Stack.py +187 -0
- osbot_utils/utils/Csv.py +32 -0
- osbot_utils/utils/Dev.py +47 -0
- osbot_utils/utils/Exceptions.py +7 -0
- osbot_utils/utils/Files.py +528 -0
- osbot_utils/utils/Functions.py +113 -0
- osbot_utils/utils/Http.py +136 -0
- osbot_utils/utils/Int.py +6 -0
- osbot_utils/utils/Json.py +171 -0
- osbot_utils/utils/Json_Cache.py +59 -0
- osbot_utils/utils/Lists.py +198 -0
- osbot_utils/utils/Misc.py +496 -0
- osbot_utils/utils/Objects.py +341 -0
- osbot_utils/utils/Png.py +29 -0
- osbot_utils/utils/Process.py +73 -0
- osbot_utils/utils/Python_Logger.py +301 -0
- osbot_utils/utils/Status.py +79 -0
- osbot_utils/utils/Str.py +63 -0
- osbot_utils/utils/Version.py +16 -0
- osbot_utils/utils/Zip.py +97 -0
- osbot_utils/utils/__init__.py +16 -0
- osbot_utils/version +1 -0
- osbot_utils-1.7.7.dist-info/LICENSE +201 -0
- osbot_utils-1.7.7.dist-info/METADATA +46 -0
- osbot_utils-1.7.7.dist-info/RECORD +260 -0
- osbot_utils-1.7.7.dist-info/WHEEL +4 -0
@@ -0,0 +1,63 @@
|
|
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.sqlite.Sqlite__Table import Sqlite__Table
|
4
|
+
from osbot_utils.utils.Objects import pickle_save_to_bytes, pickle_load_from_bytes
|
5
|
+
|
6
|
+
SQLITE__TABLE_NAME__CONFIG = 'config'
|
7
|
+
|
8
|
+
class Schema__Table__Config(Kwargs_To_Self):
|
9
|
+
key : str
|
10
|
+
value: bytes
|
11
|
+
|
12
|
+
class Sqlite__Table__Config(Sqlite__Table):
|
13
|
+
def __init__(self, **kwargs):
|
14
|
+
self.table_name = SQLITE__TABLE_NAME__CONFIG
|
15
|
+
self.row_schema = Schema__Table__Config
|
16
|
+
super().__init__(**kwargs)
|
17
|
+
|
18
|
+
def config_data(self):
|
19
|
+
config_data = {}
|
20
|
+
for row in self.rows():
|
21
|
+
key, value = self.deserialize_row(row)
|
22
|
+
config_data[key] = value
|
23
|
+
return config_data
|
24
|
+
|
25
|
+
@cache_on_self
|
26
|
+
def data(self):
|
27
|
+
return self.config_data()
|
28
|
+
|
29
|
+
def deserialize_row(self, row):
|
30
|
+
if row:
|
31
|
+
key = row.get('key')
|
32
|
+
pickled_value = row.get('value')
|
33
|
+
value = pickle_load_from_bytes(pickled_value)
|
34
|
+
return key, value
|
35
|
+
return None, None
|
36
|
+
|
37
|
+
def set_config_data(self, config_data: dict):
|
38
|
+
self.clear()
|
39
|
+
for key,value in config_data.items():
|
40
|
+
self.set_value(key=key, value=value)
|
41
|
+
self.commit()
|
42
|
+
|
43
|
+
def set_value(self, key, value):
|
44
|
+
if self.not_contains(key=key):
|
45
|
+
pickled_value = pickle_save_to_bytes(value)
|
46
|
+
return self.add_row_and_commit(key=key, value=pickled_value)
|
47
|
+
return self.update_value(key,value)
|
48
|
+
|
49
|
+
def update_value(self, key, value):
|
50
|
+
pickled_value = pickle_save_to_bytes(value)
|
51
|
+
self.row_update(dict(key=key, value=pickled_value), dict(key=key))
|
52
|
+
|
53
|
+
def setup(self):
|
54
|
+
if self.exists() is False:
|
55
|
+
self.create()
|
56
|
+
self.index_create('key')
|
57
|
+
return self
|
58
|
+
|
59
|
+
def value(self, key):
|
60
|
+
row = self.where_one(key=key)
|
61
|
+
key, value = self.deserialize_row(row)
|
62
|
+
return value
|
63
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
from osbot_utils.decorators.lists.index_by import index_by
|
2
|
+
from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
|
3
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
4
|
+
from osbot_utils.utils.Misc import timestamp_utc_now
|
5
|
+
|
6
|
+
SQLITE__TABLE_NAME__EDGES = 'edges'
|
7
|
+
|
8
|
+
class Schema__Table__Edges(Kwargs_To_Self):
|
9
|
+
source_key : str
|
10
|
+
target_key : str
|
11
|
+
value : bytes
|
12
|
+
properties : bytes
|
13
|
+
timestamp : int
|
14
|
+
|
15
|
+
class Sqlite__Table__Edges(Sqlite__Table):
|
16
|
+
auto_pickle_blob : bool = True
|
17
|
+
set_timestamp : bool = True
|
18
|
+
|
19
|
+
def __init__(self, **kwargs):
|
20
|
+
self.table_name = SQLITE__TABLE_NAME__EDGES
|
21
|
+
self.row_schema = Schema__Table__Edges
|
22
|
+
super().__init__(**kwargs)
|
23
|
+
|
24
|
+
|
25
|
+
def add_edge(self, source_key, target_key, value=None, properties=None):
|
26
|
+
row_data = self.create_node_data(source_key, target_key,value, properties)
|
27
|
+
return self.add_row_and_commit(**row_data)
|
28
|
+
|
29
|
+
def create_node_data(self, source_key, target_key, value=None, properties=None):
|
30
|
+
node_data = {'source_key' : source_key ,
|
31
|
+
'target_key' : target_key ,
|
32
|
+
'value' : value ,
|
33
|
+
'properties' : properties }
|
34
|
+
if self.set_timestamp:
|
35
|
+
node_data['timestamp'] = timestamp_utc_now()
|
36
|
+
return node_data
|
37
|
+
|
38
|
+
def edges(self):
|
39
|
+
return self.rows()
|
40
|
+
|
41
|
+
def setup(self):
|
42
|
+
if self.exists() is False:
|
43
|
+
self.create()
|
44
|
+
self.index_create('source_key')
|
45
|
+
self.index_create('target_key')
|
46
|
+
return self
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
2
|
+
from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
|
3
|
+
from osbot_utils.utils.Misc import timestamp_utc_now
|
4
|
+
|
5
|
+
SQLITE__TABLE_NAME__FILES = 'files'
|
6
|
+
|
7
|
+
class Schema__Table__Files(Kwargs_To_Self):
|
8
|
+
path : str
|
9
|
+
contents : bytes
|
10
|
+
metadata : bytes
|
11
|
+
timestamp: int
|
12
|
+
|
13
|
+
|
14
|
+
class Sqlite__Table__Files(Sqlite__Table):
|
15
|
+
auto_pickle_blob : bool = True
|
16
|
+
set_timestamp : bool = True
|
17
|
+
|
18
|
+
def __init__(self, **kwargs):
|
19
|
+
self.table_name = SQLITE__TABLE_NAME__FILES
|
20
|
+
self.row_schema = Schema__Table__Files
|
21
|
+
super().__init__(**kwargs)
|
22
|
+
|
23
|
+
def add_file(self, path, contents=None, metadata= None):
|
24
|
+
if self.contains(path=path): # don't allow multiple entries for the same file path (until we add versioning support)
|
25
|
+
return None
|
26
|
+
row_data = self.create_node_data(path, contents, metadata)
|
27
|
+
return self.add_row_and_commit(**row_data)
|
28
|
+
|
29
|
+
def create_node_data(self, path, contents=None, metadata= None):
|
30
|
+
node_data = {'path' : path ,
|
31
|
+
'contents': contents ,
|
32
|
+
'metadata': metadata }
|
33
|
+
if self.set_timestamp:
|
34
|
+
node_data['timestamp'] = timestamp_utc_now()
|
35
|
+
return node_data
|
36
|
+
|
37
|
+
|
38
|
+
def files(self):
|
39
|
+
return self.rows()
|
40
|
+
|
41
|
+
def setup(self):
|
42
|
+
if self.exists() is False:
|
43
|
+
self.create()
|
44
|
+
self.index_create('path')
|
45
|
+
return self
|
@@ -0,0 +1,52 @@
|
|
1
|
+
from osbot_utils.decorators.lists.index_by import index_by
|
2
|
+
from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
|
3
|
+
|
4
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
5
|
+
from osbot_utils.utils.Lists import unique
|
6
|
+
from osbot_utils.utils.Misc import timestamp_utc_now
|
7
|
+
|
8
|
+
SQLITE__TABLE_NAME__NODES = 'nodes'
|
9
|
+
|
10
|
+
class Schema__Table__Nodes(Kwargs_To_Self):
|
11
|
+
key : str
|
12
|
+
value : bytes
|
13
|
+
properties: bytes
|
14
|
+
timestamp : int
|
15
|
+
|
16
|
+
class Sqlite__Table__Nodes(Sqlite__Table):
|
17
|
+
allow_duplicate_keys: bool = False
|
18
|
+
auto_pickle_blob : bool = True
|
19
|
+
set_timestamp : bool = True
|
20
|
+
|
21
|
+
def __init__(self, **kwargs):
|
22
|
+
self.table_name = SQLITE__TABLE_NAME__NODES
|
23
|
+
self.row_schema = Schema__Table__Nodes
|
24
|
+
super().__init__(**kwargs)
|
25
|
+
|
26
|
+
def add_node(self, key, value=None, properties=None):
|
27
|
+
if self.allow_duplicate_keys is False:
|
28
|
+
if self.contains(key=key):
|
29
|
+
return None
|
30
|
+
row_data = self.create_node_data(key,value, properties)
|
31
|
+
return self.add_row_and_commit(**row_data)
|
32
|
+
|
33
|
+
def create_node_data(self, key, value=None, properties=None):
|
34
|
+
node_data = {'key' : key ,
|
35
|
+
'value' : value ,
|
36
|
+
'properties' : properties }
|
37
|
+
if self.set_timestamp:
|
38
|
+
node_data['timestamp'] = timestamp_utc_now()
|
39
|
+
return node_data
|
40
|
+
|
41
|
+
@index_by
|
42
|
+
def nodes(self):
|
43
|
+
return self.rows()
|
44
|
+
|
45
|
+
def keys(self):
|
46
|
+
return unique(self.select_field_values('key'))
|
47
|
+
|
48
|
+
def setup(self):
|
49
|
+
if self.exists() is False:
|
50
|
+
self.create()
|
51
|
+
self.index_create('key')
|
52
|
+
return self
|
File without changes
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import linecache
|
2
|
+
import sys
|
3
|
+
from functools import wraps
|
4
|
+
|
5
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
6
|
+
from osbot_utils.helpers.trace.Trace_Call__Config import Trace_Call__Config, PRINT_MAX_STRING_LENGTH
|
7
|
+
from osbot_utils.helpers.trace.Trace_Call__Handler import Trace_Call__Handler
|
8
|
+
from osbot_utils.helpers.trace.Trace_Call__Print_Lines import Trace_Call__Print_Lines
|
9
|
+
from osbot_utils.helpers.trace.Trace_Call__Print_Traces import Trace_Call__Print_Traces
|
10
|
+
from osbot_utils.helpers.trace.Trace_Call__View_Model import Trace_Call__View_Model
|
11
|
+
|
12
|
+
|
13
|
+
def trace_calls(title = None , print_traces = True , show_locals = False, source_code = False ,
|
14
|
+
ignore = None , include = None , show_path = False, duration_bigger_than = 0 ,
|
15
|
+
max_string = None , show_types = False, show_duration = False ,# show_caller = False , # todo: add back when show_caller is working again
|
16
|
+
show_class = False, contains = None , show_internals = False, enabled = True ,
|
17
|
+
extra_data = False, show_lines = False, print_lines = False, show_types_padding = None , duration_padding=None):
|
18
|
+
def decorator(func):
|
19
|
+
@wraps(func)
|
20
|
+
def wrapper(*args, **kwargs):
|
21
|
+
config_kwargs = dict(title=title, print_traces_on_exit=print_traces, print_locals=show_locals,
|
22
|
+
capture_locals = show_locals,
|
23
|
+
trace_capture_source_code=source_code, ignore_start_with=ignore,
|
24
|
+
trace_capture_start_with=include, print_max_string_length=max_string,
|
25
|
+
show_parent_info=show_types, show_method_class=show_class,
|
26
|
+
show_source_code_path=show_path,
|
27
|
+
capture_duration=show_duration, print_duration= show_duration,
|
28
|
+
with_duration_bigger_than=duration_bigger_than,
|
29
|
+
trace_capture_contains=contains, trace_show_internals=show_internals,
|
30
|
+
capture_extra_data=extra_data,
|
31
|
+
print_padding_parent_info= show_types_padding, print_padding_duration=duration_padding,
|
32
|
+
print_lines_on_exit=print_lines, trace_enabled=enabled,
|
33
|
+
trace_capture_lines=show_lines or print_lines)
|
34
|
+
|
35
|
+
config = (Trace_Call__Config().update_from_kwargs (**config_kwargs))
|
36
|
+
|
37
|
+
with Trace_Call(config=config):
|
38
|
+
result = func(*args, **kwargs)
|
39
|
+
return result
|
40
|
+
return wrapper
|
41
|
+
return decorator
|
42
|
+
|
43
|
+
class Trace_Call(Kwargs_To_Self):
|
44
|
+
|
45
|
+
config : Trace_Call__Config
|
46
|
+
started : bool
|
47
|
+
prev_trace_function: None
|
48
|
+
|
49
|
+
def __init__(self, **kwargs):
|
50
|
+
super().__init__(**kwargs)
|
51
|
+
|
52
|
+
self.trace_call_handler = Trace_Call__Handler (config=self.config)
|
53
|
+
self.trace_call_print_traces = Trace_Call__Print_Traces(config=self.config)
|
54
|
+
self.trace_call_view_model = Trace_Call__View_Model ()
|
55
|
+
self.config.print_traces_on_exit = self.config.print_traces_on_exit
|
56
|
+
#self.config.trace_capture_start_with = self.config.capture_start_with or [] # todo add a better way to set these to [] when then value is null
|
57
|
+
self.config.trace_ignore_start_with = self.config.ignore_start_with or [] # probablty better done inside Kwargs_To_Self since it doesn't make sense for lists or dicts to have None value
|
58
|
+
self.config.trace_capture_contains = self.config.trace_capture_contains or [] # and None will be quite common since we can use [] on method's params
|
59
|
+
self.config.print_max_string_length = self.config.print_max_string_length or PRINT_MAX_STRING_LENGTH
|
60
|
+
self.stack = self.trace_call_handler.stack
|
61
|
+
#self.prev_trace_function = None # Stores the previous trace function
|
62
|
+
|
63
|
+
|
64
|
+
def __enter__(self):
|
65
|
+
return self.on_enter()
|
66
|
+
|
67
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
68
|
+
return self.on_exit()
|
69
|
+
|
70
|
+
def on_enter(self):
|
71
|
+
if self.config.trace_enabled:
|
72
|
+
self.start() # Start the tracing
|
73
|
+
return self
|
74
|
+
|
75
|
+
def on_exit(self):
|
76
|
+
if self.config.trace_enabled:
|
77
|
+
self.stop() # Stop the tracing
|
78
|
+
if self.config.print_traces_on_exit:
|
79
|
+
self.print()
|
80
|
+
if self.config.print_lines_on_exit:
|
81
|
+
self.print_lines()
|
82
|
+
|
83
|
+
def capture_all(self):
|
84
|
+
self.config.trace_capture_all = True
|
85
|
+
return self
|
86
|
+
|
87
|
+
def view_data(self):
|
88
|
+
return self.trace_call_view_model.create(self.stack)
|
89
|
+
|
90
|
+
def print(self):
|
91
|
+
view_model = self.view_data()
|
92
|
+
self.trace_call_print_traces.print_traces(view_model)
|
93
|
+
#self.print_lines()
|
94
|
+
return view_model
|
95
|
+
|
96
|
+
def print_lines(self):
|
97
|
+
print()
|
98
|
+
view_model = self.view_data()
|
99
|
+
print_lines = Trace_Call__Print_Lines(config=self.config, view_model=view_model)
|
100
|
+
print_lines.print_lines()
|
101
|
+
|
102
|
+
def start(self):
|
103
|
+
self.trace_call_handler.stack.add_node(title=self.trace_call_handler.config.title)
|
104
|
+
self.prev_trace_function = sys.gettrace()
|
105
|
+
self.started = True # set this here so that it does show in the trace
|
106
|
+
sys.settrace(self.trace_call_handler.trace_calls) # Set the new trace function
|
107
|
+
|
108
|
+
|
109
|
+
def stop(self):
|
110
|
+
if self.started:
|
111
|
+
sys.settrace(self.prev_trace_function) # Restore the previous trace function
|
112
|
+
self.stack.empty_stack()
|
113
|
+
self.started = False
|
114
|
+
|
115
|
+
def stats(self):
|
116
|
+
return self.trace_call_handler.stats
|
117
|
+
|
118
|
+
def stats_data(self):
|
119
|
+
return self.trace_call_handler.stats.raw_call_stats
|
120
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
from osbot_utils.utils.Dev import pprint
|
2
|
+
|
3
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
4
|
+
|
5
|
+
PRINT_MAX_STRING_LENGTH = 100
|
6
|
+
PRINT_PADDING__DURATION = 100
|
7
|
+
PRINT_PADDING_PARENT_INFO = 60
|
8
|
+
|
9
|
+
class Trace_Call__Config(Kwargs_To_Self):
|
10
|
+
title : str
|
11
|
+
capture_locals : bool = False
|
12
|
+
capture_duration : bool
|
13
|
+
capture_extra_data : bool
|
14
|
+
capture_frame : bool = True
|
15
|
+
capture_frame_stats : bool
|
16
|
+
deep_copy_locals : bool
|
17
|
+
trace_capture_lines : bool
|
18
|
+
ignore_start_with : list
|
19
|
+
print_padding_duration : int = PRINT_PADDING__DURATION
|
20
|
+
print_padding_parent_info : int = PRINT_PADDING_PARENT_INFO
|
21
|
+
print_duration : bool
|
22
|
+
print_max_string_length : int = PRINT_MAX_STRING_LENGTH
|
23
|
+
print_locals : bool
|
24
|
+
print_traces_on_exit : bool
|
25
|
+
print_lines_on_exit : bool
|
26
|
+
show_parent_info : bool = False
|
27
|
+
show_caller : bool
|
28
|
+
show_method_class : bool = True
|
29
|
+
show_source_code_path : bool
|
30
|
+
trace_capture_all : bool
|
31
|
+
trace_capture_source_code : bool
|
32
|
+
trace_capture_start_with : list
|
33
|
+
trace_capture_contains : list
|
34
|
+
trace_enabled : bool = True
|
35
|
+
trace_ignore_start_with : list
|
36
|
+
trace_show_internals : bool
|
37
|
+
trace_up_to_depth : int
|
38
|
+
with_duration_bigger_than : float
|
39
|
+
|
40
|
+
def __init__(self, **wargs):
|
41
|
+
super().__init__(**wargs)
|
42
|
+
#self.locked()
|
43
|
+
|
44
|
+
def all(self, up_to_depth=0, print_traces=True):
|
45
|
+
self.trace_capture_all = True
|
46
|
+
self.print_traces_on_exit = print_traces
|
47
|
+
self.trace_up_to_depth = up_to_depth
|
48
|
+
return self
|
49
|
+
|
50
|
+
def capture(self, starts_with=None, contains=None, ignore=None):
|
51
|
+
if starts_with:
|
52
|
+
if type(starts_with) is str:
|
53
|
+
starts_with = [starts_with]
|
54
|
+
self.trace_capture_start_with = starts_with
|
55
|
+
if contains:
|
56
|
+
if type(contains) is str:
|
57
|
+
contains = [contains]
|
58
|
+
self.trace_capture_contains = contains
|
59
|
+
if ignore:
|
60
|
+
if type(ignore) is str:
|
61
|
+
ignore = [ignore]
|
62
|
+
self.ignore_start_with = ignore
|
63
|
+
self.print_traces_on_exit = True
|
64
|
+
return self
|
65
|
+
|
66
|
+
def duration(self, bigger_than=0, padding=PRINT_PADDING__DURATION):
|
67
|
+
self.capture_duration = True
|
68
|
+
self.print_duration = True
|
69
|
+
self.print_padding_duration = padding
|
70
|
+
self.with_duration_bigger_than = bigger_than
|
71
|
+
return self
|
72
|
+
|
73
|
+
def locals(self):
|
74
|
+
self.capture_locals = True
|
75
|
+
self.print_locals = True
|
76
|
+
return self
|
77
|
+
|
78
|
+
def lines(self, print_traces=True, print_lines=True):
|
79
|
+
self.trace_capture_lines = True
|
80
|
+
self.print_traces_on_exit = print_traces
|
81
|
+
self.print_lines_on_exit = print_lines
|
82
|
+
return self
|
83
|
+
|
84
|
+
def print_config(self):
|
85
|
+
pprint(self.__locals__())
|
86
|
+
return self
|
87
|
+
|
88
|
+
def print_on_exit(self, value=True):
|
89
|
+
self.print_traces_on_exit = value
|
90
|
+
return self
|
91
|
+
|
92
|
+
def up_to_depth(self, depth):
|
93
|
+
self.trace_up_to_depth = depth
|
94
|
+
return self
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from osbot_utils.graphs.mermaid.Mermaid__Graph import Mermaid__Graph
|
2
|
+
from osbot_utils.utils.Dev import pprint
|
3
|
+
|
4
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
5
|
+
from osbot_utils.helpers.trace.Trace_Call import Trace_Call
|
6
|
+
|
7
|
+
# todo: reimplement this class when Mermaid__Graph has been updated to new version
|
8
|
+
class Trace_Call__Graph(Trace_Call):
|
9
|
+
|
10
|
+
def create(self):
|
11
|
+
mermaid_graph = Mermaid__Graph()
|
12
|
+
self.trace_call_handler.stack.root_node.func_name = 'trace_root'
|
13
|
+
for trace in self.trace_call_handler.traces():
|
14
|
+
node_key = trace.func_name
|
15
|
+
class_name = trace.module.split('.')[-1]
|
16
|
+
node_label = f'`**{trace.func_name}**\n*{class_name}*`'
|
17
|
+
mermaid_graph.add_node(key=node_key, label=node_label)
|
18
|
+
|
19
|
+
nodes__by_key = mermaid_graph.data().nodes__by_key()
|
20
|
+
|
21
|
+
for trace in self.trace_call_handler.traces():
|
22
|
+
from_node = nodes__by_key[trace.func_name]
|
23
|
+
for child in trace.children:
|
24
|
+
to_node = nodes__by_key[child.func_name]
|
25
|
+
mermaid_graph.add_edge(from_node=from_node, to_node=to_node)
|
26
|
+
return mermaid_graph
|
@@ -0,0 +1,215 @@
|
|
1
|
+
import inspect
|
2
|
+
import linecache
|
3
|
+
from osbot_utils.utils.Objects import class_full_name
|
4
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
5
|
+
from osbot_utils.helpers.trace.Trace_Call__Config import Trace_Call__Config
|
6
|
+
from osbot_utils.helpers.trace.Trace_Call__Stack import Trace_Call__Stack
|
7
|
+
from osbot_utils.helpers.trace.Trace_Call__Stack_Node import Trace_Call__Stack_Node, EXTRA_DATA__RETURN_VALUE
|
8
|
+
from osbot_utils.helpers.trace.Trace_Call__Stats import Trace_Call__Stats
|
9
|
+
|
10
|
+
DEFAULT_ROOT_NODE_NODE_TITLE = 'Trace Session'
|
11
|
+
GLOBAL_FUNCTIONS_TO_IGNORE = ['value_type_matches_obj_annotation_for_attr' , # these are type safety functions which introduce quite a lot of noise in the traces (and unless one is debugging type safety, they will not be needed)
|
12
|
+
'value_type_matches_obj_annotation_for_union_attr' , # todo: map out and document why exactly these methods are ignore (and what is the side effect)
|
13
|
+
'are_types_compatible_for_assigment' ,
|
14
|
+
'obj_attribute_annotation' ,
|
15
|
+
'get_origin' ,
|
16
|
+
'getmro' ,
|
17
|
+
'default_value' ,
|
18
|
+
'raise_exception_on_obj_type_annotation_mismatch' ,
|
19
|
+
'__cls_kwargs__' ,
|
20
|
+
'__default__value__' ,
|
21
|
+
'__setattr__' ,
|
22
|
+
'<module>']
|
23
|
+
GLOBAL_MODULES_TO_IGNORE = ['osbot_utils.helpers.trace.Trace_Call' , # todo: map out and document why exactly these modules are ignore (and what is the side effect)
|
24
|
+
'osbot_utils.helpers.CPrint' , # also see if this should be done here or at the print/view stage
|
25
|
+
'osbot_utils.helpers.Print_Table' ,
|
26
|
+
'osbot_utils.decorators.methods.cache_on_self' ,
|
27
|
+
'codecs']
|
28
|
+
|
29
|
+
class Trace_Call__Handler(Kwargs_To_Self):
|
30
|
+
config : Trace_Call__Config
|
31
|
+
stack : Trace_Call__Stack
|
32
|
+
stats : Trace_Call__Stats
|
33
|
+
|
34
|
+
|
35
|
+
def __init__(self, **kwargs):
|
36
|
+
super().__init__(**kwargs)
|
37
|
+
self.config.title = self.config.title or DEFAULT_ROOT_NODE_NODE_TITLE # Title for the trace root node
|
38
|
+
self.stack.config = self.config
|
39
|
+
|
40
|
+
def add_default_root_node(self):
|
41
|
+
return self.stack.add_node(title=self.config.title)
|
42
|
+
|
43
|
+
def add_line(self, frame):
|
44
|
+
if self.config.trace_capture_lines:
|
45
|
+
if frame:
|
46
|
+
target_node = self.stack.top() # lines captured are added to the current top of the stack
|
47
|
+
#obj_info(target_node)
|
48
|
+
if self.stack.top():
|
49
|
+
target_node__func_name = target_node.func_name
|
50
|
+
target_node__module = target_node.module
|
51
|
+
frame_func_name = frame.f_code.co_name
|
52
|
+
frame_module = frame.f_globals.get("__name__", "")
|
53
|
+
if frame_func_name == target_node__func_name:
|
54
|
+
if frame_module == target_node__module:
|
55
|
+
return self.add_line_to_node(frame, target_node, 'line')
|
56
|
+
return False
|
57
|
+
|
58
|
+
def add_line_to_node(self, frame, target_node, event):
|
59
|
+
def source_code_for_frame(function_name):
|
60
|
+
try:
|
61
|
+
return inspect.getsource(frame.f_code)
|
62
|
+
except Exception as error:
|
63
|
+
return ''
|
64
|
+
#print(self.stack.line_index, f'def {function_name}() : error] {error}' )
|
65
|
+
#return f'def {function_name}() : [error] {error}'
|
66
|
+
|
67
|
+
if frame and target_node:
|
68
|
+
func_name = frame.f_code.co_name
|
69
|
+
module = frame.f_globals.get("__name__", "")
|
70
|
+
self_local = class_full_name(frame.f_locals.get('self'))
|
71
|
+
stack_size = len(self.stack)
|
72
|
+
line =''
|
73
|
+
line_number=0
|
74
|
+
if event == 'call': # if this is a call we need to do the code below to get the actual method signature (and decorators)
|
75
|
+
function_name = frame.f_code.co_name
|
76
|
+
filename = frame.f_code.co_filename # Get the filename where the function is defined
|
77
|
+
start_line_number = frame.f_code.co_firstlineno # Get the starting line number
|
78
|
+
source_lines = source_code_for_frame(function_name).split('\n')
|
79
|
+
if source_lines:
|
80
|
+
def_line_number = start_line_number # Try to find the actual 'def' line
|
81
|
+
for line in source_lines:
|
82
|
+
if line.strip().startswith('def ' + function_name):
|
83
|
+
break
|
84
|
+
def_line_number += 1
|
85
|
+
else:
|
86
|
+
def_line_number = start_line_number # If the 'def' line wasn't found, default to the starting line
|
87
|
+
line_number = def_line_number
|
88
|
+
line = linecache.getline(filename, line_number).rstrip() # todo: refactor this to not capture this info here, and to use the Ast_* utils to get a better source code mapping
|
89
|
+
else:
|
90
|
+
filename = frame.f_code.co_filename # get the filename
|
91
|
+
line_number = frame.f_lineno # get the current line number
|
92
|
+
line = linecache.getline(filename, line_number) # get the line
|
93
|
+
|
94
|
+
if line:
|
95
|
+
self.stack.line_index += 1
|
96
|
+
line_data = dict(event=event, index = self.stack.line_index, func_name=func_name,
|
97
|
+
line = line.rstrip(), line_number=line_number,
|
98
|
+
module=module, self_local=self_local,
|
99
|
+
stack_size=stack_size)
|
100
|
+
target_node.lines.append(line_data)
|
101
|
+
return True
|
102
|
+
# else:
|
103
|
+
# print(f'no line for : {self.stack.line_index}, {module}.{func_name}')
|
104
|
+
return False
|
105
|
+
|
106
|
+
def add_frame(self, frame):
|
107
|
+
return self.handle_event__call(frame)
|
108
|
+
|
109
|
+
def add_trace_ignore(self, value):
|
110
|
+
self.config.trace_ignore_start_with.append(value)
|
111
|
+
return
|
112
|
+
|
113
|
+
def handle_event__call(self, frame):
|
114
|
+
if frame:
|
115
|
+
if self.config.capture_frame_stats:
|
116
|
+
self.stats.log_frame(frame)
|
117
|
+
if self.should_capture(frame):
|
118
|
+
new_node = self.stack.add_frame(frame)
|
119
|
+
if self.config.trace_capture_lines:
|
120
|
+
self.add_line_to_node(frame, new_node,'call')
|
121
|
+
return new_node
|
122
|
+
else:
|
123
|
+
self.stats.calls_skipped += 1
|
124
|
+
|
125
|
+
def handle_event__line(self, frame):
|
126
|
+
return self.add_line(frame)
|
127
|
+
|
128
|
+
|
129
|
+
def handle_event__return(self, frame, return_value=None):
|
130
|
+
if return_value and self.config.capture_extra_data:
|
131
|
+
extra_data = { EXTRA_DATA__RETURN_VALUE : return_value}
|
132
|
+
else:
|
133
|
+
extra_data = {}
|
134
|
+
return self.stack.pop(target=frame, extra_data = extra_data)
|
135
|
+
|
136
|
+
def should_capture(self, frame): # todo: see if we can optimise these 3 lines (starting with frame.f_code) which are repeated in a number of places here
|
137
|
+
if self.config.trace_up_to_depth:
|
138
|
+
if len(self.stack) > self.config.trace_up_to_depth:
|
139
|
+
return False
|
140
|
+
|
141
|
+
capture = False
|
142
|
+
if frame:
|
143
|
+
code = frame.f_code # Get code object from frame
|
144
|
+
func_name = code.co_name # Get function name
|
145
|
+
module = frame.f_globals.get("__name__", "") # Get module name
|
146
|
+
|
147
|
+
if module in GLOBAL_MODULES_TO_IGNORE: # check if we should skip this module
|
148
|
+
return False
|
149
|
+
|
150
|
+
if func_name in GLOBAL_FUNCTIONS_TO_IGNORE: # check if we should skip this function
|
151
|
+
return False
|
152
|
+
|
153
|
+
if module and func_name:
|
154
|
+
if self.config.trace_capture_all:
|
155
|
+
capture = True
|
156
|
+
else:
|
157
|
+
for item in self.config.trace_capture_start_with: # capture if the module starts with
|
158
|
+
if item: # prevent empty queries (which will always be true)
|
159
|
+
if module.startswith(item) or item =='*':
|
160
|
+
capture = True
|
161
|
+
break
|
162
|
+
for item in self.config.trace_capture_contains: # capture if module of func_name contains
|
163
|
+
if item: # prevent empty queries (which will always be true)
|
164
|
+
if item in module or item in func_name:
|
165
|
+
capture = True
|
166
|
+
break
|
167
|
+
if self.config.trace_show_internals is False and func_name.startswith('_'): # Skip private functions
|
168
|
+
capture = False
|
169
|
+
|
170
|
+
for item in self.config.trace_ignore_start_with: # Check if the module should be ignored
|
171
|
+
if module.startswith(item):
|
172
|
+
capture = False
|
173
|
+
break
|
174
|
+
return capture
|
175
|
+
|
176
|
+
def stack_json__parse_node(self, stack_node: Trace_Call__Stack_Node):
|
177
|
+
node = stack_node.data()
|
178
|
+
new_children = []
|
179
|
+
for child in node.get('children'):
|
180
|
+
new_children.append(self.stack_json__parse_node(child))
|
181
|
+
node['children'] = new_children
|
182
|
+
return node
|
183
|
+
|
184
|
+
def stack_top(self):
|
185
|
+
if self.stack:
|
186
|
+
return self.stack[-1]
|
187
|
+
|
188
|
+
def trace_calls(self, frame, event, arg):
|
189
|
+
if event == 'call':
|
190
|
+
self.stats.calls +=1
|
191
|
+
self.handle_event__call(frame) # todo: handle bug with locals which need to be serialised, since it's value will change
|
192
|
+
elif event == 'return':
|
193
|
+
self.stats.returns += 1
|
194
|
+
self.handle_event__return(frame, arg)
|
195
|
+
elif event == 'exception':
|
196
|
+
self.stats.exceptions +=1 # for now don't handle exception events
|
197
|
+
elif event == 'line':
|
198
|
+
self.handle_event__line(frame)
|
199
|
+
self.stats.lines +=1
|
200
|
+
else:
|
201
|
+
self.stats.unknowns += 1
|
202
|
+
|
203
|
+
return self.trace_calls
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
def traces(self):
|
208
|
+
def map_traces(node, all_traces):
|
209
|
+
if node:
|
210
|
+
all_traces.append(node)
|
211
|
+
for child in node.children:
|
212
|
+
map_traces(child, all_traces)
|
213
|
+
result = []
|
214
|
+
map_traces(self.stack.root_node, result)
|
215
|
+
return result
|