osbot-utils 1.88.0__tar.gz → 1.90.0__tar.gz
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-1.88.0 → osbot_utils-1.90.0}/PKG-INFO +2 -2
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/README.md +1 -1
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/base_classes/Type_Safe.py +24 -8
- osbot_utils-1.88.0/osbot_utils/base_classes/Type_Safe__List.py → osbot_utils-1.90.0/osbot_utils/base_classes/Type_Safe__Base.py +2 -18
- osbot_utils-1.90.0/osbot_utils/base_classes/Type_Safe__Dict.py +22 -0
- osbot_utils-1.90.0/osbot_utils/base_classes/Type_Safe__List.py +22 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__Attribute.py +7 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__Element.py +15 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__File.py +9 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__File__Load.py +88 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__File__To_Dict.py +41 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/Xml__File__To_Xml.py +72 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Channel.py +17 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Enclosure.py +7 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Feed.py +11 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Feed__Parser.py +93 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Image.py +8 -0
- osbot_utils-1.90.0/osbot_utils/helpers/xml/rss/RSS__Item.py +17 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Objects.py +7 -4
- osbot_utils-1.90.0/osbot_utils/utils/__init__.py +0 -0
- osbot_utils-1.90.0/osbot_utils/version +1 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/pyproject.toml +1 -1
- osbot_utils-1.88.0/osbot_utils/version +0 -1
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/LICENSE +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/base_classes/Cache_Pickle.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/base_classes/Kwargs_To_Disk.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/base_classes/Kwargs_To_Self.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/base_classes/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/context_managers/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/context_managers/async_invoke.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/context_managers/capture_duration.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/context_managers/disable_root_loggers.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/context_managers/print_duration.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/classes/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/classes/singleton.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/lists/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/lists/filter_list.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/lists/group_by.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/lists/index_by.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/cache.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/cache_on_function.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/cache_on_self.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/cache_on_tmp.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/capture_exception.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/capture_status.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/catch.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/context.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/depreciated.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/function_type_check.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/obj_as_context.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/remove_return_value.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/required_fields.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/decorators/methods/type_safe.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/fluent/Fluent_Dict.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/fluent/Fluent_List.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/fluent/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/Mermaid.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/Mermaid__Edge.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/Mermaid__Graph.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/Mermaid__Node.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/Mermaid__Renderer.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/configs/Mermaid__Edge__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/configs/Mermaid__Node__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/configs/Mermaid__Render__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/examples/Mermaid_Examples__FlowChart.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/models/Mermaid__Diagram_Direction.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/models/Mermaid__Diagram__Type.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mermaid/models/Mermaid__Node__Shape.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Data.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Edge.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Node.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Random_Graphs.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraph__Serializer.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/MGraphs.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/graphs/mgraph/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/CFormat.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/CPrint.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Dependency_Manager.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Dict_To_Attr.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Guid.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Hashicorp_Secrets.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Local_Cache.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Local_Caches.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Print_Table.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Python_Audit.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Random_Guid.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Random_Guid_Short.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Random_Seed.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Safe_Id.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Str_ASCII.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Timestamp_Now.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Type_Registry.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Type_Safe_Method.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/Zip_Bytes.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Base.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Data.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Load.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Merge.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Node.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Ast_Visit.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/Call_Tree.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Add.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Alias.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_And.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Argument.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Arguments.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Assert.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Assign.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Attribute.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Aug_Assign.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Bin_Op.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Bool_Op.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Break.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Call.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Class_Def.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Compare.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Comprehension.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Constant.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Continue.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Dict.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Eq.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Except_Handler.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Expr.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_For.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Function_Def.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Generator_Exp.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Gt.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_GtE.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_If.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_If_Exp.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Import.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Import_From.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_In.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Is.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Is_Not.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Keyword.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Lambda.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_List.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_List_Comp.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Load.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Lt.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_LtE.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Mod.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Module.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Mult.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Name.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Not.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Not_Eq.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Not_In.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Or.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Pass.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Pow.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Raise.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Return.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Set.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Slice.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Starred.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Store.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Sub.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Subscript.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Try.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Tuple.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Unary_Op.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_While.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_With.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_With_Item.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/Ast_Yield.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ast/nodes/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Actions.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Data.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Invoke.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Row.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/Cache__Requests__Table.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/cache_requests/flows/flow__Cache__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/Flow.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/Flow__Events.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/Task.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/decorators/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/decorators/flow.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/decorators/task.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/models/Flow_Run__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/models/Flow_Run__Event.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/models/Flow_Run__Event_Data.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/models/Flow_Run__Event_Type.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/flows/models/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/generators/Generator_Context_Manager.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/generators/Generator_Manager.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/generators/Model__Generator_State.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/generators/Model__Generator_Target.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/generators/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Dict_To_Css.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Dict_To_Html.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Dict_To_Tags.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Html_To_Dict.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Html_To_Tag.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Base.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Body.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Div.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__H.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__HR.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Head.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Html.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Link.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/Tag__Style.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/html/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/Event__Queue.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/PubSub__Client.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/PubSub__Room.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/PubSub__Server.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/PubSub__Sqlite.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Disconnect.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Execute_Method.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Join_Room.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Leave_Room.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__Event__Message.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/pubsub/schemas/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Cursor.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Database.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Field.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Globals.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Table.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Sqlite__Table__Create.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Temp_Sqlite__Database__Disk.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/Temp_Sqlite__Table.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Schema__Table__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Patch.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Sqlite.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Table.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/Sqlite__DB__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/TestCase__Sqlite__Cache__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/cache/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/Sqlite__DB.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/Sqlite__DB__Files.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/Sqlite__DB__Graph.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/Sqlite__DB__Json.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/domains/schemas/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/models/Sqlite__Field__Type.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/models/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/sample_data/Sqlite__Sample_Data__Chinook.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/sample_data/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/sql_builder/SQL_Builder.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/sql_builder/SQL_Builder__Select.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/sql_builder/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/tables/Sqlite__Table__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/sqlite/tables/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SCP.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Cache__Requests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Execute.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Health_Check.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Linux.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Linux__Amazon.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/SSH__Python.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/TestCase__SSH.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/ssh/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Config.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Graph.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Handler.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Print_Traces.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Stack.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Stack_Node.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__Stats.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Call__View_Model.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/Trace_Files.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/helpers/trace/__init__.py +0 -0
- {osbot_utils-1.88.0/osbot_utils/testing → osbot_utils-1.90.0/osbot_utils/helpers/xml}/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Catch.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Custom_Handler_For_Http_Tests.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Duration.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Hook_Method.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Log_To_Queue.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Log_To_String.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Logging.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Patch_Print.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Profiler.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Pytest.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Stderr.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Stdout.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Env_Vars.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_File.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Folder.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Sys_Path.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Web_Server.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Zip.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Temp_Zip_In_Memory.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Unit_Test.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/testing/Unzip_File.py +0 -0
- {osbot_utils-1.88.0/osbot_utils/utils → osbot_utils-1.90.0/osbot_utils/testing}/__init__.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Assert.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Call_Stack.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Csv.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Dev.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Env.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Exceptions.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Files.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Functions.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Http.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Int.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Json.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Json_Cache.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Lists.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Misc.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Png.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Process.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Python_Logger.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Regex.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Status.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Str.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Threads.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Toml.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Version.py +0 -0
- {osbot_utils-1.88.0 → osbot_utils-1.90.0}/osbot_utils/utils/Zip.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: osbot_utils
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.90.0
|
4
4
|
Summary: OWASP Security Bot - Utils
|
5
5
|
Home-page: https://github.com/owasp-sbot/OSBot-Utils
|
6
6
|
License: MIT
|
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
|
|
23
23
|
|
24
24
|
Powerful Python util methods and classes that simplify common apis and tasks.
|
25
25
|
|
26
|
-

