osbot-utils 1.7.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- osbot_utils/__init__.py +1 -0
- osbot_utils/base_classes/Cache_Pickle.py +129 -0
- osbot_utils/base_classes/Kwargs_To_Disk.py +27 -0
- osbot_utils/base_classes/Kwargs_To_Self.py +308 -0
- osbot_utils/base_classes/Type_Safe__List.py +14 -0
- osbot_utils/base_classes/__init__.py +0 -0
- osbot_utils/context_managers/__init__.py +0 -0
- osbot_utils/context_managers/capture_duration.py +33 -0
- osbot_utils/decorators/__init__.py +0 -0
- osbot_utils/decorators/classes/__init__.py +0 -0
- osbot_utils/decorators/classes/singleton.py +9 -0
- osbot_utils/decorators/lists/__init__.py +0 -0
- osbot_utils/decorators/lists/filter_list.py +12 -0
- osbot_utils/decorators/lists/group_by.py +21 -0
- osbot_utils/decorators/lists/index_by.py +27 -0
- osbot_utils/decorators/methods/__init__.py +0 -0
- osbot_utils/decorators/methods/cache.py +19 -0
- osbot_utils/decorators/methods/cache_on_function.py +56 -0
- osbot_utils/decorators/methods/cache_on_self.py +78 -0
- osbot_utils/decorators/methods/cache_on_tmp.py +71 -0
- osbot_utils/decorators/methods/capture_exception.py +37 -0
- osbot_utils/decorators/methods/capture_status.py +20 -0
- osbot_utils/decorators/methods/catch.py +13 -0
- osbot_utils/decorators/methods/context.py +11 -0
- osbot_utils/decorators/methods/depreciated.py +79 -0
- osbot_utils/decorators/methods/function_type_check.py +62 -0
- osbot_utils/decorators/methods/obj_as_context.py +6 -0
- osbot_utils/decorators/methods/remove_return_value.py +22 -0
- osbot_utils/decorators/methods/required_fields.py +19 -0
- osbot_utils/fluent/Fluent_Dict.py +19 -0
- osbot_utils/fluent/Fluent_List.py +44 -0
- osbot_utils/fluent/__init__.py +1 -0
- osbot_utils/graphs/__init__.py +0 -0
- osbot_utils/graphs/mermaid/Mermaid.py +75 -0
- osbot_utils/graphs/mermaid/Mermaid__Edge.py +49 -0
- osbot_utils/graphs/mermaid/Mermaid__Graph.py +93 -0
- osbot_utils/graphs/mermaid/Mermaid__Node.py +69 -0
- osbot_utils/graphs/mermaid/Mermaid__Renderer.py +54 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Edge__Config.py +7 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Node__Config.py +9 -0
- osbot_utils/graphs/mermaid/configs/Mermaid__Render__Config.py +7 -0
- osbot_utils/graphs/mermaid/examples/Mermaid_Examples__FlowChart.py +98 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Diagram_Direction.py +9 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Diagram__Type.py +17 -0
- osbot_utils/graphs/mermaid/models/Mermaid__Node__Shape.py +30 -0
- osbot_utils/graphs/mgraph/MGraph.py +53 -0
- osbot_utils/graphs/mgraph/MGraph__Config.py +7 -0
- osbot_utils/graphs/mgraph/MGraph__Data.py +139 -0
- osbot_utils/graphs/mgraph/MGraph__Edge.py +27 -0
- osbot_utils/graphs/mgraph/MGraph__Node.py +33 -0
- osbot_utils/graphs/mgraph/MGraph__Random_Graphs.py +27 -0
- osbot_utils/graphs/mgraph/MGraph__Serializer.py +43 -0
- osbot_utils/graphs/mgraph/MGraphs.py +17 -0
- osbot_utils/graphs/mgraph/__init__.py +0 -0
- osbot_utils/helpers/CPrint.py +98 -0
- osbot_utils/helpers/Dict_To_Attr.py +7 -0
- osbot_utils/helpers/Local_Cache.py +111 -0
- osbot_utils/helpers/Local_Caches.py +54 -0
- osbot_utils/helpers/Print_Table.py +369 -0
- osbot_utils/helpers/Python_Audit.py +45 -0
- osbot_utils/helpers/Random_Seed.py +27 -0
- osbot_utils/helpers/SCP.py +58 -0
- osbot_utils/helpers/SSH.py +151 -0
- osbot_utils/helpers/Type_Registry.py +16 -0
- osbot_utils/helpers/__init__.py +0 -0
- osbot_utils/helpers/ast/Ast.py +35 -0
- osbot_utils/helpers/ast/Ast_Base.py +124 -0
- osbot_utils/helpers/ast/Ast_Data.py +28 -0
- osbot_utils/helpers/ast/Ast_Load.py +62 -0
- osbot_utils/helpers/ast/Ast_Merge.py +26 -0
- osbot_utils/helpers/ast/Ast_Node.py +117 -0
- osbot_utils/helpers/ast/Ast_Visit.py +85 -0
- osbot_utils/helpers/ast/Call_Tree.py +38 -0
- osbot_utils/helpers/ast/__init__.py +145 -0
- osbot_utils/helpers/ast/nodes/Ast_Add.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Alias.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_And.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Argument.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Arguments.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Assert.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Assign.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Attribute.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Aug_Assign.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Bin_Op.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Bool_Op.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Break.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Call.py +17 -0
- osbot_utils/helpers/ast/nodes/Ast_Class_Def.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Compare.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Comprehension.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Constant.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Continue.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Dict.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Eq.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Except_Handler.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Expr.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_For.py +10 -0
- osbot_utils/helpers/ast/nodes/Ast_Function_Def.py +17 -0
- osbot_utils/helpers/ast/nodes/Ast_Generator_Exp.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Gt.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_GtE.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_If.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_If_Exp.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Import.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Import_From.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_In.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Is.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Is_Not.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Keyword.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Lambda.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_List.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_List_Comp.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Load.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Lt.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_LtE.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Mod.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Module.py +20 -0
- osbot_utils/helpers/ast/nodes/Ast_Mult.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Name.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Not.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Not_Eq.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Not_In.py +6 -0
- osbot_utils/helpers/ast/nodes/Ast_Or.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Pass.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Pow.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Raise.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Return.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Set.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Slice.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Starred.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Store.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Sub.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Subscript.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_Try.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Tuple.py +9 -0
- osbot_utils/helpers/ast/nodes/Ast_Unary_Op.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_While.py +8 -0
- osbot_utils/helpers/ast/nodes/Ast_With.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_With_Item.py +7 -0
- osbot_utils/helpers/ast/nodes/Ast_Yield.py +7 -0
- osbot_utils/helpers/ast/nodes/__init__.py +0 -0
- osbot_utils/helpers/html/Dict_To_Css.py +20 -0
- osbot_utils/helpers/html/Dict_To_Html.py +59 -0
- osbot_utils/helpers/html/Dict_To_Tags.py +88 -0
- osbot_utils/helpers/html/Html_To_Dict.py +75 -0
- osbot_utils/helpers/html/Html_To_Tag.py +20 -0
- osbot_utils/helpers/html/Tag__Base.py +91 -0
- osbot_utils/helpers/html/Tag__Body.py +5 -0
- osbot_utils/helpers/html/Tag__Div.py +5 -0
- osbot_utils/helpers/html/Tag__H.py +9 -0
- osbot_utils/helpers/html/Tag__HR.py +5 -0
- osbot_utils/helpers/html/Tag__Head.py +32 -0
- osbot_utils/helpers/html/Tag__Html.py +42 -0
- osbot_utils/helpers/html/Tag__Link.py +17 -0
- osbot_utils/helpers/html/Tag__Style.py +25 -0
- osbot_utils/helpers/html/__init__.py +0 -0
- osbot_utils/helpers/pubsub/Event__Queue.py +95 -0
- osbot_utils/helpers/pubsub/PubSub__Client.py +53 -0
- osbot_utils/helpers/pubsub/PubSub__Room.py +13 -0
- osbot_utils/helpers/pubsub/PubSub__Server.py +94 -0
- osbot_utils/helpers/pubsub/PubSub__Sqlite.py +24 -0
- osbot_utils/helpers/pubsub/__init__.py +0 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event.py +15 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Disconnect.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Join_Room.py +8 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Leave_Room.py +8 -0
- osbot_utils/helpers/pubsub/schemas/Schema__Event__Message.py +7 -0
- osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py +8 -0
- osbot_utils/helpers/pubsub/schemas/__init__.py +0 -0
- osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py +51 -0
- osbot_utils/helpers/sqlite/Sqlite__Cursor.py +87 -0
- osbot_utils/helpers/sqlite/Sqlite__Database.py +137 -0
- osbot_utils/helpers/sqlite/Sqlite__Field.py +70 -0
- osbot_utils/helpers/sqlite/Sqlite__Globals.py +5 -0
- osbot_utils/helpers/sqlite/Sqlite__Table.py +293 -0
- osbot_utils/helpers/sqlite/Sqlite__Table__Create.py +96 -0
- osbot_utils/helpers/sqlite/Temp_Sqlite__Database__Disk.py +17 -0
- osbot_utils/helpers/sqlite/Temp_Sqlite__Table.py +23 -0
- osbot_utils/helpers/sqlite/__init__.py +0 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests.py +214 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests__Patch.py +63 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Files.py +23 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Graph.py +47 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Json.py +83 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +20 -0
- osbot_utils/helpers/sqlite/domains/Sqlite__DB__Requests.py +39 -0
- osbot_utils/helpers/sqlite/domains/__init__.py +0 -0
- osbot_utils/helpers/sqlite/domains/schemas/Schema__Table__Requests.py +12 -0
- osbot_utils/helpers/sqlite/domains/schemas/__init__.py +0 -0
- osbot_utils/helpers/sqlite/models/Sqlite__Field__Type.py +37 -0
- osbot_utils/helpers/sqlite/models/__init__.py +0 -0
- osbot_utils/helpers/sqlite/sample_data/Sqlite__Sample_Data__Chinook.py +116 -0
- osbot_utils/helpers/sqlite/sample_data/__init__.py +0 -0
- osbot_utils/helpers/sqlite/sql_builder/SQL_Builder.py +159 -0
- osbot_utils/helpers/sqlite/sql_builder/SQL_Builder__Select.py +12 -0
- osbot_utils/helpers/sqlite/sql_builder/__init__.py +0 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Config.py +63 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py +46 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py +45 -0
- osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py +52 -0
- osbot_utils/helpers/sqlite/tables/__init__.py +0 -0
- osbot_utils/helpers/trace/Trace_Call.py +120 -0
- osbot_utils/helpers/trace/Trace_Call__Config.py +94 -0
- osbot_utils/helpers/trace/Trace_Call__Graph.py +26 -0
- osbot_utils/helpers/trace/Trace_Call__Handler.py +215 -0
- osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +85 -0
- osbot_utils/helpers/trace/Trace_Call__Print_Traces.py +170 -0
- osbot_utils/helpers/trace/Trace_Call__Stack.py +166 -0
- osbot_utils/helpers/trace/Trace_Call__Stack_Node.py +59 -0
- osbot_utils/helpers/trace/Trace_Call__Stats.py +71 -0
- osbot_utils/helpers/trace/Trace_Call__View_Model.py +75 -0
- osbot_utils/helpers/trace/Trace_Files.py +33 -0
- osbot_utils/helpers/trace/__init__.py +0 -0
- osbot_utils/testing/Catch.py +54 -0
- osbot_utils/testing/Duration.py +69 -0
- osbot_utils/testing/Hook_Method.py +118 -0
- osbot_utils/testing/Log_To_Queue.py +46 -0
- osbot_utils/testing/Log_To_String.py +37 -0
- osbot_utils/testing/Logging.py +81 -0
- osbot_utils/testing/Patch_Print.py +52 -0
- osbot_utils/testing/Profiler.py +89 -0
- osbot_utils/testing/Stderr.py +19 -0
- osbot_utils/testing/Stdout.py +19 -0
- osbot_utils/testing/Temp_File.py +46 -0
- osbot_utils/testing/Temp_Folder.py +114 -0
- osbot_utils/testing/Temp_Sys_Path.py +13 -0
- osbot_utils/testing/Temp_Web_Server.py +83 -0
- osbot_utils/testing/Temp_Zip.py +45 -0
- osbot_utils/testing/Temp_Zip_In_Memory.py +90 -0
- osbot_utils/testing/Unit_Test.py +34 -0
- osbot_utils/testing/Unzip_File.py +30 -0
- osbot_utils/testing/__init__.py +0 -0
- osbot_utils/utils/Assert.py +52 -0
- osbot_utils/utils/Call_Stack.py +187 -0
- osbot_utils/utils/Csv.py +32 -0
- osbot_utils/utils/Dev.py +47 -0
- osbot_utils/utils/Exceptions.py +7 -0
- osbot_utils/utils/Files.py +528 -0
- osbot_utils/utils/Functions.py +113 -0
- osbot_utils/utils/Http.py +136 -0
- osbot_utils/utils/Int.py +6 -0
- osbot_utils/utils/Json.py +171 -0
- osbot_utils/utils/Json_Cache.py +59 -0
- osbot_utils/utils/Lists.py +198 -0
- osbot_utils/utils/Misc.py +496 -0
- osbot_utils/utils/Objects.py +341 -0
- osbot_utils/utils/Png.py +29 -0
- osbot_utils/utils/Process.py +73 -0
- osbot_utils/utils/Python_Logger.py +301 -0
- osbot_utils/utils/Status.py +79 -0
- osbot_utils/utils/Str.py +63 -0
- osbot_utils/utils/Version.py +16 -0
- osbot_utils/utils/Zip.py +97 -0
- osbot_utils/utils/__init__.py +16 -0
- osbot_utils/version +1 -0
- osbot_utils-1.7.7.dist-info/LICENSE +201 -0
- osbot_utils-1.7.7.dist-info/METADATA +46 -0
- osbot_utils-1.7.7.dist-info/RECORD +260 -0
- osbot_utils-1.7.7.dist-info/WHEEL +4 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
2
|
+
|
3
|
+
|
4
|
+
class Dict_To_Css(Kwargs_To_Self):
|
5
|
+
css: dict
|
6
|
+
|
7
|
+
|
8
|
+
def add_css_entry(self, selector, data):
|
9
|
+
self.css[selector] = data
|
10
|
+
return self
|
11
|
+
|
12
|
+
def convert(self, indent=''):
|
13
|
+
css_lines = [] # List to hold each line of CSS
|
14
|
+
for selector, properties in self.css.items():
|
15
|
+
css_line = f"{indent}{selector} {{" # Start the selector line
|
16
|
+
for prop, value in properties.items(): # Add each property and value to the selector's CSS
|
17
|
+
css_line += f"\n{indent} {prop}: {value};"
|
18
|
+
css_line += '\n' + indent + "}" # Close the selector's CSS block
|
19
|
+
css_lines.append(css_line) # Add the completed selector's CSS to the list
|
20
|
+
return "\n".join(css_lines) # Join all selector CSS blocks with a newline and return
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
HTML_SELF_CLOSING_TAGS = {'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'}
|
3
|
+
|
4
|
+
class Dict_To_Html:
|
5
|
+
def __init__(self, root):
|
6
|
+
# Define a list of self-closing tags
|
7
|
+
self.self_closing_tags =HTML_SELF_CLOSING_TAGS # {'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'}
|
8
|
+
self.root = root
|
9
|
+
|
10
|
+
def convert(self):
|
11
|
+
return self.convert_element(self.root, 0) # Start conversion with the root element and initial indentation level 0
|
12
|
+
|
13
|
+
def convert_attrs(self, attrs):
|
14
|
+
attrs_str_parts = [] # List to hold each attribute's string representation
|
15
|
+
for key, value in attrs.items():
|
16
|
+
if '"' in value: # Check if the attribute value contains double quotes
|
17
|
+
escaped_value = """.join(value.split("\"")) # If so, escape double quotes and format the attribute string
|
18
|
+
attr_str = f'{key}="{escaped_value}"'
|
19
|
+
else:
|
20
|
+
attr_str = f'{key}="{value}"' # If not, simply format the attribute string
|
21
|
+
attrs_str_parts.append(attr_str)
|
22
|
+
|
23
|
+
attrs_str = ' '.join(attrs_str_parts) # Join the parts into the final attributes string
|
24
|
+
|
25
|
+
if attrs_str:
|
26
|
+
attrs_str = " " + attrs_str # Prepend a space if there are attributes
|
27
|
+
return attrs_str
|
28
|
+
|
29
|
+
def convert_element(self, element, indent_level):
|
30
|
+
"""Recursively converts a dictionary to an HTML string with indentation."""
|
31
|
+
tag = element.get("tag")
|
32
|
+
attrs = element.get("attrs", {})
|
33
|
+
children = element.get("children", [])
|
34
|
+
data = element.get("data", "")
|
35
|
+
|
36
|
+
attrs_str = self.convert_attrs(attrs) # Convert attributes dictionary to a string
|
37
|
+
indent = " " * indent_level # Indentation for the current level, assuming 4 spaces per indent level
|
38
|
+
|
39
|
+
if tag in self.self_closing_tags: # Check if the tag is self-closing
|
40
|
+
return f"{indent}<{tag}{attrs_str} />\n"
|
41
|
+
|
42
|
+
html = f"{indent}<{tag}{attrs_str}>" # Opening tag with indentation
|
43
|
+
if not data:
|
44
|
+
html += '\n'
|
45
|
+
|
46
|
+
for child in children: # Process children with incremented indent level
|
47
|
+
html += self.convert_element(child, indent_level + 1)
|
48
|
+
|
49
|
+
if data: # Add data if present
|
50
|
+
html += data
|
51
|
+
|
52
|
+
if children: # Closing tag for non-self-closing tags, with indentation
|
53
|
+
html += f"{indent}</{tag}>\n" # Add closing tag on a new line if there are children
|
54
|
+
elif data:
|
55
|
+
html += f"</{tag}>\n"
|
56
|
+
else: # Place closing tag directly after opening tag if there are no children or data
|
57
|
+
html = f"{indent}<{tag}{attrs_str}></{tag}>\n"
|
58
|
+
|
59
|
+
return html
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from osbot_utils.helpers.html.Dict_To_Html import HTML_SELF_CLOSING_TAGS
|
2
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base
|
3
|
+
from osbot_utils.helpers.html.Tag__Body import Tag__Body
|
4
|
+
from osbot_utils.helpers.html.Tag__Head import Tag__Head
|
5
|
+
from osbot_utils.helpers.html.Tag__Html import Tag__Html
|
6
|
+
from osbot_utils.helpers.html.Tag__Link import Tag__Link
|
7
|
+
from osbot_utils.utils.Dev import pprint
|
8
|
+
|
9
|
+
|
10
|
+
class Dict_To_Tags:
|
11
|
+
|
12
|
+
def __init__(self, root):
|
13
|
+
self.root = root
|
14
|
+
|
15
|
+
def convert(self):
|
16
|
+
return self.convert_element(self.root)
|
17
|
+
|
18
|
+
def convert_element(self, element):
|
19
|
+
tag_name = element.get("tag" )
|
20
|
+
attrs = element.get("attrs" , {} )
|
21
|
+
children = element.get("children" , [] )
|
22
|
+
data = element.get("data" , "" )
|
23
|
+
if tag_name == 'html':
|
24
|
+
return self.convert_to__tag__html(element)
|
25
|
+
if tag_name == 'head':
|
26
|
+
return self.convert_to__tag__head(element)
|
27
|
+
if tag_name == 'link':
|
28
|
+
return self.convert_to__tag__link(element)
|
29
|
+
|
30
|
+
def convert_to__tag(self, target_tag, element, indent):
|
31
|
+
tag_name = element.get("tag" )
|
32
|
+
attrs = element.get("attrs" , {} )
|
33
|
+
children = element.get("children" , [] )
|
34
|
+
data = element.get("data" , '' )
|
35
|
+
end_tag = tag_name not in HTML_SELF_CLOSING_TAGS
|
36
|
+
tag_indent = indent + 1
|
37
|
+
tag_kwargs = dict(tag_name = tag_name ,
|
38
|
+
attributes = attrs ,
|
39
|
+
end_tag = end_tag ,
|
40
|
+
indent = tag_indent ,
|
41
|
+
inner_html = data )
|
42
|
+
tag = target_tag(**tag_kwargs)
|
43
|
+
for child in children:
|
44
|
+
child_tag = self.convert_to__tag(Tag__Base, child, tag_indent)
|
45
|
+
tag.elements.append(child_tag)
|
46
|
+
|
47
|
+
return tag
|
48
|
+
|
49
|
+
def convert_to__tag__head(self, element, indent):
|
50
|
+
attrs = element.get("attrs" , {} )
|
51
|
+
children = element.get("children" , [] )
|
52
|
+
print()
|
53
|
+
head_indent = indent+1
|
54
|
+
tag_head = Tag__Head(indent=head_indent, **attrs)
|
55
|
+
for child in children:
|
56
|
+
tag_name = child.get("tag" )
|
57
|
+
data = child.get("data", "")
|
58
|
+
if tag_name == 'title':
|
59
|
+
tag_head.title = data
|
60
|
+
elif tag_name == 'link':
|
61
|
+
tag_head.links.append(self.convert_to__tag__link(child))
|
62
|
+
elif tag_name == 'meta':
|
63
|
+
tag_head.elements.append((self.convert_to__tag(Tag__Base, child, indent=head_indent)))
|
64
|
+
elif tag_name == 'style':
|
65
|
+
tag_head.elements.append((self.convert_to__tag(Tag__Base, child, indent=head_indent))) # todo: add proper roundtrip of css data into Tag__Style (which already exists)
|
66
|
+
else:
|
67
|
+
print(f'[convert_to__tag__head] Unknown tag: {tag_name}')
|
68
|
+
#pprint(tag_head.__locals__())
|
69
|
+
return tag_head
|
70
|
+
|
71
|
+
def convert_to__tag__html(self, element):
|
72
|
+
attrs = element.get("attrs" , {} )
|
73
|
+
children = element.get("children" , [] )
|
74
|
+
tag_html = Tag__Html(**attrs)
|
75
|
+
for child in children:
|
76
|
+
tag_name = child.get("tag" )
|
77
|
+
if tag_name == 'head':
|
78
|
+
tag_html.head = self.convert_to__tag__head(child, tag_html.indent)
|
79
|
+
elif tag_name == 'body':
|
80
|
+
tag_html.body = self.convert_to__tag(Tag__Body, child, tag_html.indent)
|
81
|
+
else:
|
82
|
+
print(f'unknown tag: {tag_name}')
|
83
|
+
return tag_html
|
84
|
+
|
85
|
+
def convert_to__tag__link(self, element):
|
86
|
+
attrs = element.get("attrs", {})
|
87
|
+
tag_link = Tag__Link(**attrs)
|
88
|
+
return tag_link
|
@@ -0,0 +1,75 @@
|
|
1
|
+
from html.parser import HTMLParser
|
2
|
+
|
3
|
+
class Html_To_Dict(HTMLParser):
|
4
|
+
def __init__(self, html):
|
5
|
+
super().__init__()
|
6
|
+
self.root = None # No root initially
|
7
|
+
self.current = None # No current node at the start
|
8
|
+
self.stack = [] # Empty stack for hierarchy management
|
9
|
+
self.html = html or ''
|
10
|
+
|
11
|
+
def convert(self):
|
12
|
+
self.feed(self.html)
|
13
|
+
return self.root
|
14
|
+
|
15
|
+
def handle_starttag(self, tag, attrs):
|
16
|
+
new_tag = {"tag": tag, "attrs": dict(attrs), "children": [], "data": ""}
|
17
|
+
|
18
|
+
if self.current is None:
|
19
|
+
# When the first tag is encountered, it becomes the root
|
20
|
+
self.root = new_tag
|
21
|
+
self.current = new_tag
|
22
|
+
else:
|
23
|
+
# Otherwise, append the new tag as a child of the current tag
|
24
|
+
self.current["children"].append(new_tag)
|
25
|
+
|
26
|
+
# Update the stack and current pointers
|
27
|
+
self.stack.append(new_tag)
|
28
|
+
self.current = new_tag
|
29
|
+
|
30
|
+
def handle_endtag(self, tag):
|
31
|
+
if len(self.stack) > 1:
|
32
|
+
self.stack.pop()
|
33
|
+
self.current = self.stack[-1]
|
34
|
+
|
35
|
+
def handle_data(self, data):
|
36
|
+
if data.strip(): # Ignore whitespace
|
37
|
+
if "data" in self.current:
|
38
|
+
self.current["data"] += data
|
39
|
+
else:
|
40
|
+
self.current["data"] = data
|
41
|
+
|
42
|
+
def print__generate_lines(self, node, indent="", last=True, is_root=True):
|
43
|
+
lines = []
|
44
|
+
|
45
|
+
prefix = "" if is_root else ("└── " if last else "├── ")
|
46
|
+
|
47
|
+
tag = node.get("tag")
|
48
|
+
attrs = node.get("attrs", {})
|
49
|
+
children = node.get("children", [])
|
50
|
+
attrs_str = ' '.join(f'{key}="{value}"' for key, value in attrs.items())
|
51
|
+
attrs_str = f' ({attrs_str})' if attrs_str else ''
|
52
|
+
|
53
|
+
lines.append(f"{indent}{prefix}{tag}{attrs_str}")
|
54
|
+
|
55
|
+
child_indent = indent + (" " if last else "│ ")
|
56
|
+
|
57
|
+
for i, child in enumerate(children):
|
58
|
+
is_last = i == len(children) - 1
|
59
|
+
child_lines = self.print__generate_lines(child, indent=child_indent, last=is_last, is_root=False)
|
60
|
+
lines.extend(child_lines if isinstance(child_lines, list) else [child_lines])
|
61
|
+
|
62
|
+
return lines if is_root else "\n".join(lines)
|
63
|
+
|
64
|
+
def print(self, just_return_lines=False):
|
65
|
+
if self.root:
|
66
|
+
lines = self.print__generate_lines(self.root, is_root=True)
|
67
|
+
if just_return_lines:
|
68
|
+
return lines
|
69
|
+
else:
|
70
|
+
self.print__lines(lines)
|
71
|
+
return self
|
72
|
+
|
73
|
+
def print__lines(self, lines):
|
74
|
+
for line in lines:
|
75
|
+
print(line)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from osbot_utils.helpers.html.Dict_To_Tags import Dict_To_Tags
|
2
|
+
|
3
|
+
from osbot_utils.helpers.html.Html_To_Dict import Html_To_Dict
|
4
|
+
|
5
|
+
|
6
|
+
class Html_To_Tag:
|
7
|
+
|
8
|
+
def __init__(self,html):
|
9
|
+
self.html_to_dict = Html_To_Dict(html)
|
10
|
+
|
11
|
+
def __enter__(self):
|
12
|
+
return self.convert()
|
13
|
+
|
14
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
15
|
+
return
|
16
|
+
|
17
|
+
def convert(self):
|
18
|
+
html_dict = self.html_to_dict.convert()
|
19
|
+
html_tag = Dict_To_Tags(html_dict).convert()
|
20
|
+
return html_tag
|
@@ -0,0 +1,91 @@
|
|
1
|
+
from collections import defaultdict
|
2
|
+
|
3
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
4
|
+
from osbot_utils.utils.Files import file_create
|
5
|
+
|
6
|
+
INDENT_SIZE = 4
|
7
|
+
|
8
|
+
class Tag__Base(Kwargs_To_Self):
|
9
|
+
attributes : dict
|
10
|
+
elements : list
|
11
|
+
end_tag : bool = True
|
12
|
+
indent : int
|
13
|
+
tag_name : str
|
14
|
+
tag_classes : list
|
15
|
+
inner_html : str
|
16
|
+
new_line_before_elements : bool = True
|
17
|
+
|
18
|
+
def __init__(self, **kwargs):
|
19
|
+
super().__init__(**kwargs)
|
20
|
+
#self.locked() # lock the object so that it is not possible to add new attributes via normal assigment
|
21
|
+
|
22
|
+
def append(self, *elements):
|
23
|
+
self.elements.extend(elements)
|
24
|
+
return self
|
25
|
+
|
26
|
+
def attributes_values(self, *attributes_names):
|
27
|
+
attributes = {}
|
28
|
+
for attribute_name in attributes_names:
|
29
|
+
if hasattr(self, attribute_name):
|
30
|
+
attribute_value = getattr(self, attribute_name)
|
31
|
+
if attribute_value:
|
32
|
+
attributes[attribute_name] = attribute_value
|
33
|
+
return attributes
|
34
|
+
|
35
|
+
def elements__by_tag_name(self):
|
36
|
+
result = defaultdict(list)
|
37
|
+
for element in self.elements:
|
38
|
+
result[element.tag_name].append(element)
|
39
|
+
return dict(result)
|
40
|
+
|
41
|
+
def elements__with_tag_name(self, tag_name):
|
42
|
+
return self.elements__by_tag_name().get(tag_name)
|
43
|
+
|
44
|
+
def save(self, file_path):
|
45
|
+
return file_create(file_path, self.render())
|
46
|
+
|
47
|
+
def render_attributes(self):
|
48
|
+
attributes = self.attributes.copy()
|
49
|
+
if self.tag_classes:
|
50
|
+
attributes['class'] = ' '.join(self.tag_classes)
|
51
|
+
|
52
|
+
html_attributes = ' '.join([f'{key}="{value}"' for key, value in attributes.items()])
|
53
|
+
return html_attributes
|
54
|
+
|
55
|
+
def render_element(self):
|
56
|
+
html_attributes = self.render_attributes()
|
57
|
+
html_elements = self.render_elements()
|
58
|
+
element_indent = " " * self.indent * INDENT_SIZE
|
59
|
+
|
60
|
+
html = f"{element_indent}<{self.tag_name}"
|
61
|
+
if html_attributes:
|
62
|
+
html += f" {html_attributes}"
|
63
|
+
if self.end_tag:
|
64
|
+
html += ">"
|
65
|
+
if self.inner_html:
|
66
|
+
html += self.inner_html
|
67
|
+
if html_elements:
|
68
|
+
if self.new_line_before_elements:
|
69
|
+
html += "\n"
|
70
|
+
html += f"{html_elements}"
|
71
|
+
if self.new_line_before_elements:
|
72
|
+
html += "\n"
|
73
|
+
html += element_indent
|
74
|
+
html += f"</{self.tag_name}>"
|
75
|
+
else:
|
76
|
+
html += "/>"
|
77
|
+
|
78
|
+
return html
|
79
|
+
|
80
|
+
def render_elements(self):
|
81
|
+
html_elements = ""
|
82
|
+
for index, element in enumerate(self.elements):
|
83
|
+
if index:
|
84
|
+
html_elements += '\n'
|
85
|
+
element.indent = self.indent + 1 # set the indent of the child element based on the current one
|
86
|
+
html_element = element.render()
|
87
|
+
html_elements += html_element
|
88
|
+
return html_elements
|
89
|
+
|
90
|
+
def render(self):
|
91
|
+
return self.render_element()
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base
|
2
|
+
|
3
|
+
|
4
|
+
class Tag__H(Tag__Base):
|
5
|
+
def __init__(self, size, value):
|
6
|
+
tag_name = f'h{size}'
|
7
|
+
inner_html = value
|
8
|
+
init__kwargs = dict(tag_name=tag_name, inner_html=inner_html)
|
9
|
+
super().__init__(**init__kwargs)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base
|
2
|
+
from osbot_utils.helpers.html.Tag__Link import Tag__Link
|
3
|
+
from osbot_utils.helpers.html.Tag__Style import Tag__Style
|
4
|
+
from osbot_utils.utils.Dev import pprint
|
5
|
+
|
6
|
+
|
7
|
+
class Tag__Head(Tag__Base):
|
8
|
+
title : str
|
9
|
+
links : list[Tag__Link]
|
10
|
+
meta : list[Tag__Base]
|
11
|
+
style : Tag__Style
|
12
|
+
|
13
|
+
def __init__(self, **kwargs):
|
14
|
+
super().__init__(**kwargs)
|
15
|
+
self.tag_name = 'head'
|
16
|
+
|
17
|
+
def add_css_bootstrap(self):
|
18
|
+
link = Tag__Link(href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css", rel="stylesheet")
|
19
|
+
self.links.append(link)
|
20
|
+
return self
|
21
|
+
|
22
|
+
def render(self):
|
23
|
+
if self.title:
|
24
|
+
title_element = Tag__Base(tag_name='title', inner_html=self.title, indent=self.indent + 1)
|
25
|
+
self.elements.append(title_element)
|
26
|
+
for link in self.links:
|
27
|
+
link.indent = self.indent + 1
|
28
|
+
self.elements.append(link)
|
29
|
+
if self.style.css():
|
30
|
+
self.elements.append(self.style)
|
31
|
+
html = self.render_element()
|
32
|
+
return html
|
@@ -0,0 +1,42 @@
|
|
1
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base
|
2
|
+
from osbot_utils.helpers.html.Tag__Body import Tag__Body
|
3
|
+
from osbot_utils.helpers.html.Tag__Head import Tag__Head
|
4
|
+
from osbot_utils.utils.Misc import str_to_bytes
|
5
|
+
|
6
|
+
ATTRIBUTES_NAMES__LINK = ['lang']
|
7
|
+
|
8
|
+
|
9
|
+
class Tag__Html(Tag__Base):
|
10
|
+
doc_type: bool = True
|
11
|
+
body : Tag__Body
|
12
|
+
head : Tag__Head
|
13
|
+
lang : str
|
14
|
+
|
15
|
+
def __init__(self, **kwargs):
|
16
|
+
super().__init__(**kwargs)
|
17
|
+
self.head.indent = self.indent + 1
|
18
|
+
self.body.indent = self.indent + 1
|
19
|
+
self.tag_name = 'html'
|
20
|
+
|
21
|
+
def render(self):
|
22
|
+
self.elements = [self.head, self.body]
|
23
|
+
self.attributes = self.attributes_values(*ATTRIBUTES_NAMES__LINK)
|
24
|
+
if self.doc_type:
|
25
|
+
html = "<!DOCTYPE html>\n"
|
26
|
+
else:
|
27
|
+
html = ""
|
28
|
+
attributes = {}
|
29
|
+
if self.lang:
|
30
|
+
attributes['lang'] = self.lang
|
31
|
+
|
32
|
+
html += self.render_element()
|
33
|
+
return html
|
34
|
+
|
35
|
+
def render_to_bytes(self):
|
36
|
+
return str_to_bytes(self.render())
|
37
|
+
|
38
|
+
def set_inner_html(self, value):
|
39
|
+
self.body.inner_html = value
|
40
|
+
return self
|
41
|
+
|
42
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base
|
2
|
+
|
3
|
+
ATTRIBUTES_NAMES__LINK = ['href', 'rel', 'integrity', 'crossorigin']
|
4
|
+
|
5
|
+
class Tag__Link(Tag__Base):
|
6
|
+
end_tag : bool = False
|
7
|
+
tag_name : str = 'link'
|
8
|
+
crossorigin: str
|
9
|
+
href : str
|
10
|
+
rel : str
|
11
|
+
integrity : str
|
12
|
+
|
13
|
+
|
14
|
+
def render(self):
|
15
|
+
self.attributes = self.attributes_values(*ATTRIBUTES_NAMES__LINK)
|
16
|
+
|
17
|
+
return self.render_element()
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from osbot_utils.helpers.html.Dict_To_Css import Dict_To_Css
|
2
|
+
from osbot_utils.helpers.html.Tag__Base import Tag__Base, INDENT_SIZE
|
3
|
+
|
4
|
+
|
5
|
+
class Tag__Style(Tag__Base):
|
6
|
+
tag_name : str = 'style'
|
7
|
+
dict_to_css : Dict_To_Css
|
8
|
+
|
9
|
+
def add_css_entry(self, selector, data):
|
10
|
+
self.dict_to_css.add_css_entry(selector,data)
|
11
|
+
return self
|
12
|
+
|
13
|
+
def css(self):
|
14
|
+
return self.dict_to_css.css
|
15
|
+
|
16
|
+
def render(self):
|
17
|
+
if self.dict_to_css.css:
|
18
|
+
css_indent = self.indent +1
|
19
|
+
css_indent_text = " " * css_indent * INDENT_SIZE
|
20
|
+
element_indent_text = " " * self.indent * INDENT_SIZE
|
21
|
+
self.inner_html = '\n' + self.dict_to_css.convert(indent=css_indent_text) + '\n' + element_indent_text
|
22
|
+
return super().render()
|
23
|
+
|
24
|
+
def set_css(self, css):
|
25
|
+
self.dict_to_css.css = css
|
File without changes
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import time
|
2
|
+
from enum import Enum
|
3
|
+
from queue import Queue, Empty
|
4
|
+
from threading import Thread
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
|
8
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event__Message import Schema__Event__Message
|
9
|
+
from osbot_utils.utils import Misc
|
10
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
11
|
+
from osbot_utils.utils.Misc import random_text, wait_for, timestamp_utc_now, random_guid
|
12
|
+
|
13
|
+
QUEUE_WAIT_TIMEOUT = 1.0 # todo: see if this value is a good one to use here
|
14
|
+
|
15
|
+
class Event__Queue(Kwargs_To_Self):
|
16
|
+
events : list
|
17
|
+
event_class : type
|
18
|
+
log_events : bool = False
|
19
|
+
queue : Queue
|
20
|
+
queue_name : str = random_text('event_queue')
|
21
|
+
queue_timeout: float = QUEUE_WAIT_TIMEOUT
|
22
|
+
running : bool
|
23
|
+
thread : Thread = None
|
24
|
+
|
25
|
+
|
26
|
+
def __init__(self, **kwargs):
|
27
|
+
self.event_class = Schema__Event
|
28
|
+
super().__init__(**kwargs)
|
29
|
+
|
30
|
+
def __enter__(self):
|
31
|
+
self.start()
|
32
|
+
return self
|
33
|
+
|
34
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
35
|
+
self.stop()
|
36
|
+
return False
|
37
|
+
|
38
|
+
def new_event_obj(self, **kwargs):
|
39
|
+
return self.event_class(**kwargs)
|
40
|
+
|
41
|
+
def handle_event(self, event):
|
42
|
+
if self.log_events:
|
43
|
+
self.events.append(event)
|
44
|
+
return True
|
45
|
+
|
46
|
+
def send_event(self, event: Schema__Event):
|
47
|
+
if isinstance(event, Schema__Event):
|
48
|
+
if not event.timestamp:
|
49
|
+
event.timestamp = timestamp_utc_now()
|
50
|
+
if not event.event_id:
|
51
|
+
event.event_id = random_guid()
|
52
|
+
self.queue.put(event)
|
53
|
+
return True
|
54
|
+
return False
|
55
|
+
|
56
|
+
def send_data(self, event_data, **kwargs):
|
57
|
+
if type(event_data) is not dict:
|
58
|
+
event_data = {'data': event_data}
|
59
|
+
new_event = Schema__Event__Message(event_data=event_data, **kwargs)
|
60
|
+
if self.send_event(new_event):
|
61
|
+
return new_event
|
62
|
+
|
63
|
+
def send_message(self, message, **kwargs):
|
64
|
+
new_event = Schema__Event__Message(event_message=str(message), **kwargs)
|
65
|
+
if self.send_event(new_event):
|
66
|
+
return new_event
|
67
|
+
|
68
|
+
def start(self):
|
69
|
+
self.running = True
|
70
|
+
self.thread = Thread(target=self.run_thread, daemon=True)
|
71
|
+
self.thread.start()
|
72
|
+
return self
|
73
|
+
|
74
|
+
def stop(self):
|
75
|
+
self.running = False
|
76
|
+
return self
|
77
|
+
|
78
|
+
def run_thread(self):
|
79
|
+
while self.running:
|
80
|
+
try:
|
81
|
+
event = self.queue.get(timeout=self.queue_timeout)
|
82
|
+
if isinstance(event, self.event_class):
|
83
|
+
self.handle_event(event)
|
84
|
+
except Empty:
|
85
|
+
continue
|
86
|
+
except Exception as e: # todo: add way to handle this (which are errors in the handle_event), may call an on_event_handler_exceptions method
|
87
|
+
continue
|
88
|
+
|
89
|
+
def wait_micro_seconds(self, value=10):
|
90
|
+
time.sleep(0.000001 * value)
|
91
|
+
|
92
|
+
|
93
|
+
def wait_for_thread_ends(self):
|
94
|
+
self.thread.join()
|
95
|
+
return self
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from queue import Queue
|
2
|
+
|
3
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
4
|
+
from osbot_utils.helpers.pubsub.Event__Queue import Event__Queue
|
5
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event import Schema__Event
|
6
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event__Connect import Schema__Event__Connect
|
7
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event__Disconnect import Schema__Event__Disconnect
|
8
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event__Join_Room import Schema__Event__Join_Room
|
9
|
+
from osbot_utils.helpers.pubsub.schemas.Schema__Event__Leave_Room import Schema__Event__Leave_Room
|
10
|
+
from osbot_utils.utils.Misc import random_guid
|
11
|
+
|
12
|
+
|
13
|
+
class PubSub__Client(Kwargs_To_Self):
|
14
|
+
event_queue : Event__Queue
|
15
|
+
client_id : str
|
16
|
+
received_messages : list[str] # todo: fix this to be Events/Messages received via event_queue
|
17
|
+
|
18
|
+
def __init__(self, **kwargs):
|
19
|
+
self.client_id = kwargs.get('client_id') or random_guid()
|
20
|
+
super().__init__(**kwargs)
|
21
|
+
|
22
|
+
def connect(self):
|
23
|
+
event_connect = Schema__Event__Connect(connection_id=self.client_id)
|
24
|
+
self.send_event(event_connect)
|
25
|
+
return self
|
26
|
+
|
27
|
+
def disconnect(self):
|
28
|
+
event_connect = Schema__Event__Disconnect(connection_id=self.client_id)
|
29
|
+
self.send_event(event_connect)
|
30
|
+
return self
|
31
|
+
|
32
|
+
def join_room(self, room_name):
|
33
|
+
event = Schema__Event__Join_Room(connection_id=self.client_id, room_name=room_name)
|
34
|
+
self.send_event(event)
|
35
|
+
return self
|
36
|
+
|
37
|
+
def leave_room(self, room_name):
|
38
|
+
event = Schema__Event__Leave_Room(connection_id=self.client_id, room_name=room_name)
|
39
|
+
self.send_event(event)
|
40
|
+
return self
|
41
|
+
|
42
|
+
def send_data(self, event_data, **kwargs):
|
43
|
+
return self.event_queue.send_data(event_data, connection_id=self.client_id, **kwargs)
|
44
|
+
|
45
|
+
def send_event(self, event : Schema__Event):
|
46
|
+
event.connection_id = self.client_id
|
47
|
+
return self.event_queue.send_event(event)
|
48
|
+
|
49
|
+
def send_message(self, message, **kwargs):
|
50
|
+
return self.event_queue.send_message(message, connection_id=self.client_id, **kwargs)
|
51
|
+
|
52
|
+
def receive_message(self, message):
|
53
|
+
self.received_messages.append(message) # todo: fix this to be Events/Messages received via event_queue
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from osbot_utils.base_classes.Kwargs_To_Self import Kwargs_To_Self
|
2
|
+
from osbot_utils.helpers.pubsub.Event__Queue import Event__Queue
|
3
|
+
from osbot_utils.helpers.pubsub.PubSub__Client import PubSub__Client
|
4
|
+
|
5
|
+
|
6
|
+
class PubSub__Room(Kwargs_To_Self):
|
7
|
+
event_queue: Event__Queue
|
8
|
+
room_name : str
|
9
|
+
clients : set[PubSub__Client]
|
10
|
+
|
11
|
+
def send_to_clients__message(self, message):
|
12
|
+
for client in self.clients:
|
13
|
+
client.receive_message(message)
|