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.
Files changed (260) hide show
  1. osbot_utils/__init__.py +1 -0
  2. osbot_utils/base_classes/Cache_Pickle.py +129 -0
  3. osbot_utils/base_classes/Kwargs_To_Disk.py +27 -0
  4. osbot_utils/base_classes/Kwargs_To_Self.py +308 -0
  5. osbot_utils/base_classes/Type_Safe__List.py +14 -0
  6. osbot_utils/base_classes/__init__.py +0 -0
  7. osbot_utils/context_managers/__init__.py +0 -0
  8. osbot_utils/context_managers/capture_duration.py +33 -0
  9. osbot_utils/decorators/__init__.py +0 -0
  10. osbot_utils/decorators/classes/__init__.py +0 -0
  11. osbot_utils/decorators/classes/singleton.py +9 -0
  12. osbot_utils/decorators/lists/__init__.py +0 -0
  13. osbot_utils/decorators/lists/filter_list.py +12 -0
  14. osbot_utils/decorators/lists/group_by.py +21 -0
  15. osbot_utils/decorators/lists/index_by.py +27 -0
  16. osbot_utils/decorators/methods/__init__.py +0 -0
  17. osbot_utils/decorators/methods/cache.py +19 -0
  18. osbot_utils/decorators/methods/cache_on_function.py +56 -0
  19. osbot_utils/decorators/methods/cache_on_self.py +78 -0
  20. osbot_utils/decorators/methods/cache_on_tmp.py +71 -0
  21. osbot_utils/decorators/methods/capture_exception.py +37 -0
  22. osbot_utils/decorators/methods/capture_status.py +20 -0
  23. osbot_utils/decorators/methods/catch.py +13 -0
  24. osbot_utils/decorators/methods/context.py +11 -0
  25. osbot_utils/decorators/methods/depreciated.py +79 -0
  26. osbot_utils/decorators/methods/function_type_check.py +62 -0
  27. osbot_utils/decorators/methods/obj_as_context.py +6 -0
  28. osbot_utils/decorators/methods/remove_return_value.py +22 -0
  29. osbot_utils/decorators/methods/required_fields.py +19 -0
  30. osbot_utils/fluent/Fluent_Dict.py +19 -0
  31. osbot_utils/fluent/Fluent_List.py +44 -0
  32. osbot_utils/fluent/__init__.py +1 -0
  33. osbot_utils/graphs/__init__.py +0 -0
  34. osbot_utils/graphs/mermaid/Mermaid.py +75 -0
  35. osbot_utils/graphs/mermaid/Mermaid__Edge.py +49 -0
  36. osbot_utils/graphs/mermaid/Mermaid__Graph.py +93 -0
  37. osbot_utils/graphs/mermaid/Mermaid__Node.py +69 -0
  38. osbot_utils/graphs/mermaid/Mermaid__Renderer.py +54 -0
  39. osbot_utils/graphs/mermaid/configs/Mermaid__Edge__Config.py +7 -0
  40. osbot_utils/graphs/mermaid/configs/Mermaid__Node__Config.py +9 -0
  41. osbot_utils/graphs/mermaid/configs/Mermaid__Render__Config.py +7 -0
  42. osbot_utils/graphs/mermaid/examples/Mermaid_Examples__FlowChart.py +98 -0
  43. osbot_utils/graphs/mermaid/models/Mermaid__Diagram_Direction.py +9 -0
  44. osbot_utils/graphs/mermaid/models/Mermaid__Diagram__Type.py +17 -0
  45. osbot_utils/graphs/mermaid/models/Mermaid__Node__Shape.py +30 -0
  46. osbot_utils/graphs/mgraph/MGraph.py +53 -0
  47. osbot_utils/graphs/mgraph/MGraph__Config.py +7 -0
  48. osbot_utils/graphs/mgraph/MGraph__Data.py +139 -0
  49. osbot_utils/graphs/mgraph/MGraph__Edge.py +27 -0
  50. osbot_utils/graphs/mgraph/MGraph__Node.py +33 -0
  51. osbot_utils/graphs/mgraph/MGraph__Random_Graphs.py +27 -0
  52. osbot_utils/graphs/mgraph/MGraph__Serializer.py +43 -0
  53. osbot_utils/graphs/mgraph/MGraphs.py +17 -0
  54. osbot_utils/graphs/mgraph/__init__.py +0 -0
  55. osbot_utils/helpers/CPrint.py +98 -0
  56. osbot_utils/helpers/Dict_To_Attr.py +7 -0
  57. osbot_utils/helpers/Local_Cache.py +111 -0
  58. osbot_utils/helpers/Local_Caches.py +54 -0
  59. osbot_utils/helpers/Print_Table.py +369 -0
  60. osbot_utils/helpers/Python_Audit.py +45 -0
  61. osbot_utils/helpers/Random_Seed.py +27 -0
  62. osbot_utils/helpers/SCP.py +58 -0
  63. osbot_utils/helpers/SSH.py +151 -0
  64. osbot_utils/helpers/Type_Registry.py +16 -0
  65. osbot_utils/helpers/__init__.py +0 -0
  66. osbot_utils/helpers/ast/Ast.py +35 -0
  67. osbot_utils/helpers/ast/Ast_Base.py +124 -0
  68. osbot_utils/helpers/ast/Ast_Data.py +28 -0
  69. osbot_utils/helpers/ast/Ast_Load.py +62 -0
  70. osbot_utils/helpers/ast/Ast_Merge.py +26 -0
  71. osbot_utils/helpers/ast/Ast_Node.py +117 -0
  72. osbot_utils/helpers/ast/Ast_Visit.py +85 -0
  73. osbot_utils/helpers/ast/Call_Tree.py +38 -0
  74. osbot_utils/helpers/ast/__init__.py +145 -0
  75. osbot_utils/helpers/ast/nodes/Ast_Add.py +6 -0
  76. osbot_utils/helpers/ast/nodes/Ast_Alias.py +6 -0
  77. osbot_utils/helpers/ast/nodes/Ast_And.py +6 -0
  78. osbot_utils/helpers/ast/nodes/Ast_Argument.py +7 -0
  79. osbot_utils/helpers/ast/nodes/Ast_Arguments.py +10 -0
  80. osbot_utils/helpers/ast/nodes/Ast_Assert.py +7 -0
  81. osbot_utils/helpers/ast/nodes/Ast_Assign.py +8 -0
  82. osbot_utils/helpers/ast/nodes/Ast_Attribute.py +9 -0
  83. osbot_utils/helpers/ast/nodes/Ast_Aug_Assign.py +9 -0
  84. osbot_utils/helpers/ast/nodes/Ast_Bin_Op.py +8 -0
  85. osbot_utils/helpers/ast/nodes/Ast_Bool_Op.py +7 -0
  86. osbot_utils/helpers/ast/nodes/Ast_Break.py +7 -0
  87. osbot_utils/helpers/ast/nodes/Ast_Call.py +17 -0
  88. osbot_utils/helpers/ast/nodes/Ast_Class_Def.py +9 -0
  89. osbot_utils/helpers/ast/nodes/Ast_Compare.py +9 -0
  90. osbot_utils/helpers/ast/nodes/Ast_Comprehension.py +10 -0
  91. osbot_utils/helpers/ast/nodes/Ast_Constant.py +6 -0
  92. osbot_utils/helpers/ast/nodes/Ast_Continue.py +7 -0
  93. osbot_utils/helpers/ast/nodes/Ast_Dict.py +8 -0
  94. osbot_utils/helpers/ast/nodes/Ast_Eq.py +6 -0
  95. osbot_utils/helpers/ast/nodes/Ast_Except_Handler.py +9 -0
  96. osbot_utils/helpers/ast/nodes/Ast_Expr.py +7 -0
  97. osbot_utils/helpers/ast/nodes/Ast_For.py +10 -0
  98. osbot_utils/helpers/ast/nodes/Ast_Function_Def.py +17 -0
  99. osbot_utils/helpers/ast/nodes/Ast_Generator_Exp.py +8 -0
  100. osbot_utils/helpers/ast/nodes/Ast_Gt.py +7 -0
  101. osbot_utils/helpers/ast/nodes/Ast_GtE.py +7 -0
  102. osbot_utils/helpers/ast/nodes/Ast_If.py +9 -0
  103. osbot_utils/helpers/ast/nodes/Ast_If_Exp.py +9 -0
  104. osbot_utils/helpers/ast/nodes/Ast_Import.py +7 -0
  105. osbot_utils/helpers/ast/nodes/Ast_Import_From.py +7 -0
  106. osbot_utils/helpers/ast/nodes/Ast_In.py +6 -0
  107. osbot_utils/helpers/ast/nodes/Ast_Is.py +6 -0
  108. osbot_utils/helpers/ast/nodes/Ast_Is_Not.py +7 -0
  109. osbot_utils/helpers/ast/nodes/Ast_Keyword.py +8 -0
  110. osbot_utils/helpers/ast/nodes/Ast_Lambda.py +8 -0
  111. osbot_utils/helpers/ast/nodes/Ast_List.py +8 -0
  112. osbot_utils/helpers/ast/nodes/Ast_List_Comp.py +8 -0
  113. osbot_utils/helpers/ast/nodes/Ast_Load.py +6 -0
  114. osbot_utils/helpers/ast/nodes/Ast_Lt.py +7 -0
  115. osbot_utils/helpers/ast/nodes/Ast_LtE.py +7 -0
  116. osbot_utils/helpers/ast/nodes/Ast_Mod.py +6 -0
  117. osbot_utils/helpers/ast/nodes/Ast_Module.py +20 -0
  118. osbot_utils/helpers/ast/nodes/Ast_Mult.py +6 -0
  119. osbot_utils/helpers/ast/nodes/Ast_Name.py +6 -0
  120. osbot_utils/helpers/ast/nodes/Ast_Not.py +7 -0
  121. osbot_utils/helpers/ast/nodes/Ast_Not_Eq.py +7 -0
  122. osbot_utils/helpers/ast/nodes/Ast_Not_In.py +6 -0
  123. osbot_utils/helpers/ast/nodes/Ast_Or.py +7 -0
  124. osbot_utils/helpers/ast/nodes/Ast_Pass.py +7 -0
  125. osbot_utils/helpers/ast/nodes/Ast_Pow.py +7 -0
  126. osbot_utils/helpers/ast/nodes/Ast_Raise.py +8 -0
  127. osbot_utils/helpers/ast/nodes/Ast_Return.py +7 -0
  128. osbot_utils/helpers/ast/nodes/Ast_Set.py +7 -0
  129. osbot_utils/helpers/ast/nodes/Ast_Slice.py +8 -0
  130. osbot_utils/helpers/ast/nodes/Ast_Starred.py +8 -0
  131. osbot_utils/helpers/ast/nodes/Ast_Store.py +7 -0
  132. osbot_utils/helpers/ast/nodes/Ast_Sub.py +7 -0
  133. osbot_utils/helpers/ast/nodes/Ast_Subscript.py +8 -0
  134. osbot_utils/helpers/ast/nodes/Ast_Try.py +9 -0
  135. osbot_utils/helpers/ast/nodes/Ast_Tuple.py +9 -0
  136. osbot_utils/helpers/ast/nodes/Ast_Unary_Op.py +7 -0
  137. osbot_utils/helpers/ast/nodes/Ast_While.py +8 -0
  138. osbot_utils/helpers/ast/nodes/Ast_With.py +7 -0
  139. osbot_utils/helpers/ast/nodes/Ast_With_Item.py +7 -0
  140. osbot_utils/helpers/ast/nodes/Ast_Yield.py +7 -0
  141. osbot_utils/helpers/ast/nodes/__init__.py +0 -0
  142. osbot_utils/helpers/html/Dict_To_Css.py +20 -0
  143. osbot_utils/helpers/html/Dict_To_Html.py +59 -0
  144. osbot_utils/helpers/html/Dict_To_Tags.py +88 -0
  145. osbot_utils/helpers/html/Html_To_Dict.py +75 -0
  146. osbot_utils/helpers/html/Html_To_Tag.py +20 -0
  147. osbot_utils/helpers/html/Tag__Base.py +91 -0
  148. osbot_utils/helpers/html/Tag__Body.py +5 -0
  149. osbot_utils/helpers/html/Tag__Div.py +5 -0
  150. osbot_utils/helpers/html/Tag__H.py +9 -0
  151. osbot_utils/helpers/html/Tag__HR.py +5 -0
  152. osbot_utils/helpers/html/Tag__Head.py +32 -0
  153. osbot_utils/helpers/html/Tag__Html.py +42 -0
  154. osbot_utils/helpers/html/Tag__Link.py +17 -0
  155. osbot_utils/helpers/html/Tag__Style.py +25 -0
  156. osbot_utils/helpers/html/__init__.py +0 -0
  157. osbot_utils/helpers/pubsub/Event__Queue.py +95 -0
  158. osbot_utils/helpers/pubsub/PubSub__Client.py +53 -0
  159. osbot_utils/helpers/pubsub/PubSub__Room.py +13 -0
  160. osbot_utils/helpers/pubsub/PubSub__Server.py +94 -0
  161. osbot_utils/helpers/pubsub/PubSub__Sqlite.py +24 -0
  162. osbot_utils/helpers/pubsub/__init__.py +0 -0
  163. osbot_utils/helpers/pubsub/schemas/Schema__Event.py +15 -0
  164. osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py +7 -0
  165. osbot_utils/helpers/pubsub/schemas/Schema__Event__Disconnect.py +7 -0
  166. osbot_utils/helpers/pubsub/schemas/Schema__Event__Join_Room.py +8 -0
  167. osbot_utils/helpers/pubsub/schemas/Schema__Event__Leave_Room.py +8 -0
  168. osbot_utils/helpers/pubsub/schemas/Schema__Event__Message.py +7 -0
  169. osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py +8 -0
  170. osbot_utils/helpers/pubsub/schemas/__init__.py +0 -0
  171. osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py +51 -0
  172. osbot_utils/helpers/sqlite/Sqlite__Cursor.py +87 -0
  173. osbot_utils/helpers/sqlite/Sqlite__Database.py +137 -0
  174. osbot_utils/helpers/sqlite/Sqlite__Field.py +70 -0
  175. osbot_utils/helpers/sqlite/Sqlite__Globals.py +5 -0
  176. osbot_utils/helpers/sqlite/Sqlite__Table.py +293 -0
  177. osbot_utils/helpers/sqlite/Sqlite__Table__Create.py +96 -0
  178. osbot_utils/helpers/sqlite/Temp_Sqlite__Database__Disk.py +17 -0
  179. osbot_utils/helpers/sqlite/Temp_Sqlite__Table.py +23 -0
  180. osbot_utils/helpers/sqlite/__init__.py +0 -0
  181. osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests.py +214 -0
  182. osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests__Patch.py +63 -0
  183. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Files.py +23 -0
  184. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Graph.py +47 -0
  185. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Json.py +83 -0
  186. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +20 -0
  187. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Requests.py +39 -0
  188. osbot_utils/helpers/sqlite/domains/__init__.py +0 -0
  189. osbot_utils/helpers/sqlite/domains/schemas/Schema__Table__Requests.py +12 -0
  190. osbot_utils/helpers/sqlite/domains/schemas/__init__.py +0 -0
  191. osbot_utils/helpers/sqlite/models/Sqlite__Field__Type.py +37 -0
  192. osbot_utils/helpers/sqlite/models/__init__.py +0 -0
  193. osbot_utils/helpers/sqlite/sample_data/Sqlite__Sample_Data__Chinook.py +116 -0
  194. osbot_utils/helpers/sqlite/sample_data/__init__.py +0 -0
  195. osbot_utils/helpers/sqlite/sql_builder/SQL_Builder.py +159 -0
  196. osbot_utils/helpers/sqlite/sql_builder/SQL_Builder__Select.py +12 -0
  197. osbot_utils/helpers/sqlite/sql_builder/__init__.py +0 -0
  198. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Config.py +63 -0
  199. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py +46 -0
  200. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py +45 -0
  201. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py +52 -0
  202. osbot_utils/helpers/sqlite/tables/__init__.py +0 -0
  203. osbot_utils/helpers/trace/Trace_Call.py +120 -0
  204. osbot_utils/helpers/trace/Trace_Call__Config.py +94 -0
  205. osbot_utils/helpers/trace/Trace_Call__Graph.py +26 -0
  206. osbot_utils/helpers/trace/Trace_Call__Handler.py +215 -0
  207. osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +85 -0
  208. osbot_utils/helpers/trace/Trace_Call__Print_Traces.py +170 -0
  209. osbot_utils/helpers/trace/Trace_Call__Stack.py +166 -0
  210. osbot_utils/helpers/trace/Trace_Call__Stack_Node.py +59 -0
  211. osbot_utils/helpers/trace/Trace_Call__Stats.py +71 -0
  212. osbot_utils/helpers/trace/Trace_Call__View_Model.py +75 -0
  213. osbot_utils/helpers/trace/Trace_Files.py +33 -0
  214. osbot_utils/helpers/trace/__init__.py +0 -0
  215. osbot_utils/testing/Catch.py +54 -0
  216. osbot_utils/testing/Duration.py +69 -0
  217. osbot_utils/testing/Hook_Method.py +118 -0
  218. osbot_utils/testing/Log_To_Queue.py +46 -0
  219. osbot_utils/testing/Log_To_String.py +37 -0
  220. osbot_utils/testing/Logging.py +81 -0
  221. osbot_utils/testing/Patch_Print.py +52 -0
  222. osbot_utils/testing/Profiler.py +89 -0
  223. osbot_utils/testing/Stderr.py +19 -0
  224. osbot_utils/testing/Stdout.py +19 -0
  225. osbot_utils/testing/Temp_File.py +46 -0
  226. osbot_utils/testing/Temp_Folder.py +114 -0
  227. osbot_utils/testing/Temp_Sys_Path.py +13 -0
  228. osbot_utils/testing/Temp_Web_Server.py +83 -0
  229. osbot_utils/testing/Temp_Zip.py +45 -0
  230. osbot_utils/testing/Temp_Zip_In_Memory.py +90 -0
  231. osbot_utils/testing/Unit_Test.py +34 -0
  232. osbot_utils/testing/Unzip_File.py +30 -0
  233. osbot_utils/testing/__init__.py +0 -0
  234. osbot_utils/utils/Assert.py +52 -0
  235. osbot_utils/utils/Call_Stack.py +187 -0
  236. osbot_utils/utils/Csv.py +32 -0
  237. osbot_utils/utils/Dev.py +47 -0
  238. osbot_utils/utils/Exceptions.py +7 -0
  239. osbot_utils/utils/Files.py +528 -0
  240. osbot_utils/utils/Functions.py +113 -0
  241. osbot_utils/utils/Http.py +136 -0
  242. osbot_utils/utils/Int.py +6 -0
  243. osbot_utils/utils/Json.py +171 -0
  244. osbot_utils/utils/Json_Cache.py +59 -0
  245. osbot_utils/utils/Lists.py +198 -0
  246. osbot_utils/utils/Misc.py +496 -0
  247. osbot_utils/utils/Objects.py +341 -0
  248. osbot_utils/utils/Png.py +29 -0
  249. osbot_utils/utils/Process.py +73 -0
  250. osbot_utils/utils/Python_Logger.py +301 -0
  251. osbot_utils/utils/Status.py +79 -0
  252. osbot_utils/utils/Str.py +63 -0
  253. osbot_utils/utils/Version.py +16 -0
  254. osbot_utils/utils/Zip.py +97 -0
  255. osbot_utils/utils/__init__.py +16 -0
  256. osbot_utils/version +1 -0
  257. osbot_utils-1.7.7.dist-info/LICENSE +201 -0
  258. osbot_utils-1.7.7.dist-info/METADATA +46 -0
  259. osbot_utils-1.7.7.dist-info/RECORD +260 -0
  260. osbot_utils-1.7.7.dist-info/WHEEL +4 -0