|
27
27
|
[](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
|
28
28
|
|
29
29
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Powerful Python util methods and classes that simplify common apis and tasks.
|
4
4
|
|
5
|
-

|
6
6
|
[](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
|
7
7
|
|
8
8
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
import sys
|
5
5
|
import types
|
6
|
-
from osbot_utils.utils.Objects
|
6
|
+
from osbot_utils.utils.Objects import default_value # todo: remove test mocking requirement for this to be here (instead of on the respective method)
|
7
7
|
|
8
8
|
# Backport implementations of get_origin and get_args for Python 3.7
|
9
9
|
if sys.version_info < (3, 8): # pragma: no cover
|
@@ -23,7 +23,7 @@ if sys.version_info < (3, 8): # pragma
|
|
23
23
|
else:
|
24
24
|
return ()
|
25
25
|
else:
|
26
|
-
from typing import get_origin, get_args
|
26
|
+
from typing import get_origin, get_args, ForwardRef
|
27
27
|
|
28
28
|
if sys.version_info >= (3, 10):
|
29
29
|
NoneType = types.NoneType
|
@@ -148,6 +148,7 @@ class Type_Safe:
|
|
148
148
|
def __default__value__(cls, var_type):
|
149
149
|
import typing
|
150
150
|
from osbot_utils.base_classes.Type_Safe__List import Type_Safe__List
|
151
|
+
from osbot_utils.base_classes.Type_Safe__Dict import Type_Safe__Dict
|
151
152
|
|
152
153
|
if var_type is typing.Set: # todo: refactor the dict, set and list logic, since they are 90% the same
|
153
154
|
return set()
|
@@ -156,13 +157,28 @@ class Type_Safe:
|
|
156
157
|
|
157
158
|
if var_type is typing.Dict:
|
158
159
|
return {}
|
159
|
-
|
160
|
-
|
160
|
+
|
161
|
+
if get_origin(var_type) is dict: # e.g. Dict[key_type, value_type]
|
162
|
+
key_type, value_type = get_args(var_type)
|
163
|
+
if isinstance(key_type, ForwardRef): # Handle forward references on key_type ---
|
164
|
+
forward_name = key_type.__forward_arg__
|
165
|
+
if forward_name == cls.__name__:
|
166
|
+
key_type = cls
|
167
|
+
if isinstance(value_type, ForwardRef): # Handle forward references on value_type ---
|
168
|
+
forward_name = value_type.__forward_arg__
|
169
|
+
if forward_name == cls.__name__:
|
170
|
+
value_type = cls
|
171
|
+
return Type_Safe__Dict(expected_key_type=key_type, expected_value_type=value_type)
|
161
172
|
|
162
173
|
if var_type is typing.List:
|
163
|
-
return []
|
174
|
+
return [] # handle case when List was used with no type information provided
|
175
|
+
|
164
176
|
if get_origin(var_type) is list: # if we have list defined as list[type]
|
165
177
|
item_type = get_args(var_type)[0] # get the type that was defined
|
178
|
+
if isinstance(item_type, ForwardRef): # handle the case when the type is a forward reference
|
179
|
+
forward_name = item_type.__forward_arg__
|
180
|
+
if forward_name == cls.__name__: # if the forward reference is to the current class (simple name check)
|
181
|
+
item_type = cls # set the item_type to the current class
|
166
182
|
return Type_Safe__List(expected_type=item_type) # and used it as expected_type in Type_Safe__List
|
167
183
|
else:
|
168
184
|
return default_value(var_type) # for all other cases call default_value, which will try to create a default instance
|
@@ -258,16 +274,16 @@ class Type_Safe:
|
|
258
274
|
return self
|
259
275
|
|
260
276
|
def deserialize_dict__using_key_value_annotations(self, key, value):
|
277
|
+
from osbot_utils.base_classes.Type_Safe__Dict import Type_Safe__Dict
|
278
|
+
|
261
279
|
dict_annotations_tuple = get_args(self.__annotations__[key])
|
262
280
|
if not dict_annotations_tuple: # happens when the value is a dict/Dict with no annotations
|
263
281
|
return value
|
264
282
|
if not type(value) is dict:
|
265
283
|
return value
|
266
|
-
#key_class = get_args(self.__annotations__[key])[0]
|
267
|
-
#value_class = get_args(self.__annotations__[key])[1]
|
268
284
|
key_class = dict_annotations_tuple[0]
|
269
285
|
value_class = dict_annotations_tuple[1]
|
270
|
-
new_value =
|
286
|
+
new_value = Type_Safe__Dict(expected_key_type=key_class, expected_value_type=value_class)
|
271
287
|
|
272
288
|
for dict_key, dict_value in value.items():
|
273
289
|
if issubclass(key_class, Type_Safe):
|
@@ -2,23 +2,7 @@ from typing import get_origin, get_args, Union, Optional, Any, ForwardRef
|
|
2
2
|
|
3
3
|
EXACT_TYPE_MATCH = (int, float, str, bytes, bool, complex)
|
4
4
|
|
5
|
-
class
|
6
|
-
|
7
|
-
def __init__(self, expected_type, *args):
|
8
|
-
super().__init__(*args)
|
9
|
-
self.expected_type = expected_type
|
10
|
-
|
11
|
-
def __repr__(self):
|
12
|
-
expected_type_name = type_str(self.expected_type)
|
13
|
-
return f"list[{expected_type_name}] with {len(self)} elements"
|
14
|
-
|
15
|
-
def append(self, item):
|
16
|
-
try:
|
17
|
-
self.is_instance_of_type(item, self.expected_type)
|
18
|
-
except TypeError as e:
|
19
|
-
raise TypeError(f"In Type_Safe__List: Invalid type for item: {e}")
|
20
|
-
super().append(item)
|
21
|
-
|
5
|
+
class Type_Safe__Base:
|
22
6
|
def is_instance_of_type(self, item, expected_type):
|
23
7
|
if expected_type is Any:
|
24
8
|
return True
|
@@ -130,4 +114,4 @@ def get_object_type_str(obj):
|
|
130
114
|
elem_type_str = ', '.join(sorted(elem_types))
|
131
115
|
return f"List[{elem_type_str}]"
|
132
116
|
else:
|
133
|
-
return type(obj).__name__
|
117
|
+
return type(obj).__name__
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from osbot_utils.base_classes.Type_Safe__Base import type_str, Type_Safe__Base
|
2
|
+
|
3
|
+
class Type_Safe__Dict(Type_Safe__Base, dict):
|
4
|
+
def __init__(self, expected_key_type, expected_value_type, *args, **kwargs):
|
5
|
+
super().__init__(*args, **kwargs)
|
6
|
+
|
7
|
+
self.expected_key_type = expected_key_type
|
8
|
+
self.expected_value_type = expected_value_type
|
9
|
+
|
10
|
+
for k, v in self.items(): # check type-safety of ctor arguments
|
11
|
+
self.is_instance_of_type(k, self.expected_key_type )
|
12
|
+
self.is_instance_of_type(v, self.expected_value_type)
|
13
|
+
|
14
|
+
def __setitem__(self, key, value): # Check type-safety before allowing assignment.
|
15
|
+
self.is_instance_of_type(key, self.expected_key_type)
|
16
|
+
self.is_instance_of_type(value, self.expected_value_type)
|
17
|
+
super().__setitem__(key, value)
|
18
|
+
|
19
|
+
def __repr__(self):
|
20
|
+
key_type_name = type_str(self.expected_key_type)
|
21
|
+
value_type_name = type_str(self.expected_value_type)
|
22
|
+
return f"dict[{key_type_name}, {value_type_name}] with {len(self)} entries"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from osbot_utils.base_classes.Type_Safe__Base import Type_Safe__Base, type_str
|
2
|
+
|
3
|
+
|
4
|
+
class Type_Safe__List(Type_Safe__Base, list):
|
5
|
+
|
6
|
+
def __init__(self, expected_type, *args):
|
7
|
+
super().__init__(*args)
|
8
|
+
self.expected_type = expected_type
|
9
|
+
|
10
|
+
def __repr__(self):
|
11
|
+
expected_type_name = type_str(self.expected_type)
|
12
|
+
return f"list[{expected_type_name}] with {len(self)} elements"
|
13
|
+
|
14
|
+
def append(self, item):
|
15
|
+
try:
|
16
|
+
self.is_instance_of_type(item, self.expected_type)
|
17
|
+
except TypeError as e:
|
18
|
+
raise TypeError(f"In Type_Safe__List: Invalid type for item: {e}")
|
19
|
+
super().append(item)
|
20
|
+
|
21
|
+
|
22
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
from typing import Dict, List, Union
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.xml.Xml__Attribute import Xml__Attribute
|
4
|
+
|
5
|
+
class XML__Element(Type_Safe):
|
6
|
+
tag : str # Element's local name
|
7
|
+
namespace : str # Element's namespace URI
|
8
|
+
namespace_prefix: str # Element's namespace prefix
|
9
|
+
attributes : Dict[str, Xml__Attribute] # Element attributes
|
10
|
+
children : List[Union[str, 'XML__Element']] # Child elements/text
|
11
|
+
|
12
|
+
# def qualified_name(self) -> str: # Get fully qualified name with prefix
|
13
|
+
# if self.namespace_prefix:
|
14
|
+
# return f"{self.namespace_prefix}:{self.tag}"
|
15
|
+
# return self.tag
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from typing import Dict
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.xml.Xml__Element import XML__Element
|
4
|
+
|
5
|
+
class Xml__File(Type_Safe):
|
6
|
+
xml_data : str # Raw XML content
|
7
|
+
root_element: XML__Element # Parsed root element
|
8
|
+
namespaces : Dict[str, str] # XML namespace mappings
|
9
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from io import StringIO
|
2
|
+
from typing import List, Union, Dict
|
3
|
+
from xml.etree.ElementTree import iterparse, Element, fromstring, ParseError
|
4
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
5
|
+
from osbot_utils.helpers.xml.Xml__Attribute import Xml__Attribute
|
6
|
+
from osbot_utils.helpers.xml.Xml__Element import XML__Element
|
7
|
+
from osbot_utils.helpers.xml.Xml__File import Xml__File
|
8
|
+
|
9
|
+
|
10
|
+
class Xml__File__Load(Type_Safe):
|
11
|
+
|
12
|
+
def load_from_string(self, xml_data: str) -> Xml__File: # Create Xml__File from string
|
13
|
+
xml_file = Xml__File(xml_data=xml_data)
|
14
|
+
self.load_namespaces(xml_file)
|
15
|
+
self.parse_xml (xml_file)
|
16
|
+
return xml_file
|
17
|
+
|
18
|
+
def load_namespaces(self, xml_file: Xml__File): # Extract namespaces from XML
|
19
|
+
if not xml_file.xml_data:
|
20
|
+
raise ValueError("XML data cannot be empty")
|
21
|
+
|
22
|
+
for event, elem in iterparse(StringIO(xml_file.xml_data), events=("start-ns",)):
|
23
|
+
prefix, uri = elem
|
24
|
+
xml_file.namespaces[prefix] = uri
|
25
|
+
|
26
|
+
def parse_xml(self, xml_file: Xml__File): # Parse XML into type-safe structure
|
27
|
+
if not xml_file.xml_data:
|
28
|
+
raise ValueError("XML data cannot be empty")
|
29
|
+
|
30
|
+
try:
|
31
|
+
root = fromstring(xml_file.xml_data)
|
32
|
+
namespaces = xml_file.namespaces
|
33
|
+
xml_file.root_element = self.convert_element(namespaces,root)
|
34
|
+
except ParseError as error:
|
35
|
+
raise ValueError(f"Invalid XML: {str(error)}")
|
36
|
+
|
37
|
+
def convert_element(self, namespaces: Dict[str,str], element: Element) -> XML__Element:
|
38
|
+
attributes = self.convert_attributes(element)
|
39
|
+
children: List[Union[str, XML__Element]] = []
|
40
|
+
|
41
|
+
tag = element.tag
|
42
|
+
namespace = ''
|
43
|
+
namespace_prefix = ''
|
44
|
+
|
45
|
+
if '}' in tag:
|
46
|
+
namespace, tag = tag.split('}', 1) # Split namespace and tag
|
47
|
+
namespace = namespace[1:] # Remove the '{' prefix
|
48
|
+
|
49
|
+
for prefix, uri in namespaces.items(): # Find prefix for this namespace
|
50
|
+
if uri == namespace:
|
51
|
+
namespace_prefix = prefix
|
52
|
+
break
|
53
|
+
|
54
|
+
# Handle text content
|
55
|
+
if element.text and element.text.strip():
|
56
|
+
children.append(element.text.strip())
|
57
|
+
|
58
|
+
# Process child elements
|
59
|
+
for child in element:
|
60
|
+
child_element = self.convert_element(namespaces, child)
|
61
|
+
children.append(child_element)
|
62
|
+
|
63
|
+
if child.tail and child.tail.strip():
|
64
|
+
children.append(child.tail.strip())
|
65
|
+
|
66
|
+
return XML__Element(tag=tag,
|
67
|
+
namespace=namespace,
|
68
|
+
namespace_prefix=namespace_prefix,
|
69
|
+
attributes=attributes,
|
70
|
+
children=children)
|
71
|
+
|
72
|
+
def convert_attributes(self, element: Element) -> Dict[str, Xml__Attribute]: # Convert element attributes
|
73
|
+
attributes = {}
|
74
|
+
for key, value in element.attrib.items():
|
75
|
+
if '}' in key: # Handle namespaced attributes
|
76
|
+
namespace, name = key.split('}', 1)
|
77
|
+
namespace = namespace[1:] # Remove the '{' prefix
|
78
|
+
else:
|
79
|
+
namespace = ''
|
80
|
+
name = key
|
81
|
+
|
82
|
+
attribute = Xml__Attribute(
|
83
|
+
name=name,
|
84
|
+
value=value,
|
85
|
+
namespace=namespace
|
86
|
+
)
|
87
|
+
attributes[key] = attribute
|
88
|
+
return attributes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from typing import Dict, Any
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.xml.Xml__Element import XML__Element
|
4
|
+
from osbot_utils.helpers.xml.Xml__File import Xml__File
|
5
|
+
|
6
|
+
|
7
|
+
class Xml__File__To_Dict(Type_Safe):
|
8
|
+
def to_dict(self, xml_file: Xml__File) -> Dict[str, Any]: # Convert Xml__File to dictionary
|
9
|
+
if not xml_file.root_element:
|
10
|
+
return {}
|
11
|
+
return self.element_to_dict(xml_file.root_element)
|
12
|
+
|
13
|
+
def element_to_dict(self, element: XML__Element) -> Dict[str, Any]: # Convert XML__Element to dictionary
|
14
|
+
result = {}
|
15
|
+
|
16
|
+
for key, attr in element.attributes.items(): # Convert attributes first
|
17
|
+
result[key] = attr.value
|
18
|
+
|
19
|
+
|
20
|
+
child_nodes: Dict[str, Any] = {} # Process children and collect text content
|
21
|
+
text_content = []
|
22
|
+
for child in element.children:
|
23
|
+
if isinstance(child, str):
|
24
|
+
text_content.append(child)
|
25
|
+
else:
|
26
|
+
if child.tag in child_nodes: # Handle child elements
|
27
|
+
if not isinstance(child_nodes[child.tag], list):
|
28
|
+
child_nodes[child.tag] = [child_nodes[child.tag]]
|
29
|
+
child_nodes[child.tag].append(self.element_to_dict(child))
|
30
|
+
else:
|
31
|
+
child_nodes[child.tag] = self.element_to_dict(child)
|
32
|
+
|
33
|
+
if text_content: # Handle text content
|
34
|
+
text_value = ' '.join(text_content)
|
35
|
+
if child_nodes or result: # If we have attributes or child nodes
|
36
|
+
result['#text'] = text_value # Add text as a special key
|
37
|
+
else:
|
38
|
+
return text_value # Return just the text if no attributes/children
|
39
|
+
|
40
|
+
result.update(child_nodes) # Merge child nodes into result
|
41
|
+
return result
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from xml.etree.ElementTree import Element, SubElement, tostring
|
3
|
+
from xml.dom import minidom
|
4
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
5
|
+
from osbot_utils.helpers.xml.Xml__Element import XML__Element
|
6
|
+
from osbot_utils.helpers.xml.Xml__File import Xml__File
|
7
|
+
|
8
|
+
class Xml__File__To_Xml(Type_Safe):
|
9
|
+
|
10
|
+
def convert_to_xml(self, xml_file: Xml__File, pretty_print: bool = True) -> str:
|
11
|
+
if not xml_file.root_element:
|
12
|
+
raise ValueError("XML file must have a root element")
|
13
|
+
|
14
|
+
# Create XML element tree
|
15
|
+
root = self.create_element(xml_file.root_element, xml_file.namespaces)
|
16
|
+
|
17
|
+
# Add all namespace declarations to root element
|
18
|
+
for prefix, uri in xml_file.namespaces.items():
|
19
|
+
if prefix == '':
|
20
|
+
root.set('xmlns', uri)
|
21
|
+
else:
|
22
|
+
root.set(f'xmlns:{prefix}', uri)
|
23
|
+
|
24
|
+
# Convert to string
|
25
|
+
xml_string = tostring(root, encoding='unicode', method='xml')
|
26
|
+
|
27
|
+
# Pretty print if requested
|
28
|
+
if pretty_print:
|
29
|
+
return self.pretty_print(xml_string)
|
30
|
+
return xml_string
|
31
|
+
|
32
|
+
def create_element(self, xml_element: XML__Element, namespaces: Optional[dict] = None, parent: Optional[Element] = None) -> Element:
|
33
|
+
# Create tag with namespace if applicable
|
34
|
+
tag = xml_element.tag
|
35
|
+
if xml_element.namespace_prefix:
|
36
|
+
tag = f"{xml_element.namespace_prefix}:{tag}"
|
37
|
+
# Don't add namespace URI for default namespace - let it be inherited
|
38
|
+
|
39
|
+
# Create new element or sub-element
|
40
|
+
if parent is not None:
|
41
|
+
element = SubElement(parent, tag)
|
42
|
+
else:
|
43
|
+
element = Element(tag)
|
44
|
+
|
45
|
+
# Add attributes including namespace declarations
|
46
|
+
for attr_key, attr in xml_element.attributes.items():
|
47
|
+
if attr.namespace:
|
48
|
+
attr_name = f"{{{attr.namespace}}}{attr.name}"
|
49
|
+
else:
|
50
|
+
attr_name = attr.name
|
51
|
+
element.set(attr_name, attr.value)
|
52
|
+
|
53
|
+
# Process children
|
54
|
+
text_parts = []
|
55
|
+
for child in xml_element.children:
|
56
|
+
if isinstance(child, str):
|
57
|
+
text_parts.append(child)
|
58
|
+
elif isinstance(child, XML__Element):
|
59
|
+
self.create_element(child, namespaces, element)
|
60
|
+
|
61
|
+
# Set text content if any
|
62
|
+
if text_parts:
|
63
|
+
element.text = ''.join(text_parts)
|
64
|
+
|
65
|
+
return element
|
66
|
+
|
67
|
+
def pretty_print(self, xml_string: str) -> str:
|
68
|
+
"""Format XML string with proper indentation."""
|
69
|
+
parsed = minidom.parseString(xml_string)
|
70
|
+
pretty_xml = parsed.toprettyxml(indent=' ').rstrip() + '\n'
|
71
|
+
# Remove empty lines (common issue with toprettyxml)
|
72
|
+
return '\n'.join(line for line in pretty_xml.split('\n') if line.strip())
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from typing import Any, Dict, List
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.xml.rss.RSS__Image import RSS__Image
|
4
|
+
from osbot_utils.helpers.xml.rss.RSS__Item import RSS__Item
|
5
|
+
|
6
|
+
|
7
|
+
class RSS__Channel(Type_Safe):
|
8
|
+
description : str
|
9
|
+
extensions : Dict[str, Any]
|
10
|
+
image : RSS__Image = None
|
11
|
+
items : List[RSS__Item]
|
12
|
+
language : str
|
13
|
+
last_build_date : str
|
14
|
+
link : str
|
15
|
+
title : str
|
16
|
+
update_frequency: str
|
17
|
+
update_period : str
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from typing import Dict, Any
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.xml.rss.RSS__Channel import RSS__Channel
|
4
|
+
|
5
|
+
DEFAULT__RSS_FEED__VERSION = "2.0"
|
6
|
+
|
7
|
+
class RSS__Feed(Type_Safe):
|
8
|
+
version : str = DEFAULT__RSS_FEED__VERSION
|
9
|
+
channel : RSS__Channel = None
|
10
|
+
namespaces : Dict[str, str]
|
11
|
+
extensions : Dict[str, Any]
|
@@ -0,0 +1,93 @@
|
|
1
|
+
from typing import Dict, Any
|
2
|
+
from osbot_utils.helpers.Guid import Guid
|
3
|
+
from osbot_utils.helpers.xml.rss.RSS__Channel import RSS__Channel
|
4
|
+
from osbot_utils.helpers.xml.rss.RSS__Feed import RSS__Feed
|
5
|
+
from osbot_utils.helpers.xml.rss.RSS__Image import RSS__Image
|
6
|
+
from osbot_utils.helpers.xml.rss.RSS__Item import RSS__Item
|
7
|
+
|
8
|
+
|
9
|
+
class RSS__Feed__Parser:
|
10
|
+
|
11
|
+
def from_dict(self, data: Dict[str, Any]) -> RSS__Feed: # Convert a dictionary (from XML) into an RSS__Feed object
|
12
|
+
if 'channel' not in data:
|
13
|
+
raise ValueError("Invalid RSS feed: no channel element found")
|
14
|
+
|
15
|
+
channel_data = data['channel']
|
16
|
+
rss_items = []
|
17
|
+
items = channel_data.get('item', []) # get raw items data
|
18
|
+
if type(items) is not list: # handle case when only one item is present
|
19
|
+
items = [items] # by converting it to a list
|
20
|
+
for item_data in items: # Process items
|
21
|
+
|
22
|
+
title = self.element_text(item_data.get('title' ))
|
23
|
+
link = self.element_text(item_data.get('link' ))
|
24
|
+
description = self.element_text(item_data.get('description'))
|
25
|
+
guid = self.extract_guid(item_data.get('guid' ))
|
26
|
+
pubDate = self.element_text(item_data.get('pubDate' ))
|
27
|
+
creator = self.element_text(item_data.get('creator' ))
|
28
|
+
rss_item = RSS__Item(title = title ,
|
29
|
+
link = link ,
|
30
|
+
description = description ,
|
31
|
+
guid = guid ,
|
32
|
+
pubDate = pubDate ,
|
33
|
+
creator = creator ,
|
34
|
+
categories = item_data.get('category' , []),
|
35
|
+
content = item_data.get('content' , {}),
|
36
|
+
thumbnail = item_data.get('thumbnail' , {}))
|
37
|
+
|
38
|
+
|
39
|
+
known_fields = {'title', 'link', 'description', 'guid', 'pubDate', # Move non-standard elements to extensions
|
40
|
+
'creator', 'category', 'content', 'thumbnail'}
|
41
|
+
rss_item.extensions = {k: v for k, v in item_data.items()
|
42
|
+
if k not in known_fields}
|
43
|
+
rss_items.append(rss_item)
|
44
|
+
|
45
|
+
# Create channel
|
46
|
+
link = self.element_text(channel_data.get('link'))
|
47
|
+
channel = RSS__Channel( title = channel_data.get('title' , ''),
|
48
|
+
link = link ,
|
49
|
+
description = channel_data.get('description' , ''),
|
50
|
+
language = channel_data.get('language' , ''),
|
51
|
+
last_build_date = channel_data.get('lastBuildDate' ),
|
52
|
+
items = rss_items ,
|
53
|
+
update_frequency = channel_data.get('updateFrequency', ''),
|
54
|
+
update_period = channel_data.get('updatePeriod' , ''))
|
55
|
+
|
56
|
+
|
57
|
+
# Process channel image if present
|
58
|
+
if 'image' in channel_data:
|
59
|
+
img_data = channel_data['image']
|
60
|
+
channel.image = RSS__Image( url = img_data.get('url' , '' ),
|
61
|
+
title = img_data.get('title' , '' ),
|
62
|
+
link = img_data.get('link' , '' ),
|
63
|
+
width = int(img_data.get('width' , 0 )),
|
64
|
+
height = int(img_data.get('height', 0 )))
|
65
|
+
|
66
|
+
known_channel_fields = {'title', 'link', 'description', 'language', # Move non-standard channel elements to extensions
|
67
|
+
'lastBuildDate', 'image', 'item', 'updateFrequency', 'updatePeriod'}
|
68
|
+
channel.extensions = {k: v for k, v in channel_data.items()
|
69
|
+
if k not in known_channel_fields}
|
70
|
+
|
71
|
+
rss_feed = RSS__Feed(channel = channel)
|
72
|
+
return rss_feed
|
73
|
+
|
74
|
+
def extract_guid(self, target):
|
75
|
+
return Guid(self.extract_text(target))
|
76
|
+
|
77
|
+
def element_text(self, target):
|
78
|
+
if isinstance(target, list):
|
79
|
+
for item in target:
|
80
|
+
value = self.extract_text(item)
|
81
|
+
if value:
|
82
|
+
return value
|
83
|
+
value = self.extract_text(target)
|
84
|
+
return value or f'{target}'
|
85
|
+
|
86
|
+
def extract_text(self, target):
|
87
|
+
if not target:
|
88
|
+
return ''
|
89
|
+
if isinstance(target, str):
|
90
|
+
return target
|
91
|
+
if isinstance(target, dict):
|
92
|
+
return target.get('#text', '')
|
93
|
+
return ''
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from typing import Dict, List, Any
|
2
|
+
from osbot_utils.base_classes.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.helpers.Guid import Guid
|
4
|
+
from osbot_utils.helpers.xml.rss.RSS__Enclosure import RSS__Enclosure
|
5
|
+
|
6
|
+
class RSS__Item(Type_Safe):
|
7
|
+
title : str
|
8
|
+
link : str
|
9
|
+
description : str
|
10
|
+
guid : Guid
|
11
|
+
pubDate : str
|
12
|
+
creator : str
|
13
|
+
categories : List[str]
|
14
|
+
enclosure : RSS__Enclosure = None
|
15
|
+
content : Dict[str, Any]
|
16
|
+
thumbnail : Dict[str, Any]
|
17
|
+
extensions : Dict[str, Any]
|
@@ -30,14 +30,17 @@ def are_types_compatible_for_assigment(source_type, target_type):
|
|
30
30
|
import types
|
31
31
|
import typing
|
32
32
|
|
33
|
+
if isinstance(target_type, str): # If the "target_type" is a forward reference (string), handle it here.
|
34
|
+
if target_type == source_type.__name__: # Simple check: does the string match the actual class name
|
35
|
+
return True
|
33
36
|
if source_type is target_type:
|
34
37
|
return True
|
35
38
|
if source_type is int and target_type is float:
|
36
39
|
return True
|
37
|
-
if target_type in source_type.__mro__:
|
40
|
+
if target_type in source_type.__mro__: # this means that the source_type has the target_type has of its base types
|
38
41
|
return True
|
39
|
-
if target_type is callable:
|
40
|
-
if source_type is types.MethodType:
|
42
|
+
if target_type is callable: # handle case where callable was used as the target type
|
43
|
+
if source_type is types.MethodType: # and a method or function was used as the source type
|
41
44
|
return True
|
42
45
|
if source_type is types.FunctionType:
|
43
46
|
return True
|
@@ -413,7 +416,7 @@ def value_type_matches_obj_annotation_for_attr(target, attr_name, value):
|
|
413
416
|
origin_attr_type = get_origin(attr_type) # to handle when type definion contains an generic
|
414
417
|
if origin_attr_type is typing.Union:
|
415
418
|
args = get_args(attr_type)
|
416
|
-
if len(args)==2 and args[1] is type(None): # todo: find a better way to do this, since this is handling an edge case when origin_attr_type is Optional (
|
419
|
+
if len(args)==2 and args[1] is type(None): # todo: find a better way to do this, since this is handling an edge case when origin_attr_type is Optional (which is an shorthand for Union[X, None] )
|
417
420
|
attr_type = args[0]
|
418
421
|
origin_attr_type = get_origin(attr_type)
|
419
422
|
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
v1.90.0
|
@@ -1 +0,0 @@
|
|
1
|
-
v1.88.0
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|