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,63 @@
1
+ import types
2
+
3
+ from osbot_utils.helpers.sqlite.domains.Sqlite__Cache__Requests import Sqlite__Cache__Requests
4
+ from osbot_utils.utils.Dev import pprint
5
+ from osbot_utils.utils.Misc import random_text
6
+
7
+
8
+ class Sqlite__Cache__Requests__Patch(Sqlite__Cache__Requests):
9
+ db_name : str = random_text('requests_cache_')
10
+ table_name : str = random_text('requests_table_')
11
+ pickle_response : bool = True
12
+ target_function : types.FunctionType
13
+ target_class : object
14
+ target_function_name: str
15
+
16
+ def __init__(self, db_path=None):
17
+ super().__init__(db_path=db_path, db_name=self.db_name, table_name=self.table_name)
18
+
19
+ def __enter__(self):
20
+ self.patch_apply()
21
+ return self
22
+
23
+ def __exit__(self, exc_type, exc_val, exc_tb):
24
+ self.patch_restore()
25
+ return
26
+
27
+ def delete(self):
28
+ return self.sqlite_requests.delete()
29
+
30
+ def proxy_method(self, *args, **kwargs):
31
+ request_data = self.request_data (*args, **kwargs)
32
+ target_kwargs = self.target_kwargs(*args, **kwargs)
33
+ target_args = self.target_args (*args, **kwargs)
34
+
35
+ invoke_kwargs = dict(target = self.target_function,
36
+ target_args = target_args ,
37
+ target_kwargs = target_kwargs ,
38
+ request_data = request_data )
39
+
40
+ return self.invoke_with_cache(**invoke_kwargs)
41
+
42
+ def patch_apply(self):
43
+ if (type(self.target_class) is object or
44
+ self.target_function is None or
45
+ self.target_function_name == '' ):
46
+ raise ValueError('target_function, target_object and target_function_name must be set')
47
+ def proxy(*args, **kwargs):
48
+ return self.proxy_method(*args, **kwargs)
49
+ setattr(self.target_class, self.target_function_name, proxy)
50
+ return self
51
+
52
+ def patch_restore(self):
53
+ setattr(self.target_class, self.target_function_name, self.target_function)
54
+
55
+ def request_data(self, *args, **kwargs):
56
+ return {'args' : args ,
57
+ 'kwargs': kwargs }
58
+
59
+ def target_args(self, *args, **kwargs):
60
+ return args
61
+
62
+ def target_kwargs(self, *args, **kwargs):
63
+ return kwargs
@@ -0,0 +1,23 @@
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.tables.Sqlite__Table__Files import Sqlite__Table__Files
4
+
5
+
6
+ class Sqlite__DB__Files(Sqlite__DB__Local):
7
+
8
+ def __init__(self, db_path=None, db_name=None):
9
+ super().__init__(db_path=db_path, db_name=db_name)
10
+
11
+ def add_file(self, path, contents=None, metadata=None):
12
+ return self.table_files().add_file(path, contents, metadata)
13
+
14
+ @cache_on_self
15
+ def table_files(self):
16
+ return Sqlite__Table__Files(database=self).setup()
17
+
18
+ def files(self):
19
+ return self.table_files().files()
20
+
21
+ def setup(self):
22
+ self.table_files()
23
+ return self
@@ -0,0 +1,47 @@
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.tables.Sqlite__Table__Edges import Sqlite__Table__Edges
4
+ from osbot_utils.helpers.sqlite.tables.Sqlite__Table__Nodes import Sqlite__Table__Nodes
5
+
6
+
7
+ class Sqlite__DB__Graph(Sqlite__DB__Local):
8
+
9
+ def __init__(self, db_path=None, db_name=None):
10
+ super().__init__(db_path=db_path, db_name=db_name)
11
+
12
+ def add_edge(self, source_key, target_key, value=None, properties=None):
13
+ new_edge = self.table_edges().add_edge(source_key, target_key, value, properties)
14
+ self.add_node(source_key) # assuming node_table.allow_duplicate_keys is set to False
15
+ self.add_node(target_key) # make sure there is a node for each part of the edge added
16
+ return new_edge
17
+
18
+
19
+ def add_node(self, key, value=None, properties=None):
20
+ return self.table_nodes().add_node(key, value, properties)
21
+
22
+ def clear(self):
23
+ self.table_edges().clear()
24
+ self.table_nodes().clear()
25
+
26
+ def edges(self):
27
+ return self.table_edges().edges()
28
+
29
+ def nodes(self):
30
+ return self.table_nodes().nodes()
31
+
32
+ def nodes_keys(self):
33
+ return self.table_nodes().keys()
34
+
35
+ @cache_on_self
36
+ def table_edges(self):
37
+ return Sqlite__Table__Edges(database=self).setup()
38
+
39
+ @cache_on_self
40
+ def table_nodes(self):
41
+ return Sqlite__Table__Nodes(database=self).setup()
42
+
43
+ def setup(self):
44
+ #self.table_config() # wire this up when I have a use case for it
45
+ self.table_nodes()
46
+ self.table_edges()
47
+ return self
@@ -0,0 +1,83 @@
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__Create import Sqlite__Table__Create
4
+ from osbot_utils.helpers.sqlite.models.Sqlite__Field__Type import Sqlite__Field__Type
5
+
6
+
7
+ class Sqlite__DB__Json(Kwargs_To_Self):
8
+ database : Sqlite__Database
9
+ table_create : Sqlite__Table__Create
10
+ table_name : str = 'new_db_table'
11
+
12
+ def __init__(self):
13
+ super().__init__()
14
+ self.table_create = Sqlite__Table__Create(self.table_name)
15
+ self.table_create.table.database = self.database
16
+
17
+ def create_fields_from_json_data(self, json_data):
18
+ for key,value in json_data.items():
19
+ self.table_create.add_field_with_type(key, type(value))
20
+
21
+ def create_table_from_schema(self, table_name, schema):
22
+ table_create = Sqlite__Table__Create(table_name)
23
+ table_create.table.database = self.database
24
+ for field_name,field_type in schema.items():
25
+ table_create.add_field_with_type(field_name, field_type)
26
+
27
+ if table_create.create_table():
28
+ return table_create.table
29
+
30
+ def create_table_from_json_data(self, json_data):
31
+ self.create_fields_from_json_data(json_data)
32
+ if self.table_create.create_table():
33
+ self.table_create.table.row_add_record(json_data)
34
+ return self.table_create.table
35
+
36
+ #def add_data_to_data_from_json_data(self, json_data):
37
+
38
+ def get_schema_from_json_data(self, json_data):
39
+ if type(json_data) is dict:
40
+ return self.get_schema_from_dict(json_data)
41
+ if type(json_data) is list:
42
+ return self.get_schema_from_list_of_dict(json_data)
43
+
44
+ def get_schema_from_list_of_dict(self, target):
45
+ if not isinstance(target, list):
46
+ raise ValueError("in get_schema_from_list_of_dict, the provided target is not a list")
47
+
48
+ overall_schema = {}
49
+
50
+ for item in target:
51
+ if not isinstance(item, dict):
52
+ continue # or raise an exception, depending on your needs
53
+
54
+ current_schema = self.get_schema_from_dict(item)
55
+
56
+ for key, current_type in current_schema.items():
57
+ if (key in overall_schema and # Check if key exists in the overall schema
58
+ overall_schema[key] != current_type and # Check if there's a type mismatch for the key
59
+ current_type != Sqlite__Field__Type.UNKNOWN and # Ensure current type is not UNKNOWN
60
+ overall_schema[key] != Sqlite__Field__Type.UNKNOWN ): # Ensure overall schema's type for the key is not UNKNOWN
61
+ message = f"Type conflict for field '{key}': {overall_schema[key]} vs {current_type}"
62
+ raise ValueError(message)
63
+ else:
64
+ overall_schema[key] = current_type # Update or add the key with its type to the overall schema
65
+
66
+
67
+ return overall_schema
68
+
69
+ def get_schema_from_dict(self, target):
70
+ schema = {}
71
+ type_map = Sqlite__Field__Type.type_map()
72
+ for key, value in target.items():
73
+ value_type = type(value)
74
+ field_type = type_map.get(value_type)
75
+ if field_type is None:
76
+ raise ValueError(f"in get_schema_from_dict, the value_type {value_type} from '{key} = {value}' is not supported by Sqlite__Field__Type")
77
+ schema[key] = field_type
78
+ return schema
79
+
80
+
81
+
82
+
83
+
@@ -0,0 +1,20 @@
1
+ from os import environ
2
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database
3
+ from osbot_utils.utils.Files import current_temp_folder, path_combine
4
+ from osbot_utils.utils.Misc import random_text
5
+ from osbot_utils.utils.Str import str_safe
6
+
7
+ ENV_NAME_PATH_LOCAL_DBS = 'PATH_LOCAL_DBS'
8
+
9
+ class Sqlite__DB__Local(Sqlite__Database):
10
+ db_name: str
11
+
12
+ def __init__(self, db_path=None, db_name=None):
13
+ self.db_name = db_name or random_text('db_local') + '.sqlite'
14
+ super().__init__(db_path=db_path or self.path_local_db())
15
+
16
+ def path_db_folder(self):
17
+ return environ.get(ENV_NAME_PATH_LOCAL_DBS) or current_temp_folder()
18
+
19
+ def path_local_db(self):
20
+ return path_combine(self.path_db_folder(), str_safe(self.db_name))
@@ -0,0 +1,39 @@
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.domains.schemas.Schema__Table__Requests import Schema__Table__Requests
4
+ from osbot_utils.utils.Misc import random_text
5
+
6
+ SQLITE_TABLE__REQUESTS = 'requests'
7
+
8
+ class Sqlite__DB__Requests(Sqlite__DB__Local):
9
+ table_name : str
10
+ table_schema: type
11
+
12
+ def __init__(self,db_path=None, db_name=None, table_name=None):
13
+ self.table_name = table_name or SQLITE_TABLE__REQUESTS
14
+ self.table_schema = Schema__Table__Requests
15
+ super().__init__(db_path=db_path, db_name=db_name)
16
+ # if not self.table_name:
17
+ # self.table_name = 'temp_table'
18
+ self.setup()
19
+
20
+ @cache_on_self
21
+ def table_requests(self):
22
+ return self.table(self.table_name)
23
+
24
+ def table_requests__create(self):
25
+ with self.table_requests() as _:
26
+ _.row_schema = self.table_schema # set the table_class
27
+ if _.exists() is False:
28
+ _.create() # create if it doesn't exist
29
+ _.index_create('request_hash') # add index to the request_hash field
30
+ return True
31
+ return False
32
+
33
+ def table_requests__reset(self):
34
+ self.table_requests().delete()
35
+ return self.table_requests__create()
36
+
37
+ def setup(self):
38
+ self.table_requests__create()
39
+ return self
File without changes
@@ -0,0 +1,12 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+
3
+ class Schema__Table__Requests(Kwargs_To_Self):
4
+ request_hash : str
5
+ request_data : str
6
+ response_hash : str
7
+ response_data : str
8
+ response_bytes: bytes
9
+ cache_hits : int # todo: to implement
10
+ timestamp : int
11
+ latest : bool # todo: add native bool support to sqlite
12
+ comments : str
File without changes
@@ -0,0 +1,37 @@
1
+ from decimal import Decimal
2
+ from enum import Enum, auto
3
+ from types import NoneType
4
+
5
+ from osbot_utils.decorators.methods.cache import cache
6
+
7
+
8
+ class Sqlite__Field__Type(Enum):
9
+ BOOLEAN = bool
10
+ DECIMAL = Decimal
11
+ INTEGER = int
12
+ TEXT = str
13
+ BLOB = bytes
14
+ REAL = float
15
+ NUMERIC = 'numeric' # special case to have some support for using NUMERIC in the Create Table
16
+ UNKNOWN = NoneType # special type to handle cases when the type is not known # todo: handle this on the table creation stage
17
+
18
+ def __repr__(self):
19
+ return f'Sqlite__Field__Type.{self.name}'
20
+
21
+ def __str__(self):
22
+ return self.name
23
+
24
+ @classmethod
25
+ @cache
26
+ def type_map(cls):
27
+ type_map = {}
28
+ for member in cls:
29
+ if member.value not in [auto()]:
30
+ type_map[member.value] = member
31
+ return type_map
32
+
33
+ @classmethod
34
+ @cache
35
+ def enum_map(cls):
36
+ return {member.name: member.value for member in cls}
37
+
File without changes
@@ -0,0 +1,116 @@
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__Database import Sqlite__Database
4
+ from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
5
+ from osbot_utils.helpers.sqlite.Sqlite__Table__Create import Sqlite__Table__Create
6
+ from osbot_utils.helpers.sqlite.domains.Sqlite__DB__Json import Sqlite__DB__Json
7
+ from osbot_utils.testing.Duration import duration, Duration
8
+ from osbot_utils.utils.Dev import pprint
9
+ from osbot_utils.utils.Files import current_temp_folder, path_combine, folder_create, file_exists, file_not_exists, \
10
+ file_contents
11
+ from osbot_utils.utils.Http import GET, GET_to_file
12
+ from osbot_utils.utils.Json import json_loads, json_from_file, json_dump, json_file_create, json_file_load
13
+ from osbot_utils.utils.Objects import obj_info
14
+
15
+ URL__CHINOOK_JSON = 'https://github.com/lerocha/chinook-database/releases/download/v1.4.5/ChinookData.json'
16
+ FILE_NAME__CHINOOK_DATA_JSON = 'ChinookData.json'
17
+ FILE_NAME__TABLES_SCHEMAS_FIELDS = 'chinook__tables_schemas_fields.json'
18
+ FOLDER_NAME__CHINOOK_DATA = 'chinook_data'
19
+ FOLDER_NAME__SQLITE_DATA_SETS = '_sqlite_data_sets'
20
+ PATH__DB__TESTS = '/tmp/db-tests'
21
+ PATH__DB__CHINOOK = '/tmp/db-tests/test-chinook.db'
22
+ TABLE_NAME__CHINOOK = 'chinook_data'
23
+
24
+ class Sqlite__Sample_Data__Chinook(Kwargs_To_Self):
25
+ url_chinook_database_json : str = URL__CHINOOK_JSON
26
+ path_local_db : str = PATH__DB__CHINOOK
27
+ table_name : str = TABLE_NAME__CHINOOK
28
+ json_db : Sqlite__DB__Json
29
+
30
+
31
+
32
+ def chinook_data_as_json(self):
33
+ path_chinook_data_as_json = self.path_chinook_data_as_json()
34
+ if file_not_exists(path_chinook_data_as_json):
35
+ GET_to_file(self.url_chinook_database_json, path_chinook_data_as_json)
36
+ return json_from_file(path_chinook_data_as_json)
37
+
38
+ # def create_table_from_data(self):
39
+ # chinook_data = self.chinook_data_as_json()
40
+ # table_creator = Sqlite__Table__Create(table_name=self.table_name)
41
+ # table = table_creator.table
42
+ # table_creator.add_fields__text("name", "value").create_table()
43
+ #
44
+ # cursor = table.cursor()
45
+ # assert len(chinook_data) == 11
46
+ # for key, items in chinook_data.items():
47
+ # name = key
48
+ # value = json_dump(items)
49
+ # table.row_add(dict(name=name, value=value))
50
+ #
51
+ # cursor.commit()
52
+ # return table
53
+
54
+ def create_tables(self):
55
+ self.create_tables_from_schema()
56
+ chinook_data = self.chinook_data_as_json()
57
+ for table_name, rows in chinook_data.items():
58
+ table = self.json_db.database.table(table_name)
59
+ table.rows_add(rows)
60
+
61
+
62
+
63
+ def create_tables_from_schema(self):
64
+ schemas = self.tables_schemas_fields_from_data()
65
+ for table_name, table_schema in schemas.items():
66
+ self.json_db.create_table_from_schema(table_name, table_schema)
67
+ return self
68
+
69
+ def database(self): # todo: need to refactor this code based from the creation of the database to the use of it
70
+ return self.json_db.database
71
+
72
+ @cache_on_self
73
+ def load_db_from_disk(self):
74
+ db_chinook = Sqlite__Database(db_path=PATH__DB__CHINOOK, auto_schema_row=True) # set the auto_schema_row so that we have a row_schema defined for all tables
75
+ return db_chinook
76
+ # db_chinook.connect()
77
+ # return db_chinook.table(self.table_name)
78
+
79
+ def path_chinook_data_as_json(self):
80
+ return path_combine(self.path_chinook_data(), FILE_NAME__CHINOOK_DATA_JSON)
81
+
82
+ def path_chinook_data(self):
83
+ path_chinook_data = path_combine(self.path_sqlite_sample_data_sets(), FOLDER_NAME__CHINOOK_DATA)
84
+ return folder_create(path_chinook_data)
85
+
86
+ def path_sqlite_sample_data_sets(self): # todo: refactor to sqlite_sample_data_sets helper class
87
+ path_data_sets = path_combine(current_temp_folder(), FOLDER_NAME__SQLITE_DATA_SETS)
88
+ return folder_create(path_data_sets)
89
+
90
+ def path_tables_schemas_fields(self):
91
+ return path_combine(self.path_chinook_data(), FILE_NAME__TABLES_SCHEMAS_FIELDS)
92
+
93
+ def table__genre(self):
94
+ return self.load_db_from_disk().table('Genre') # todo: refactor to sqlite_sample_data_sets helper class
95
+
96
+ def table__track(self):
97
+ return self.load_db_from_disk().table('Track') # todo: refactor to sqlite_sample_data_sets helper class
98
+
99
+ # def tables(self):
100
+ # return self.load_db_from_disk().tables()
101
+
102
+ def tables_schemas_fields_from_data(self):
103
+ path_tables_schemas_fields = self.path_tables_schemas_fields()
104
+ if file_not_exists(path_tables_schemas_fields):
105
+ tables_schemas = {}
106
+ for name, data in self.chinook_data_as_json().items():
107
+ table_schema = self.json_db.get_schema_from_json_data(data)
108
+ tables_schemas[name] = table_schema
109
+ json_file_create(tables_schemas, path=path_tables_schemas_fields)
110
+
111
+ return json_file_load(path_tables_schemas_fields)
112
+
113
+ def save(self, path=PATH__DB__CHINOOK):
114
+ database = self.database()
115
+ database.save_to(path)
116
+ return True
File without changes
@@ -0,0 +1,159 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.sqlite.Sqlite__Globals import ROW_BASE_CLASS
3
+ from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table
4
+
5
+
6
+ class SQL_Builder(Kwargs_To_Self):
7
+ table : Sqlite__Table
8
+ limit : int = None # set it to None to make it explict that the limit is not set
9
+
10
+ def validate_query_data(self):
11
+ if self.table.row_schema is None:
12
+ raise ValueError("in SQL_Builder, there was no row_schema defined in the mapped table")
13
+
14
+ def select_for_fields(self, field_names: list = None):
15
+ valid_fields = self.table.fields_names__cached()
16
+ if field_names is None:
17
+ field_names = valid_fields
18
+ elif isinstance(field_names, list) is False:
19
+ raise ValueError(f"in sql_query_for_fields, field_names must be a list, it was :{field_names}")
20
+
21
+ invalid_field_names = [name for name in field_names if name not in valid_fields] # If no valid field names are provided, raise an error or return a default query
22
+ if invalid_field_names: # If there are any invalid field names, raise an exception listing them
23
+ message = f"Invalid field names provided: {', '.join(invalid_field_names)}"
24
+ raise ValueError(message)
25
+
26
+ fields_str = ', '.join(field_names) # Construct the SQL query string
27
+ sql_query = f"SELECT {fields_str} FROM {self.table.table_name}{self.sql_limit()};" # Join the valid field names with commas
28
+ return sql_query
29
+
30
+ def command__delete_table(self):
31
+ return f'DELETE FROM {self.table.table_name}'
32
+
33
+ def command__delete_where(self, query_conditions):
34
+ self.validator().validate_query_fields(self.table, [],query_conditions) # todo: add method to validate_query_fields to handle just the query section (so that we don't need to provide a empty list for the return values)
35
+ target_table = self.table.table_name
36
+ where_fields = list(query_conditions.keys())
37
+ params = list(query_conditions.values())
38
+ where_clause = ' AND '.join([f"{field}=?" for field in where_fields]) # todo: refactor into method that just handle the WHERE statements
39
+ sql_query = f"DELETE FROM {target_table} WHERE {where_clause}" # todo: refactor into a method that creates the final statement from a number of other objects (or strings)
40
+ return sql_query, params
41
+
42
+ def command_for_insert(self, record):
43
+ valid_field_names = self.table.fields_names__cached()
44
+ if type(record) is dict:
45
+ if record:
46
+ field_names = record.keys()
47
+ params = list(record.values())
48
+ for field_name in field_names:
49
+ if field_name not in valid_field_names:
50
+ raise ValueError(f'in sql_command_for_insert, there was a field_name "{field_name}" that did exist in the current table')
51
+
52
+ columns = ', '.join(field_names) # Construct column names and placeholders
53
+ placeholders = ', '.join(['?' for _ in field_names])
54
+ sql_command = f'INSERT INTO {self.table.table_name} ({columns}) VALUES ({placeholders})' # Construct the SQL statement
55
+ return sql_command, params
56
+
57
+ def query_for_fields(self, field_names: list = None):
58
+ return self.select_for_fields(field_names)
59
+
60
+ def query_for_size(self):
61
+ return f'SELECT COUNT(*) as size FROM {self.table.table_name}'
62
+
63
+ def sql_limit(self):
64
+ if self.limit is not None:
65
+ return f" LIMIT {int(self.limit)}"
66
+ return ""
67
+
68
+ def query_select_fields_with_conditions(self, return_fields, query_conditions):
69
+ self.validator().validate_query_fields(self.table , return_fields, query_conditions)
70
+ target_table = self.table.table_name
71
+ if target_table and return_fields and query_conditions:
72
+ where_fields = list(query_conditions.keys())
73
+ params = list(query_conditions.values())
74
+ fields_to_return = ', '.join(return_fields) # Join the select_fields list into a comma-separated string
75
+ where_clause = ' AND '.join([f"{field}=?" for field in where_fields]) # Dynamically construct the WHERE clause based on condition_fields
76
+ sql_query = f"SELECT {fields_to_return} FROM {target_table} WHERE {where_clause}" # Construct the full SQL query
77
+ return sql_query, params
78
+
79
+ def query_for_select_rows_where(self, **kwargs):
80
+ valid_fields = self.table.fields__cached() # Get a list of valid field names from the cached schema
81
+ params = [] # Initialize an empty list to hold query parameters
82
+ where_clauses = [] # Initialize an empty list to hold parts of the WHERE clause
83
+ for field_name, query_value in kwargs.items(): # Iterate over each keyword argument and its value
84
+ if field_name not in valid_fields: # Check if the provided field name is valid
85
+ raise ValueError(f'in select_rows_where, the provided field is not valid: {field_name}')
86
+ params.append(query_value) # Append the query value to the parameters list
87
+ where_clauses.append(f"{field_name} = ?") # Append the corresponding WHERE clause part, using a placeholder for the value
88
+ where_clause = ' AND '.join(where_clauses) # Join the individual parts of the WHERE clause with 'AND'
89
+
90
+ sql_query = f"SELECT * FROM {self.table.table_name} WHERE {where_clause}" # Construct the full SQL query
91
+ return sql_query, params
92
+
93
+ def sql_query_update_with_conditions(self, update_fields, query_conditions):
94
+ update_keys = list(update_fields.keys()) # todo: refactor self.validate_query_fields to use a more generic value for these fields
95
+ condition_keys = list(query_conditions.keys())
96
+ self.validator().validate_query_fields(self.table, update_keys, query_conditions)
97
+ target_table = self.table.table_name
98
+ if target_table and update_fields and query_conditions:
99
+ update_clause = ', '.join([f"{key}=?" for key in update_keys])
100
+ where_clause = ' AND '.join([f"{field}=?" for field in condition_keys])
101
+ sql_query = f"UPDATE {target_table} SET {update_clause} WHERE {where_clause}"
102
+
103
+ # The parameters for the SQL execution must include both the update values and the condition values, in the correct order.
104
+ params = list(update_fields.values()) + list(query_conditions.values())
105
+ return sql_query, params
106
+
107
+ def validate_row_obj(self, row_obj):
108
+ field_types = self.table.fields_types__cached()
109
+ invalid_reason = ""
110
+ if self.table.row_schema:
111
+ if row_obj:
112
+ if issubclass(type(row_obj), ROW_BASE_CLASS):
113
+ for field_name, field_type in row_obj.__annotations__.items():
114
+ if field_name not in field_types:
115
+ invalid_reason = f'provided row_obj has a field that is not part of the current table: {field_name}'
116
+ break
117
+
118
+ if field_type != field_types[field_name]:
119
+ invalid_reason = f'provided row_obj has a field {field_name} that has a field type {field_type} that does not match the current tables type of that field: {field_types[field_name]}'
120
+ break
121
+ if invalid_reason == '':
122
+ for field_name, field_value in row_obj.__locals__().items():
123
+ if field_name not in field_types:
124
+ invalid_reason = f'provided row_obj has a field that is not part of the current table: {field_name}'
125
+ break
126
+ if type(field_value) != field_types.get(field_name):
127
+ invalid_reason = f'provided row_obj has a field {field_name} that has a field value {field_value} value that has a type {type(field_value)} that does not match the current tables type of that field: {field_types.get(field_name)}'
128
+ break
129
+ else:
130
+ invalid_reason = f'provided row_obj ({type(row_obj)}) is not a subclass of {ROW_BASE_CLASS}'
131
+ else:
132
+ invalid_reason = f'provided row_obj was None'
133
+ else:
134
+ invalid_reason = f'there is no row_schema defined for this table {self.table.table_name}'
135
+ return invalid_reason
136
+
137
+ def validator(self):
138
+ return SQL_Query__Validator()
139
+
140
+ class SQL_Query__Validator:
141
+
142
+ # todo: refactor this method to use a more generic value for these return_fields since it is already being used in two use cases: return fields and update fields
143
+ def validate_query_fields(self, table, return_fields, query_conditions):
144
+ target_table = table.table_name
145
+ valid_fields = table.fields_names__cached(include_star_field=True)
146
+ if target_table not in table.database.tables_names(include_sqlite_master=True):
147
+ raise ValueError(f'in validate_query_fields, invalid target_table name: "{target_table}"')
148
+ if type(return_fields) is not list:
149
+ raise ValueError(f'in validate_query_fields, return_fields value must be a list, and it was "{type(return_fields)}"')
150
+ for return_field in return_fields:
151
+ if return_field not in valid_fields:
152
+ raise ValueError(f'in validate_query_fields, invalid, invalid return_field: "{return_field}"')
153
+ if type(query_conditions) is not dict:
154
+ raise ValueError(f'in validate_query_fields, query_conditions value must be a dict, and it was "{type(query_conditions)}"')
155
+ for where_field in query_conditions.keys():
156
+ if where_field not in valid_fields:
157
+ raise ValueError(f'in validate_query_fields, invalid, invalid return_field: "{where_field}"')
158
+
159
+ return self
@@ -0,0 +1,12 @@
1
+ from osbot_utils.helpers.sqlite.sql_builder.SQL_Builder import SQL_Builder
2
+
3
+
4
+ class SQL_Builder__Select(SQL_Builder): # todo: to refactor SELECT methods into this class
5
+ pass
6
+ # def build(self):
7
+ # self.validate_query_data()
8
+ #
9
+ # return f"SELECT * FROM *"
10
+
11
+ # def validate_query_data(self):
12
+ # super().validate_query_data()
File without changes