@@ -0,0 +1,293 @@
1
+ import re
2
+
3
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
4
+ from osbot_utils.decorators.lists.filter_list import filter_list
5
+ from osbot_utils.decorators.lists.index_by import index_by
6
+ from osbot_utils.decorators.methods.cache_on_self import cache_on_self
7
+ from osbot_utils.helpers.Print_Table import Print_Table
8
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database
9
+ from osbot_utils.helpers.sqlite.Sqlite__Globals import DEFAULT_FIELD_NAME__ID, ROW_BASE_CLASS, SQL_TABLE__MODULE_NAME__ROW_SCHEMA
10
+ from osbot_utils.helpers.sqlite.models.Sqlite__Field__Type import Sqlite__Field__Type
11
+ from osbot_utils.utils.Dev import pprint
12
+ from osbot_utils.utils.Json import json_load
13
+ from osbot_utils.utils.Misc import list_set
14
+ from osbot_utils.utils.Objects import base_types, default_value, bytes_to_obj, obj_to_bytes
15
+ from osbot_utils.utils.Str import str_cap_snake_case
16
+
17
+ class Sqlite__Table(Kwargs_To_Self):
18
+ database : Sqlite__Database
19
+ table_name : str
20
+ row_schema : type
21
+ auto_pickle_blob: bool = False
22
+
23
+ def __setattr__(self, key, value):
24
+ if key =='table_name': # SQL injection protection
25
+ if re.search(r'[^a-zA-Z0-9_-]',value): # make sure table name cannot be used to inject SQL, str_safe uses r'[^a-zA-Z0-9_-]' regex, i.e. only allows letter, numbers and the chars - _
26
+ raise ValueError( "Invalid table name. Table names can only contain alphanumeric characters, numbers, underscores, and hyphens.")
27
+
28
+ super().__setattr__(key, value)
29
+
30
+ def _table_create(self): # todo: Sqlite__Table__Create needs to be refactored (since that was created before we had support for table_class )
31
+ from osbot_utils.helpers.sqlite.Sqlite__Table__Create import Sqlite__Table__Create
32
+ table_create = Sqlite__Table__Create(self.table_name) # todo: fix this workflow
33
+ table_create.table = self
34
+ return table_create # since it is weird to have to overwrite the table vale of Sqlite__Table__Create
35
+
36
+ def add_row(self, **row_data):
37
+ new_row = self.new_row_obj(row_data)
38
+ return self.row_add(new_row)
39
+
40
+ def add_row_and_commit(self, **row_data):
41
+ new_row = self.new_row_obj(row_data)
42
+ return self.row_add_and_commit(new_row)
43
+
44
+ def clear(self):
45
+ sql_query = self.sql_builder().command__delete_table()
46
+ return self.cursor().execute_and_commit(sql_query)
47
+
48
+ def create(self):
49
+ table_create = self._table_create()
50
+ return table_create.create_table__from_row_schema(self.row_schema)
51
+
52
+ def commit(self):
53
+ return self.cursor().commit()
54
+
55
+ def connection(self):
56
+ return self.database.connection()
57
+
58
+ def cursor(self):
59
+ return self.database.cursor()
60
+
61
+ def delete(self):
62
+ if self.exists() is False: # if table doesn't exist
63
+ return False # return False
64
+ self.cursor().table_delete(self.table_name) # delete table
65
+ return self.exists() is False # confirm table does not exist
66
+
67
+ def exists(self):
68
+ return self.cursor().table_exists(self.table_name)
69
+
70
+ def fields(self):
71
+ return self.schema(index_by='name')
72
+
73
+ @cache_on_self
74
+ def fields__cached(self):
75
+ return self.fields()
76
+
77
+ def fields_data__from_raw_json(self, target_field): # todo: see if this should be refactored into a Select/Data filtering class
78
+ fields_data = []
79
+ for raw_field_data in self.select_field_values(target_field):
80
+ fields_data.append(json_load(raw_field_data))
81
+ return fields_data
82
+
83
+ def fields_types__cached(self, exclude_id=False):
84
+ fields_types = {}
85
+ for field_name, field_data in self.fields__cached().items():
86
+ if exclude_id and field_name == DEFAULT_FIELD_NAME__ID:
87
+ continue
88
+ sqlite_field_type = field_data['type']
89
+ field_type = Sqlite__Field__Type.enum_map().get(sqlite_field_type)
90
+ fields_types[field_name] = field_type
91
+ return fields_types
92
+
93
+ def fields_names__cached(self, exclude_id=False, include_star_field=False):
94
+ field_names = list_set(self.fields__cached())
95
+ if exclude_id:
96
+ field_names.remove(DEFAULT_FIELD_NAME__ID)
97
+ if include_star_field:
98
+ field_names.append('*')
99
+ return field_names
100
+
101
+ def index_create(self, index_field):
102
+ if index_field not in self.fields_names__cached():
103
+ raise ValueError(f"in index_create, invalid target_field: {index_field}")
104
+
105
+ index_name = self.index_name(index_field)
106
+ sql_query = f'CREATE INDEX IF NOT EXISTS {index_name} ON {self.table_name}({index_field});'
107
+ return self.cursor().execute_and_commit(sql_query)
108
+
109
+ def index_delete(self, index_name):
110
+ sql_query = f'DROP INDEX IF EXISTS {index_name};'
111
+ return self.cursor().execute_and_commit(sql_query)
112
+
113
+ def index_exists(self, index_field):
114
+ index_name = self.index_name(index_field)
115
+ return index_name in self.indexes()
116
+
117
+ def index_name(self, index_field):
118
+ return f'idx__{self.table_name}__{index_field}'
119
+
120
+ def list_of_field_name_from_rows(self, rows, field_name):
121
+ return [row[field_name] for row in rows]
122
+
123
+ def indexes(self):
124
+ field_name = 'name'
125
+ return_fields = [field_name]
126
+ table_sqlite_master = self.database.table__sqlite_master()
127
+ table_type = 'index'
128
+ query_conditions = {'type': table_type, 'tbl_name': self.table_name}
129
+ sql_query, params = table_sqlite_master.sql_builder().query_select_fields_with_conditions(return_fields, query_conditions)
130
+ rows = table_sqlite_master.cursor().execute__fetch_all(sql_query, params)
131
+ return table_sqlite_master.list_of_field_name_from_rows(rows, field_name)
132
+
133
+ def new_row_obj(self, row_data=None):
134
+ if self.row_schema:
135
+ new_obj = self.row_schema()
136
+ if row_data and ROW_BASE_CLASS in base_types(new_obj):
137
+ row_data = self.parse_new_row_data(row_data)
138
+ new_obj.update_from_kwargs(**row_data)
139
+ return new_obj
140
+
141
+ def not_exists(self):
142
+ return self.exists() is False
143
+
144
+ def parse_new_row_data(self, row_data):
145
+ if row_data:
146
+ if self.auto_pickle_blob:
147
+ fields = self.fields__cached()
148
+ picked_row_data = {}
149
+ for field_name, field_value in row_data.items():
150
+ field_type = fields.get(field_name, {}).get('type')
151
+ if field_type == 'BLOB':
152
+ picked_row_data[field_name] = obj_to_bytes(field_value)
153
+ else:
154
+ picked_row_data[field_name] = field_value
155
+ return picked_row_data
156
+ return row_data
157
+ def parse_row(self, row):
158
+ if row and self.auto_pickle_blob:
159
+ fields = self.fields__cached()
160
+ for field_name, field_value in row.items():
161
+ field_type = fields.get(field_name, {}).get('type')
162
+ if field_type == 'BLOB':
163
+ row[field_name] = bytes_to_obj(field_value)
164
+ return row
165
+
166
+ def parse_rows(self, rows):
167
+ return [self.parse_row(row) for row in rows]
168
+
169
+ def print(self, **kwargs):
170
+ return Print_Table(**kwargs).print(self.rows())
171
+
172
+ def row_add(self, row_obj=None):
173
+ invalid_reason = self.sql_builder().validate_row_obj(row_obj)
174
+ if invalid_reason:
175
+ raise Exception(f"in row_add the provided row_obj is not valid: {invalid_reason}")
176
+ return self.row_add_record(row_obj.__dict__)
177
+
178
+ def row_add_and_commit(self, row_obj=None):
179
+ if self.row_add(row_obj).get('status') == 'ok':
180
+ self.commit()
181
+ return row_obj # this allows the original callers to see the actual object that was added to the table
182
+
183
+ def row_add_record(self, record):
184
+ validation_result = self.validate_record_with_schema(record)
185
+ if validation_result:
186
+ raise ValueError(f"row_add_record, validation_result for provided record failed with {validation_result}")
187
+
188
+ sql_command,params = self.sql_builder().command_for_insert(record)
189
+ return self.cursor().execute(sql_command, params) # Execute the SQL statement with the filtered data values
190
+
191
+ def row_schema__create_from_current_field_types(self):
192
+ exclude_field_id = True # don't include the id field since in most cases the row_schema doesn't include it
193
+ field_types = self.fields_types__cached(exclude_id=exclude_field_id) # mapping with field name to field type (in python)
194
+ caps_table_name = str_cap_snake_case(self.table_name)
195
+ dynamic_class_name = f'Row_Schema__{caps_table_name}' # name that we will give to the dynamic class generated
196
+ dynamic_class_dict = { k: default_value(v) for k, v in field_types.items()} # assign the field values its default value (for that type)
197
+ dynamic_class_dict['__module__'] = SQL_TABLE__MODULE_NAME__ROW_SCHEMA # set the module name
198
+ Dynamic_Class = type(dynamic_class_name, (ROW_BASE_CLASS,), dynamic_class_dict) # Create the dynamic class
199
+ Dynamic_Class.__annotations__ = field_types # Set annotations of the new Dynamic_Class to be the mappings we have from field_types
200
+ return Dynamic_Class # return the Dynamic class (whose fields should match the field_types)
201
+
202
+ def row_schema__set_from_field_types(self):
203
+ self.row_schema = self.row_schema__create_from_current_field_types()
204
+ return self
205
+
206
+ def row_update(self, update_fields, query_conditions ):
207
+ sql_query, params = self.sql_builder().sql_query_update_with_conditions(update_fields, query_conditions)
208
+ return self.cursor().execute_and_commit(sql_query, params)
209
+
210
+ def rows(self, fields_names=None, limit=None):
211
+ sql_query = self.sql_builder(limit=limit).query_for_fields(fields_names)
212
+ rows = self.cursor().execute__fetch_all(sql_query)
213
+ return self.parse_rows(rows)
214
+
215
+ def rows_add(self, records, commit=True): # todo: refactor to use row_add
216
+ for record in records:
217
+ if type(record) is dict:
218
+ self.row_add_record(record)
219
+ else:
220
+ self.row_add(row_obj=record)
221
+ if commit:
222
+ self.cursor().commit()
223
+ return self
224
+
225
+ def rows_delete_where(self, **query_conditions):
226
+ sql_query,params = self.sql_builder().command__delete_where(query_conditions)
227
+ return self.cursor().execute_and_commit(sql_query,params)
228
+
229
+ def select_row_where(self, **kwargs):
230
+ rows = self.select_rows_where(**kwargs) # execute the query
231
+ if len(rows) == 1: # only return a result if there is one row
232
+ return rows[0]
233
+ return None # return None if there no match or more than one match
234
+
235
+ def select_rows_where(self, **kwargs):
236
+ sql_query, params = self.sql_builder().query_for_select_rows_where(**kwargs)
237
+ rows = self.cursor().execute__fetch_all(sql_query, params) # Execute the query and return the results
238
+ return self.parse_rows(rows)
239
+
240
+ def select_rows_where_one(self, **kwargs):
241
+ sql_query, params = self.sql_builder().query_for_select_rows_where(**kwargs)
242
+ row = self.cursor().execute__fetch_one(sql_query, params) # Execute the query and return the results
243
+ return self.parse_row(row)
244
+
245
+ def select_field_values(self, field_name):
246
+ if field_name not in self.fields__cached():
247
+ raise ValueError(f'in select_all_vales_from_field, the provide field_name "{field_name}" does not exist in the current table "{self.table_name}"')
248
+
249
+ sql_query = self.sql_builder().query_for_fields([field_name])
250
+ rows = self.cursor().execute__fetch_all(sql_query) # Execute the SQL query and get all rows
251
+ all_rows = self.parse_rows(rows)
252
+ all_values = [row[field_name] for row in all_rows] # Extract the desired field from each row in the result set
253
+ return all_values
254
+
255
+ @index_by
256
+ def schema(self):
257
+ return self.cursor().table_schema(self.table_name)
258
+
259
+ @filter_list
260
+ def schema__by_name_type(self):
261
+ return {item.get('name'): item.get('type') for item in self.schema()}
262
+
263
+ def size(self):
264
+ sql_query = self.sql_builder().query_for_size()
265
+ result = self.cursor().execute__fetch_one(sql_query)
266
+ return result.get('size')
267
+
268
+ @cache_on_self
269
+ def sql_builder(self, limit=None):
270
+ from osbot_utils.helpers.sqlite.sql_builder.SQL_Builder import SQL_Builder
271
+ return SQL_Builder(table=self, limit=limit)
272
+
273
+ def validate_record_with_schema(self, record): # todo: refactor out to a validator class
274
+ schema = self.fields__cached()
275
+
276
+ extra_keys = [key for key in record if key not in schema] # Check for keys in record that are not in the schema
277
+ if extra_keys:
278
+ return f'Validation error: Unrecognized keys {extra_keys} in record.'
279
+ return '' # If we reach here, the record is valid
280
+
281
+ # query helpers
282
+ def contains(self, **kwargs):
283
+ result = self.where_one(**kwargs)
284
+ return result is not None
285
+
286
+ def not_contains(self, **kwargs):
287
+ return self.contains(**kwargs) is False
288
+
289
+ def where(self, **kwargs):
290
+ return self.select_rows_where(**kwargs)
291
+
292
+ def where_one(self, **kwargs):
293
+ return self.select_rows_where_one(**kwargs)
@@ -0,0 +1,96 @@
1
+ import inspect
2
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
3
+ from osbot_utils.decorators.lists.filter_list import filter_list
4
+ from osbot_utils.helpers.sqlite.Sqlite__Field import Sqlite__Field
5
+ from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table, DEFAULT_FIELD_NAME__ID
6
+ from osbot_utils.helpers.sqlite.models.Sqlite__Field__Type import Sqlite__Field__Type
7
+
8
+ class Sqlite__Table__Create(Kwargs_To_Self):
9
+ fields : list[Sqlite__Field]
10
+ table : Sqlite__Table
11
+
12
+ def __init__(self, table_name):
13
+ super().__init__()
14
+ self.table.table_name = table_name
15
+ self.set_default_fields()
16
+
17
+ def add_field(self, field_data: dict):
18
+ sqlite_field = Sqlite__Field.from_json(field_data)
19
+ if sqlite_field:
20
+ self.fields.append(sqlite_field)
21
+ return True
22
+ return False
23
+
24
+ def add_fields(self, fields_data:list[dict]):
25
+ results = []
26
+ if fields_data:
27
+ for field_data in fields_data:
28
+ results.append(self.add_field(field_data))
29
+ return results
30
+
31
+ def add_fields_from_class(self, table_class):
32
+ if inspect.isclass(table_class):
33
+ for field_name, field_type in table_class.__annotations__.items():
34
+ self.add_field_with_type(field_name, field_type)
35
+ return self
36
+
37
+ def add_field_with_type(self, field_name, field_type):
38
+ if inspect.isclass(field_type):
39
+ field_type = Sqlite__Field__Type.type_map().get(field_type)
40
+
41
+ return self.add_field(dict(name=field_name, type=field_type))
42
+
43
+ def add_field__text(self, field_name):
44
+ return self.add_field_with_type(field_name=field_name, field_type=str)
45
+
46
+ def add_fields__text(self, *fields_name):
47
+ for field_name in fields_name:
48
+ self.add_field__text(field_name=field_name)
49
+ return self
50
+
51
+ def create_table(self):
52
+ sql_query = self.sql_for__create_table()
53
+ if self.table.not_exists():
54
+ self.table.cursor().execute(sql_query)
55
+ return self.table.exists()
56
+ return False
57
+
58
+ def create_table__from_row_schema(self, row_schema): # todo add check if there is an index field (which is now supported since it clashes with the one that is added by default)
59
+ self.add_fields_from_class(row_schema)
60
+ self.table.row_schema = row_schema
61
+ return self.create_table()
62
+
63
+ @filter_list
64
+ def fields_json(self):
65
+ return [field.json() for field in self.fields]
66
+
67
+ def fields__by_name_type(self):
68
+ return { item.get('name'): item.get('type') for item in self.fields_json() }
69
+
70
+ def fields_reset(self):
71
+ self.fields = []
72
+ return self
73
+
74
+ def database(self):
75
+ return self.table.database
76
+
77
+ def set_default_fields(self):
78
+ self.add_field(dict(name=DEFAULT_FIELD_NAME__ID, type="INTEGER", pk=True)) # by default every table has an id field
79
+ return self
80
+
81
+ def sql_for__create_table(self):
82
+ field_definitions = [field.text_for_create_table() for field in self.fields]
83
+ primary_keys = [field.name for field in self.fields if field.pk]
84
+ foreign_keys_constraints = [field.text_for_create_table() for field in self.fields if field.is_foreign_key]
85
+
86
+ # Handling composite primary keys if necessary
87
+ if len(primary_keys) > 1:
88
+ pk_constraint = f"PRIMARY KEY ({', '.join(primary_keys)})"
89
+ field_definitions.append(pk_constraint)
90
+
91
+ # Adding foreign key constraints separately if there are any
92
+ if foreign_keys_constraints:
93
+ field_definitions.extend(foreign_keys_constraints)
94
+
95
+ table_definition = f"CREATE TABLE {self.table.table_name} ({', '.join(field_definitions)});"
96
+ return table_definition
@@ -0,0 +1,17 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database, SQLITE_DATABASE_PATH__IN_MEMORY
3
+
4
+
5
+ class Temp_Sqlite__Database__Disk(Kwargs_To_Self):
6
+ database : Sqlite__Database
7
+
8
+ def __init__(self):
9
+ super().__init__()
10
+ self.database.in_memory = False
11
+
12
+ def __enter__(self):
13
+ self.database.connect()
14
+ return self.database
15
+
16
+ def __exit__(self, exc_type, exc_val, exc_tb):
17
+ self.database.delete()
@@ -0,0 +1,23 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database
3
+ from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
4
+ from osbot_utils.utils.Dev import pprint
5
+ from osbot_utils.utils.Misc import random_text
6
+
7
+
8
+ class Temp_Sqlite__Table(Kwargs_To_Self):
9
+ table_name : str = random_text(prefix='random_table')
10
+ table_fields : list
11
+ table : Sqlite__Table
12
+
13
+
14
+ def __init__(self):
15
+ super().__init__()
16
+ self.table.table_name = self.table_name
17
+
18
+ def __enter__(self):
19
+ self.table.create()
20
+ return self.table
21
+
22
+ def __exit__(self, exc_type, exc_val, exc_tb):
23
+ self.table.delete()
File without changes
@@ -0,0 +1,214 @@
1
+ import types
2
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
3
+ from osbot_utils.helpers.sqlite.domains.Sqlite__DB__Requests import Sqlite__DB__Requests
4
+ from osbot_utils.utils.Json import json_dumps, json_loads
5
+ from osbot_utils.utils.Misc import str_sha256, timestamp_utc_now
6
+ from osbot_utils.utils.Objects import pickle_save_to_bytes, pickle_load_from_bytes
7
+
8
+
9
+ class Sqlite__Cache__Requests(Kwargs_To_Self):
10
+ add_timestamp : bool = True
11
+ enabled : bool = True
12
+ update_mode : bool = False
13
+ cache_only_mode : bool = False
14
+ sqlite_requests : Sqlite__DB__Requests = None
15
+ pickle_response : bool = False
16
+ capture_exceptions: bool = False # once this is working, it might be more useful to have this set to true
17
+ exception_classes : list
18
+ on_invoke_target : types.FunctionType
19
+
20
+ def __init__(self, db_path=None, db_name=None, table_name=None):
21
+ self.sqlite_requests = Sqlite__DB__Requests(db_path=db_path, db_name=db_name, table_name=table_name)
22
+ super().__init__()
23
+
24
+ def cache_add(self, request_data, response_data):
25
+ new_row_obj = self.create_new_cache_obj(request_data, response_data)
26
+ return self.cache_table().row_add_and_commit(new_row_obj)
27
+
28
+ def cache_delete(self, request_data):
29
+ request_data = json_dumps(request_data)
30
+ request_data_sha256 = str_sha256(request_data)
31
+ return self.cache_table().rows_delete_where(request_hash=request_data_sha256)
32
+
33
+ def cache_entries(self):
34
+ return self.cache_table().rows()
35
+
36
+ def cache_entry(self, request_data):
37
+ request_data = json_dumps(request_data)
38
+ request_data_sha256 = str_sha256(request_data)
39
+ data = self.cache_table().select_rows_where(request_hash=request_data_sha256)
40
+ if len(data) > 0: # todo: add logic to handle (or log), where there are multiple entries with the same hash
41
+ return data[0]
42
+ return {}
43
+
44
+ def cache_entry_comments(self, model_id, body):
45
+ cache_entry = self.cache_entry_for_request_params(model_id=model_id, body=body)
46
+ return cache_entry.get('comments')
47
+
48
+ def cache_entry_comments_update(self, model_id, body, new_comments):
49
+ cache_entry = self.cache_entry_for_request_params(model_id=model_id, body=body)
50
+ request_hash = cache_entry.get('request_hash')
51
+ update_fields = dict(comments=new_comments)
52
+ query_conditions = dict(request_hash=request_hash)
53
+ result = self.cache_table().row_update(update_fields, query_conditions)
54
+ return result
55
+
56
+ def cache_entry_for_request_params(self, *args, **target_kwargs):
57
+ request_data = self.cache_request_data(*args, **target_kwargs)
58
+ return self.cache_entry(request_data)
59
+
60
+ def create_new_cache_data(self, request_data, response_data):
61
+ request_data_json = json_dumps(request_data)
62
+ request_data_hash = str_sha256(request_data_json)
63
+ if self.add_timestamp:
64
+ timestamp = timestamp_utc_now()
65
+ else:
66
+ timestamp = 0
67
+ cache_cata = dict(request_data = request_data_json ,
68
+ request_hash = request_data_hash ,
69
+ response_bytes = b'' ,
70
+ response_data = '' ,
71
+ response_hash = '' ,
72
+ timestamp = timestamp )
73
+ if self.pickle_response:
74
+ cache_cata['response_bytes'] = response_data
75
+ else:
76
+ response_data_json = json_dumps(response_data)
77
+ response_data_hash = str_sha256(response_data_json)
78
+ cache_cata['response_data'] = response_data_json
79
+ cache_cata['response_hash'] = response_data_hash
80
+ return cache_cata
81
+
82
+ def create_new_cache_obj(self, request_data, response_data):
83
+ new_row_data = self.create_new_cache_data(request_data, response_data)
84
+ new_row_obj = self.cache_table().new_row_obj(new_row_data)
85
+ return new_row_obj
86
+
87
+ def cache_table(self):
88
+ return self.sqlite_requests.table_requests()
89
+
90
+ def cache_table__clear(self):
91
+ return self.cache_table().clear()
92
+
93
+ def cache_request_data(self, *args, **target_kwargs):
94
+ 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
95
+
96
+
97
+ 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
98
+ if type(request_data) is dict: # if we get an request_data obj
99
+ request_data = json_dumps(request_data) # convert it to the json dump
100
+ if type(request_data) is str: # make sure we have a string
101
+ if len(self.rows_where__request_data(request_data)) > 0: # make sure there is at least one entry to delete
102
+ self.cache_table().rows_delete_where(request_data=request_data) # delete it
103
+ return len(self.rows_where__request_data(request_data)) == 0 # confirm it was deleted
104
+ return False # if anything was not right, return False
105
+
106
+ def disable(self):
107
+ self.enabled = False
108
+ return self
109
+
110
+ def enable(self):
111
+ self.enabled = True
112
+ return self
113
+
114
+ def invoke(self, target, target_args, target_kwargs):
115
+ return self.invoke_with_cache(target, target_args, target_kwargs)
116
+
117
+ def invoke_target(self, target, target_args, target_kwargs):
118
+ if self.on_invoke_target:
119
+ raw_response = self.on_invoke_target(target, target_args, target_kwargs)
120
+ else:
121
+ raw_response = target(*target_args, **target_kwargs)
122
+ return self.transform_raw_response(raw_response)
123
+
124
+ def invoke_with_cache(self, target, target_args, target_kwargs, request_data=None):
125
+ if self.enabled is False:
126
+ if self.cache_only_mode:
127
+ return None
128
+ return self.invoke_target(target, target_args, target_kwargs)
129
+ if request_data is None:
130
+ request_data = self.cache_request_data(*target_args, **target_kwargs)
131
+ cache_entry = self.cache_entry(request_data)
132
+ if cache_entry:
133
+ if self.update_mode is True:
134
+ self.cache_delete(request_data)
135
+ else:
136
+ return self.response_data_deserialize(cache_entry)
137
+ if self.cache_only_mode is False:
138
+ return self.invoke_target__and_add_to_cache(request_data, target, target_args, target_kwargs)
139
+
140
+
141
+ def invoke_target__and_add_to_cache(self,request_data, target, target_args, target_kwargs):
142
+ try:
143
+ response_data_obj = self.invoke_target(target, target_args, target_kwargs)
144
+ response_data = self.response_data_serialize(response_data_obj)
145
+ self.cache_add(request_data=request_data, response_data=response_data)
146
+ return response_data_obj
147
+ except Exception as exception:
148
+ if self.capture_exceptions:
149
+ response_data = self.response_data_serialize(exception)
150
+ self.cache_add(request_data=request_data, response_data=response_data)
151
+ raise exception
152
+
153
+ def only_from_cache(self, value=True):
154
+ self.cache_only_mode = value
155
+ return self
156
+
157
+ def response_data_deserialize(self, cache_entry):
158
+ if self.pickle_response:
159
+ response_bytes = cache_entry.get('response_bytes')
160
+ response_data_obj = pickle_load_from_bytes(response_bytes)
161
+ else:
162
+ response_data = cache_entry.get('response_data')
163
+ response_data_obj = json_loads(response_data)
164
+ if self.capture_exceptions:
165
+ if (type(response_data_obj) is Exception or # raise if it is an exception
166
+ type(response_data_obj) in self.exception_classes): # or if one of the types that have been set as being exception classes
167
+ raise response_data_obj
168
+ # else:
169
+ # pprint(type(response_data_obj))
170
+ return response_data_obj
171
+
172
+ def response_data_serialize(self, response_data):
173
+ if self.pickle_response:
174
+ return pickle_save_to_bytes(response_data)
175
+ return response_data
176
+
177
+ def response_data_for__request_hash(self, request_hash):
178
+ rows = self.rows_where__request_hash(request_hash)
179
+ if len(rows) > 0:
180
+ cache_entry = rows[0]
181
+ response_data_obj = self.response_data_deserialize(cache_entry)
182
+ return response_data_obj
183
+ return {}
184
+
185
+ def requests_data__all(self):
186
+ requests_data = []
187
+ for row in self.cache_table().rows():
188
+ req_id = row.get('id')
189
+ request_data = row.get('request_data')
190
+ request_hash = row.get('request_hash')
191
+ request_comments = row.get('comments')
192
+ request_data_obj = json_loads(request_data)
193
+ request_data_obj['_id' ] = req_id
194
+ request_data_obj['_hash' ] = request_hash
195
+ request_data_obj['_comments'] = request_comments
196
+
197
+ requests_data.append(request_data_obj)
198
+ return requests_data
199
+
200
+ def rows_where(self, **kwargs):
201
+ return self.cache_table().select_rows_where(**kwargs)
202
+
203
+ def rows_where__request_data(self, request_data):
204
+ return self.rows_where(request_data=request_data)
205
+
206
+ def rows_where__request_hash(self, request_hash):
207
+ return self.rows_where(request_hash=request_hash)
208
+
209
+ def transform_raw_response(self, raw_response):
210
+ return raw_response
211
+
212
+ def update(self, value=True):
213
+ self.update_mode = value
214
+ return self