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,94 @@
1
+ import queue
2
+ from threading import Thread
3
+ from queue import Queue
4
+
5
+ from osbot_utils.helpers.pubsub.Event__Queue import Event__Queue
6
+ from osbot_utils.helpers.pubsub.PubSub__Client import PubSub__Client
7
+ from osbot_utils.helpers.pubsub.PubSub__Room import PubSub__Room
8
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
9
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event__Connect import Schema__Event__Connect
10
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event__Leave_Room import Schema__Event__Leave_Room
11
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event__Disconnect import Schema__Event__Disconnect
12
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event__Join_Room import Schema__Event__Join_Room
13
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event__Message import Schema__Event__Message
14
+ from osbot_utils.testing.Logging import Logging
15
+ from osbot_utils.utils.Dev import pprint
16
+
17
+
18
+ class PubSub__Server(Event__Queue):
19
+ #pubsub_db: PubSub__Sqlite
20
+ clients : dict
21
+ clients_connected: set[PubSub__Client]
22
+ rooms : dict[str, PubSub__Room]
23
+ logging : Logging
24
+
25
+ def __init__ (self):
26
+ super().__init__()
27
+
28
+ # def db_table_clients(self):
29
+ # return self.pubsub_db.table_clients() # todo refactor to class that uses this as a base and uses sqlite to capture connections
30
+
31
+ def add_client(self, client: PubSub__Client):
32
+ client_id = client.client_id
33
+ if client_id:
34
+ self.clients[client_id] = client
35
+ return self
36
+
37
+ def client_connect(self, client):
38
+ self.clients_connected.add(client)
39
+
40
+ def client_disconnect(self, client):
41
+ self.clients_connected.discard(client)
42
+
43
+ def client_join_room(self, client, event):
44
+ room_name = event.room_name
45
+ if room_name:
46
+ self.room(room_name).clients.add(client)
47
+
48
+ def client_message(self, client, event):
49
+ pass
50
+
51
+ def client_leave_room(self, client, event):
52
+ room_name = event.room_name
53
+ if room_name:
54
+ self.room(room_name).clients.discard(client)
55
+
56
+ def get_client(self, client_id):
57
+ return self.clients.get(client_id)
58
+
59
+ def handle_event(self, event: Schema__Event):
60
+ event_type = type(event)
61
+ client = self.clients.get(event.connection_id)
62
+ if client:
63
+ if event_type is Schema__Event__Connect : self.client_connect (client)
64
+ elif event_type is Schema__Event__Disconnect : self.client_disconnect(client)
65
+ elif event_type is Schema__Event__Join_Room : self.client_join_room (client, event)
66
+ elif event_type is Schema__Event__Leave_Room : self.client_leave_room(client, event)
67
+ elif event_type is Schema__Event__Message : self.client_message (client, event)
68
+ else:
69
+ return False
70
+
71
+ if self.log_events:
72
+ self.events.append(event)
73
+ return True
74
+
75
+ def log(self, message):
76
+ self.logging.debug(message)
77
+ return self
78
+
79
+ def new_client(self):
80
+ client = PubSub__Client(event_queue = self)
81
+ self.add_client(client)
82
+ return client
83
+
84
+ def room(self, room_name):
85
+ if room_name not in self.rooms:
86
+ new_room = PubSub__Room(room_name=room_name)
87
+ self.rooms[room_name] = new_room
88
+
89
+ return self.rooms.get(room_name)
90
+
91
+
92
+
93
+
94
+
@@ -0,0 +1,24 @@
1
+ from osbot_utils.decorators.methods.cache_on_self import cache_on_self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__PubSub__Client import Schema__PubSub__Clients
3
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database
4
+
5
+ TABLE_NAME__PUB_SUB__CLIENTS = 'pubsub_clients'
6
+ TABLE_SCHEMA__PUB_SUB__CLIENTS = Schema__PubSub__Clients
7
+
8
+ class PubSub__Sqlite(Sqlite__Database):
9
+
10
+ @cache_on_self
11
+ def table_clients(self):
12
+ return self.table(TABLE_NAME__PUB_SUB__CLIENTS)
13
+
14
+ def table_clients__create(self):
15
+ with self.table_clients() as _:
16
+ _.row_schema = TABLE_SCHEMA__PUB_SUB__CLIENTS
17
+ if _.exists() is False:
18
+ _.create() # create if it doesn't exist
19
+ return True
20
+ return False
21
+
22
+ def setup(self):
23
+ self.table_clients__create()
24
+ return self
File without changes
@@ -0,0 +1,15 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.utils.Misc import random_guid
3
+
4
+
5
+ class Schema__Event(Kwargs_To_Self):
6
+ connection_id: str
7
+ event_id : str
8
+ event_data : dict
9
+ event_message: str
10
+ event_target : str
11
+ event_type : str
12
+ timestamp : int
13
+
14
+ def __repr__(self):
15
+ return f'<{self.__class__.__name__}: {self.event_id}>'
@@ -0,0 +1,7 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
3
+ from osbot_utils.utils.Misc import random_guid
4
+
5
+
6
+ class Schema__Event__Connect(Schema__Event):
7
+ event_type : str = 'connect'
@@ -0,0 +1,7 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
3
+ from osbot_utils.utils.Misc import random_guid
4
+
5
+
6
+ class Schema__Event__Disconnect(Schema__Event):
7
+ event_type : str = 'disconnect'
@@ -0,0 +1,8 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
3
+ from osbot_utils.utils.Misc import random_guid
4
+
5
+
6
+ class Schema__Event__Join_Room(Schema__Event):
7
+ event_type : str = 'join-room'
8
+ room_name : str
@@ -0,0 +1,8 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
3
+ from osbot_utils.utils.Misc import random_guid
4
+
5
+
6
+ class Schema__Event__Leave_Room(Schema__Event):
7
+ event_type : str = 'leave-room'
8
+ room_name : str
@@ -0,0 +1,7 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
3
+ from osbot_utils.utils.Misc import random_guid
4
+
5
+
6
+ class Schema__Event__Message(Schema__Event):
7
+ pass
@@ -0,0 +1,8 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+
3
+
4
+ class Schema__PubSub__Clients(Kwargs_To_Self):
5
+ client_id : str
6
+ status : str
7
+ timestamp_connect : int
8
+ timestamp_disconnect : str
File without changes
@@ -0,0 +1,51 @@
1
+ import sqlite3
2
+ from functools import wraps
3
+ from osbot_utils.utils.Dev import pprint
4
+
5
+ def capture_sqlite_error(func):
6
+ @wraps(func)
7
+ def wrapper(*args, **kwargs):
8
+ return_value = None
9
+ with Capture_Sqlite_Error() as error_capture:
10
+ try:
11
+ return_value = func(*args, **kwargs)
12
+ except Exception as e:
13
+ raise e
14
+ if error_capture.error_details:
15
+ print()
16
+ pprint('****** SQLITE ERROR DETECTED ******')
17
+ pprint(error_capture.error_details)
18
+ return return_value
19
+
20
+ return wrapper
21
+
22
+ class Capture_Sqlite_Error:
23
+ def __init__(self):
24
+ self.error_details = {}
25
+
26
+ def __enter__(self):
27
+ return self
28
+
29
+ def __exit__(self, exc_type, exc_val, exc_tb):
30
+ if exc_val: # Check if an exception occurred
31
+ if isinstance(exc_val, sqlite3.ProgrammingError): # Check for SQLite ProgrammingError
32
+ self.process_programming_error(exc_val)
33
+ return True # Prevent the exception from propagating
34
+ elif isinstance(exc_val, sqlite3.Error): # Handle other generic sqlite3 errors
35
+ self.process_generic_sqlite_error(exc_val)
36
+ return True
37
+ return False # Allow exceptions not handled here to propagate
38
+
39
+ def process_programming_error(self, exc_val):
40
+ error_message = str(exc_val)
41
+ self.error_details = {
42
+ 'error_code': 'ProgrammingError',
43
+ 'error_message': error_message
44
+ }
45
+
46
+ def process_generic_sqlite_error(self, exc_val):
47
+ error_message = str(exc_val)
48
+ self.error_details = {
49
+ 'error_code': type(exc_val).__name__,
50
+ 'error_message': error_message
51
+ }
@@ -0,0 +1,87 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+ from osbot_utils.decorators.methods.cache import cache
3
+ from osbot_utils.decorators.methods.cache_on_self import cache_on_self
4
+ from osbot_utils.helpers.sqlite.Sqlite__Database import Sqlite__Database
5
+ from osbot_utils.utils.Status import status_ok, status_error, status_exception
6
+
7
+
8
+ class Sqlite__Cursor(Kwargs_To_Self):
9
+ database : Sqlite__Database
10
+
11
+ @cache_on_self
12
+ def cursor(self):
13
+ return self.connection().cursor()
14
+
15
+ def commit(self):
16
+ self.connection().commit()
17
+ return self
18
+
19
+ def connection(self):
20
+ return self.database.connection()
21
+
22
+ def execute(self, sql_query, *params):
23
+ try:
24
+ self.cursor().execute(sql_query, *params)
25
+ return status_ok()
26
+ except Exception as error:
27
+ return status_exception(error=f'{error}')
28
+
29
+ def execute_and_commit(self, sql_query, *params): # todo: refactor this with the execute method
30
+ try:
31
+ self.cursor().execute(sql_query, *params)
32
+ self.connection().commit()
33
+ return status_ok()
34
+ except Exception as error:
35
+ return status_exception(error=f'{error}')
36
+
37
+ def execute__fetch_all(self,sql_query, *params):
38
+ self.execute(sql_query,*params)
39
+ return self.cursor().fetchall()
40
+
41
+ def execute__fetch_one(self,sql_query, *params):
42
+ self.execute(sql_query, *params)
43
+ return self.cursor().fetchone()
44
+
45
+ def fetch_all(self):
46
+ return self.cursor().fetchall()
47
+
48
+ def fetch_one(self):
49
+ return self.cursor().fetchone()
50
+
51
+ def table_create(self, table_name, fields):
52
+ if table_name and fields:
53
+ sql_query = f"CREATE TABLE {table_name} ({', '.join(fields)})"
54
+ return self.execute(sql_query=sql_query)
55
+ return status_error(message='table_name, fields cannot be empty')
56
+
57
+ def table_delete(self, table_name):
58
+ sql_query = f"DROP TABLE IF EXISTS {table_name};"
59
+ return self.execute(sql_query=sql_query)
60
+
61
+ def table_exists(self, table_name):
62
+ self.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
63
+ return self.cursor().fetchone() is not None
64
+
65
+ def table_schema(self, table_name):
66
+ sql_query = f"PRAGMA table_info({table_name});"
67
+ self.execute(sql_query)
68
+ columns = self.cursor().fetchall()
69
+ return columns
70
+
71
+ def table__sqlite_master(self): # todo: refactor into separate class
72
+ sql_query = "SELECT * FROM sqlite_master"
73
+ self.execute(sql_query)
74
+ return self.cursor().fetchall()
75
+
76
+ def tables(self):
77
+ sql_query = "SELECT * FROM sqlite_master WHERE type='table';" # Query to select all table names from the sqlite_master table
78
+ self.execute(sql_query)
79
+ return self.cursor().fetchall()
80
+
81
+ def tables_names(self):
82
+ cell_name = 'name'
83
+ sql_query = f"SELECT {cell_name} FROM sqlite_master WHERE type='table';" # Query to select all table names from the sqlite_master table
84
+ self.execute(sql_query)
85
+ all_rows = self.cursor().fetchall()
86
+ all_values = [cell.get(cell_name) for cell in all_rows]
87
+ return all_values
@@ -0,0 +1,137 @@
1
+ import sqlite3
2
+
3
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
4
+ from osbot_utils.decorators.methods.cache import cache
5
+ from osbot_utils.decorators.methods.cache_on_self import cache_on_self
6
+
7
+ from osbot_utils.utils.Files import current_temp_folder, path_combine, folder_create, file_exists, file_delete
8
+ from osbot_utils.utils.Misc import random_filename
9
+
10
+ SQLITE_DATABASE_PATH__IN_MEMORY = ':memory:'
11
+ FOLDER_NAME_TEMP_DATABASES = '_temp_sqlite_databases'
12
+ TEMP_DATABASE__FILE_NAME_PREFIX = 'random_sqlite_db__'
13
+ TEMP_DATABASE__FILE_EXTENSION = '.sqlite'
14
+
15
+ class Sqlite__Database(Kwargs_To_Self):
16
+ db_path : str = None
17
+ closed : bool = False
18
+ connected : bool = False
19
+ deleted : bool = False
20
+ in_memory : bool = True # default to an in-memory database
21
+ auto_schema_row : bool = False # option to map the table's schema_row when creating an table object
22
+
23
+ def __init__(self, **kwargs):
24
+ super().__init__(**kwargs)
25
+ if self.db_path: # if self.db_path is set via the ctor (then it means that this is not in memory)
26
+ self.in_memory = False # todo: see if this is not better done with a direct method for a getter/setter
27
+
28
+ def close(self):
29
+ if self.closed is False:
30
+ self.connection().close()
31
+ self.closed = True
32
+ self.connected = False
33
+ return True
34
+ return False
35
+
36
+ # def config(self, key):
37
+ # return self.table_config().data().get(key)
38
+
39
+ @cache_on_self
40
+ def connect(self):
41
+ connection_string = self.connection_string()
42
+ connection = sqlite3.connect(connection_string)
43
+ connection.row_factory = self.dict_factory # this returns a dict as the row value of every query
44
+ self.connected = True
45
+ return connection
46
+
47
+ def connection(self):
48
+ return self.connect()
49
+
50
+ def connection_string(self):
51
+ if self.in_memory:
52
+ return SQLITE_DATABASE_PATH__IN_MEMORY
53
+ if not self.db_path:
54
+ self.db_path = self.path_temp_database()
55
+ return self.db_path
56
+
57
+ @cache_on_self
58
+ def cursor(self):
59
+ from osbot_utils.helpers.sqlite.Sqlite__Cursor import Sqlite__Cursor
60
+ return Sqlite__Cursor(database=self)
61
+
62
+ def delete(self):
63
+ if self.in_memory: # can't delete an in-memory database
64
+ return False
65
+ if self.deleted:
66
+ return False
67
+ self.close()
68
+ if file_delete(self.db_path):
69
+ self.deleted = True
70
+ return True
71
+ return False
72
+
73
+ def dict_factory(self, cursor, row): # from https://docs.python.org/3/library/sqlite3.html#how-to-create-and-use-row-factories
74
+ fields = [column[0] for column in cursor.description]
75
+ return {key: value for key, value in zip(fields, row)}
76
+
77
+ def exists(self):
78
+ if self.in_memory:
79
+ return True
80
+ return file_exists(self.db_path)
81
+
82
+ def path_temp_database(self, file_name=None):
83
+ if file_name is None:
84
+ file_name = TEMP_DATABASE__FILE_NAME_PREFIX + random_filename(extension=TEMP_DATABASE__FILE_EXTENSION)
85
+ return path_combine(self.path_temp_databases(), file_name)
86
+
87
+ def path_temp_databases(self):
88
+ path_temp_databases = path_combine(current_temp_folder(), FOLDER_NAME_TEMP_DATABASES) # use current temp folder has the parent folder
89
+ folder_create(path_temp_databases) # make sure it exists
90
+ return path_temp_databases
91
+
92
+ def save_to(self, path):
93
+ connection = self.connection()
94
+ file_conn = sqlite3.connect(path)
95
+ connection.backup(file_conn)
96
+ file_conn.close()
97
+ return path
98
+
99
+
100
+ def table(self, table_name):
101
+ from osbot_utils.helpers.sqlite.Sqlite__Table import Sqlite__Table # need to import here due to circular imports
102
+ table = Sqlite__Table(database=self, table_name=table_name)
103
+ if self.auto_schema_row:
104
+ table.row_schema__set_from_field_types() # todo: see if we shouldn't just propagate the auto_schema_row to the Sqlite__Table and do that on the ctor
105
+ return table
106
+
107
+ # def table_config(self):
108
+ # from osbot_utils.helpers.sqlite.tables.Sqlite__Table__Config import Sqlite__Table__Config
109
+ # table_config = Sqlite__Table__Config(database=self)
110
+ # table_config.setup()
111
+ # return table_config
112
+
113
+ def table__sqlite_master(self):
114
+ return self.table('sqlite_master')
115
+
116
+ def tables(self):
117
+ tables = []
118
+ for table_data in self.tables_raw():
119
+ table_name = table_data.get('name')
120
+ table = self.table(table_name)
121
+ tables.append(table)
122
+ return tables
123
+
124
+ def tables_raw(self):
125
+ return self.cursor().tables()
126
+
127
+ def tables_names(self, include_sqlite_master=False):
128
+ table_names = self.table__sqlite_master().select_field_values('name')
129
+ if include_sqlite_master:
130
+ table_names.append('sqlite_master')
131
+ return table_names
132
+
133
+
134
+
135
+
136
+
137
+
@@ -0,0 +1,70 @@
1
+ import inspect
2
+ import typing
3
+ from decimal import Decimal
4
+ from enum import auto, Enum
5
+ from typing import Optional, Union
6
+
7
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
8
+ from osbot_utils.helpers.sqlite.models.Sqlite__Field__Type import Sqlite__Field__Type
9
+
10
+
11
+ class Sqlite__Field(Kwargs_To_Self):
12
+ cid : int
13
+ name : str
14
+ type : Sqlite__Field__Type
15
+ notnull : bool
16
+ dflt_value : Optional[Union[int, str, float, bytes]]
17
+ pk : bool
18
+ autoincrement : bool
19
+ unique : bool
20
+ is_foreign_key : bool # Indicates if the field is a foreign key
21
+ references_table : Optional[str] # The table the foreign key references
22
+ references_column: Optional[str] # The column in the referenced table
23
+ on_delete_action : Optional[str] # Action on delete (e.g., CASCADE, SET NULL)
24
+ precision : Optional[int] # Precision for decimal types
25
+ scale : Optional[int] # Scale for decimal types
26
+ check_constraint : Optional[str] # Check constraint expression
27
+
28
+ def text_for_create_table(self):
29
+ parts = [self.name] # Start with name
30
+
31
+ if self.type == Sqlite__Field__Type.DECIMAL and self.precision is not None and self.scale is not None:
32
+ parts.append(f"DECIMAL({self.precision}, {self.scale})")
33
+ else:
34
+ parts.append(self.type.name)
35
+ if self.pk:
36
+ parts.append("PRIMARY KEY")
37
+ if self.autoincrement:
38
+ parts.append("AUTOINCREMENT")
39
+ if self.unique:
40
+ parts.append("UNIQUE")
41
+ if self.notnull:
42
+ parts.append("NOT NULL")
43
+
44
+
45
+ if self.check_constraint:
46
+ parts.append(f"CHECK ({self.check_constraint})")
47
+
48
+ if self.is_foreign_key and self.references_table and self.references_column:
49
+ fk_constraint = f"FOREIGN KEY ({self.name}) REFERENCES {self.references_table} ({self.references_column})"
50
+ if self.on_delete_action:
51
+ fk_constraint += f" ON DELETE {self.on_delete_action}"
52
+ return fk_constraint
53
+
54
+ return " ".join(parts)
55
+
56
+ @classmethod
57
+ def fix_from_json_data(cls, json_data):
58
+ if type(json_data) is dict:
59
+ type_type = json_data.get('type')
60
+ mapped_type = Sqlite__Field__Type.type_map().get(type_type)
61
+ if mapped_type:
62
+ json_data['type'] = mapped_type
63
+ return mapped_type
64
+
65
+
66
+ @classmethod
67
+ def from_json(cls, json_data):
68
+ cls.fix_from_json_data(json_data)
69
+ return super(Sqlite__Field, cls).from_json(json_data)
70
+
@@ -0,0 +1,5 @@
1
+ from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
2
+
3
+ DEFAULT_FIELD_NAME__ID = 'id'
4
+ ROW_BASE_CLASS = Kwargs_To_Self
5
+ SQL_TABLE__MODULE_NAME__ROW_SCHEMA = 'Dynamic_Class__Sqlite__Table'