osbot-utils 1.7.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. osbot_utils/__init__.py +1 -0
  2. osbot_utils/base_classes/Cache_Pickle.py +129 -0
  3. osbot_utils/base_classes/Kwargs_To_Disk.py +27 -0
  4. osbot_utils/base_classes/Kwargs_To_Self.py +308 -0
  5. osbot_utils/base_classes/Type_Safe__List.py +14 -0
  6. osbot_utils/base_classes/__init__.py +0 -0
  7. osbot_utils/context_managers/__init__.py +0 -0
  8. osbot_utils/context_managers/capture_duration.py +33 -0
  9. osbot_utils/decorators/__init__.py +0 -0
  10. osbot_utils/decorators/classes/__init__.py +0 -0
  11. osbot_utils/decorators/classes/singleton.py +9 -0
  12. osbot_utils/decorators/lists/__init__.py +0 -0
  13. osbot_utils/decorators/lists/filter_list.py +12 -0
  14. osbot_utils/decorators/lists/group_by.py +21 -0
  15. osbot_utils/decorators/lists/index_by.py +27 -0
  16. osbot_utils/decorators/methods/__init__.py +0 -0
  17. osbot_utils/decorators/methods/cache.py +19 -0
  18. osbot_utils/decorators/methods/cache_on_function.py +56 -0
  19. osbot_utils/decorators/methods/cache_on_self.py +78 -0
  20. osbot_utils/decorators/methods/cache_on_tmp.py +71 -0
  21. osbot_utils/decorators/methods/capture_exception.py +37 -0
  22. osbot_utils/decorators/methods/capture_status.py +20 -0
  23. osbot_utils/decorators/methods/catch.py +13 -0
  24. osbot_utils/decorators/methods/context.py +11 -0
  25. osbot_utils/decorators/methods/depreciated.py +79 -0
  26. osbot_utils/decorators/methods/function_type_check.py +62 -0
  27. osbot_utils/decorators/methods/obj_as_context.py +6 -0
  28. osbot_utils/decorators/methods/remove_return_value.py +22 -0
  29. osbot_utils/decorators/methods/required_fields.py +19 -0
  30. osbot_utils/fluent/Fluent_Dict.py +19 -0
  31. osbot_utils/fluent/Fluent_List.py +44 -0
  32. osbot_utils/fluent/__init__.py +1 -0
  33. osbot_utils/graphs/__init__.py +0 -0
  34. osbot_utils/graphs/mermaid/Mermaid.py +75 -0
  35. osbot_utils/graphs/mermaid/Mermaid__Edge.py +49 -0
  36. osbot_utils/graphs/mermaid/Mermaid__Graph.py +93 -0
  37. osbot_utils/graphs/mermaid/Mermaid__Node.py +69 -0
  38. osbot_utils/graphs/mermaid/Mermaid__Renderer.py +54 -0
  39. osbot_utils/graphs/mermaid/configs/Mermaid__Edge__Config.py +7 -0
  40. osbot_utils/graphs/mermaid/configs/Mermaid__Node__Config.py +9 -0
  41. osbot_utils/graphs/mermaid/configs/Mermaid__Render__Config.py +7 -0
  42. osbot_utils/graphs/mermaid/examples/Mermaid_Examples__FlowChart.py +98 -0
  43. osbot_utils/graphs/mermaid/models/Mermaid__Diagram_Direction.py +9 -0
  44. osbot_utils/graphs/mermaid/models/Mermaid__Diagram__Type.py +17 -0
  45. osbot_utils/graphs/mermaid/models/Mermaid__Node__Shape.py +30 -0
  46. osbot_utils/graphs/mgraph/MGraph.py +53 -0
  47. osbot_utils/graphs/mgraph/MGraph__Config.py +7 -0
  48. osbot_utils/graphs/mgraph/MGraph__Data.py +139 -0
  49. osbot_utils/graphs/mgraph/MGraph__Edge.py +27 -0
  50. osbot_utils/graphs/mgraph/MGraph__Node.py +33 -0
  51. osbot_utils/graphs/mgraph/MGraph__Random_Graphs.py +27 -0
  52. osbot_utils/graphs/mgraph/MGraph__Serializer.py +43 -0
  53. osbot_utils/graphs/mgraph/MGraphs.py +17 -0
  54. osbot_utils/graphs/mgraph/__init__.py +0 -0
  55. osbot_utils/helpers/CPrint.py +98 -0
  56. osbot_utils/helpers/Dict_To_Attr.py +7 -0
  57. osbot_utils/helpers/Local_Cache.py +111 -0
  58. osbot_utils/helpers/Local_Caches.py +54 -0
  59. osbot_utils/helpers/Print_Table.py +369 -0
  60. osbot_utils/helpers/Python_Audit.py +45 -0
  61. osbot_utils/helpers/Random_Seed.py +27 -0
  62. osbot_utils/helpers/SCP.py +58 -0
  63. osbot_utils/helpers/SSH.py +151 -0
  64. osbot_utils/helpers/Type_Registry.py +16 -0
  65. osbot_utils/helpers/__init__.py +0 -0
  66. osbot_utils/helpers/ast/Ast.py +35 -0
  67. osbot_utils/helpers/ast/Ast_Base.py +124 -0
  68. osbot_utils/helpers/ast/Ast_Data.py +28 -0
  69. osbot_utils/helpers/ast/Ast_Load.py +62 -0
  70. osbot_utils/helpers/ast/Ast_Merge.py +26 -0
  71. osbot_utils/helpers/ast/Ast_Node.py +117 -0
  72. osbot_utils/helpers/ast/Ast_Visit.py +85 -0
  73. osbot_utils/helpers/ast/Call_Tree.py +38 -0
  74. osbot_utils/helpers/ast/__init__.py +145 -0
  75. osbot_utils/helpers/ast/nodes/Ast_Add.py +6 -0
  76. osbot_utils/helpers/ast/nodes/Ast_Alias.py +6 -0
  77. osbot_utils/helpers/ast/nodes/Ast_And.py +6 -0
  78. osbot_utils/helpers/ast/nodes/Ast_Argument.py +7 -0
  79. osbot_utils/helpers/ast/nodes/Ast_Arguments.py +10 -0
  80. osbot_utils/helpers/ast/nodes/Ast_Assert.py +7 -0
  81. osbot_utils/helpers/ast/nodes/Ast_Assign.py +8 -0
  82. osbot_utils/helpers/ast/nodes/Ast_Attribute.py +9 -0
  83. osbot_utils/helpers/ast/nodes/Ast_Aug_Assign.py +9 -0
  84. osbot_utils/helpers/ast/nodes/Ast_Bin_Op.py +8 -0
  85. osbot_utils/helpers/ast/nodes/Ast_Bool_Op.py +7 -0
  86. osbot_utils/helpers/ast/nodes/Ast_Break.py +7 -0
  87. osbot_utils/helpers/ast/nodes/Ast_Call.py +17 -0
  88. osbot_utils/helpers/ast/nodes/Ast_Class_Def.py +9 -0
  89. osbot_utils/helpers/ast/nodes/Ast_Compare.py +9 -0
  90. osbot_utils/helpers/ast/nodes/Ast_Comprehension.py +10 -0
  91. osbot_utils/helpers/ast/nodes/Ast_Constant.py +6 -0
  92. osbot_utils/helpers/ast/nodes/Ast_Continue.py +7 -0
  93. osbot_utils/helpers/ast/nodes/Ast_Dict.py +8 -0
  94. osbot_utils/helpers/ast/nodes/Ast_Eq.py +6 -0
  95. osbot_utils/helpers/ast/nodes/Ast_Except_Handler.py +9 -0
  96. osbot_utils/helpers/ast/nodes/Ast_Expr.py +7 -0
  97. osbot_utils/helpers/ast/nodes/Ast_For.py +10 -0
  98. osbot_utils/helpers/ast/nodes/Ast_Function_Def.py +17 -0
  99. osbot_utils/helpers/ast/nodes/Ast_Generator_Exp.py +8 -0
  100. osbot_utils/helpers/ast/nodes/Ast_Gt.py +7 -0
  101. osbot_utils/helpers/ast/nodes/Ast_GtE.py +7 -0
  102. osbot_utils/helpers/ast/nodes/Ast_If.py +9 -0
  103. osbot_utils/helpers/ast/nodes/Ast_If_Exp.py +9 -0
  104. osbot_utils/helpers/ast/nodes/Ast_Import.py +7 -0
  105. osbot_utils/helpers/ast/nodes/Ast_Import_From.py +7 -0
  106. osbot_utils/helpers/ast/nodes/Ast_In.py +6 -0
  107. osbot_utils/helpers/ast/nodes/Ast_Is.py +6 -0
  108. osbot_utils/helpers/ast/nodes/Ast_Is_Not.py +7 -0
  109. osbot_utils/helpers/ast/nodes/Ast_Keyword.py +8 -0
  110. osbot_utils/helpers/ast/nodes/Ast_Lambda.py +8 -0
  111. osbot_utils/helpers/ast/nodes/Ast_List.py +8 -0
  112. osbot_utils/helpers/ast/nodes/Ast_List_Comp.py +8 -0
  113. osbot_utils/helpers/ast/nodes/Ast_Load.py +6 -0
  114. osbot_utils/helpers/ast/nodes/Ast_Lt.py +7 -0
  115. osbot_utils/helpers/ast/nodes/Ast_LtE.py +7 -0
  116. osbot_utils/helpers/ast/nodes/Ast_Mod.py +6 -0
  117. osbot_utils/helpers/ast/nodes/Ast_Module.py +20 -0
  118. osbot_utils/helpers/ast/nodes/Ast_Mult.py +6 -0
  119. osbot_utils/helpers/ast/nodes/Ast_Name.py +6 -0
  120. osbot_utils/helpers/ast/nodes/Ast_Not.py +7 -0
  121. osbot_utils/helpers/ast/nodes/Ast_Not_Eq.py +7 -0
  122. osbot_utils/helpers/ast/nodes/Ast_Not_In.py +6 -0
  123. osbot_utils/helpers/ast/nodes/Ast_Or.py +7 -0
  124. osbot_utils/helpers/ast/nodes/Ast_Pass.py +7 -0
  125. osbot_utils/helpers/ast/nodes/Ast_Pow.py +7 -0
  126. osbot_utils/helpers/ast/nodes/Ast_Raise.py +8 -0
  127. osbot_utils/helpers/ast/nodes/Ast_Return.py +7 -0
  128. osbot_utils/helpers/ast/nodes/Ast_Set.py +7 -0
  129. osbot_utils/helpers/ast/nodes/Ast_Slice.py +8 -0
  130. osbot_utils/helpers/ast/nodes/Ast_Starred.py +8 -0
  131. osbot_utils/helpers/ast/nodes/Ast_Store.py +7 -0
  132. osbot_utils/helpers/ast/nodes/Ast_Sub.py +7 -0
  133. osbot_utils/helpers/ast/nodes/Ast_Subscript.py +8 -0
  134. osbot_utils/helpers/ast/nodes/Ast_Try.py +9 -0
  135. osbot_utils/helpers/ast/nodes/Ast_Tuple.py +9 -0
  136. osbot_utils/helpers/ast/nodes/Ast_Unary_Op.py +7 -0
  137. osbot_utils/helpers/ast/nodes/Ast_While.py +8 -0
  138. osbot_utils/helpers/ast/nodes/Ast_With.py +7 -0
  139. osbot_utils/helpers/ast/nodes/Ast_With_Item.py +7 -0
  140. osbot_utils/helpers/ast/nodes/Ast_Yield.py +7 -0
  141. osbot_utils/helpers/ast/nodes/__init__.py +0 -0
  142. osbot_utils/helpers/html/Dict_To_Css.py +20 -0
  143. osbot_utils/helpers/html/Dict_To_Html.py +59 -0
  144. osbot_utils/helpers/html/Dict_To_Tags.py +88 -0
  145. osbot_utils/helpers/html/Html_To_Dict.py +75 -0
  146. osbot_utils/helpers/html/Html_To_Tag.py +20 -0
  147. osbot_utils/helpers/html/Tag__Base.py +91 -0
  148. osbot_utils/helpers/html/Tag__Body.py +5 -0
  149. osbot_utils/helpers/html/Tag__Div.py +5 -0
  150. osbot_utils/helpers/html/Tag__H.py +9 -0
  151. osbot_utils/helpers/html/Tag__HR.py +5 -0
  152. osbot_utils/helpers/html/Tag__Head.py +32 -0
  153. osbot_utils/helpers/html/Tag__Html.py +42 -0
  154. osbot_utils/helpers/html/Tag__Link.py +17 -0
  155. osbot_utils/helpers/html/Tag__Style.py +25 -0
  156. osbot_utils/helpers/html/__init__.py +0 -0
  157. osbot_utils/helpers/pubsub/Event__Queue.py +95 -0
  158. osbot_utils/helpers/pubsub/PubSub__Client.py +53 -0
  159. osbot_utils/helpers/pubsub/PubSub__Room.py +13 -0
  160. osbot_utils/helpers/pubsub/PubSub__Server.py +94 -0
  161. osbot_utils/helpers/pubsub/PubSub__Sqlite.py +24 -0
  162. osbot_utils/helpers/pubsub/__init__.py +0 -0
  163. osbot_utils/helpers/pubsub/schemas/Schema__Event.py +15 -0
  164. osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py +7 -0
  165. osbot_utils/helpers/pubsub/schemas/Schema__Event__Disconnect.py +7 -0
  166. osbot_utils/helpers/pubsub/schemas/Schema__Event__Join_Room.py +8 -0
  167. osbot_utils/helpers/pubsub/schemas/Schema__Event__Leave_Room.py +8 -0
  168. osbot_utils/helpers/pubsub/schemas/Schema__Event__Message.py +7 -0
  169. osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py +8 -0
  170. osbot_utils/helpers/pubsub/schemas/__init__.py +0 -0
  171. osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py +51 -0
  172. osbot_utils/helpers/sqlite/Sqlite__Cursor.py +87 -0
  173. osbot_utils/helpers/sqlite/Sqlite__Database.py +137 -0
  174. osbot_utils/helpers/sqlite/Sqlite__Field.py +70 -0
  175. osbot_utils/helpers/sqlite/Sqlite__Globals.py +5 -0
  176. osbot_utils/helpers/sqlite/Sqlite__Table.py +293 -0
  177. osbot_utils/helpers/sqlite/Sqlite__Table__Create.py +96 -0
  178. osbot_utils/helpers/sqlite/Temp_Sqlite__Database__Disk.py +17 -0
  179. osbot_utils/helpers/sqlite/Temp_Sqlite__Table.py +23 -0
  180. osbot_utils/helpers/sqlite/__init__.py +0 -0
  181. osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests.py +214 -0
  182. osbot_utils/helpers/sqlite/domains/Sqlite__Cache__Requests__Patch.py +63 -0
  183. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Files.py +23 -0
  184. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Graph.py +47 -0
  185. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Json.py +83 -0
  186. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Local.py +20 -0
  187. osbot_utils/helpers/sqlite/domains/Sqlite__DB__Requests.py +39 -0
  188. osbot_utils/helpers/sqlite/domains/__init__.py +0 -0
  189. osbot_utils/helpers/sqlite/domains/schemas/Schema__Table__Requests.py +12 -0
  190. osbot_utils/helpers/sqlite/domains/schemas/__init__.py +0 -0
  191. osbot_utils/helpers/sqlite/models/Sqlite__Field__Type.py +37 -0
  192. osbot_utils/helpers/sqlite/models/__init__.py +0 -0
  193. osbot_utils/helpers/sqlite/sample_data/Sqlite__Sample_Data__Chinook.py +116 -0
  194. osbot_utils/helpers/sqlite/sample_data/__init__.py +0 -0
  195. osbot_utils/helpers/sqlite/sql_builder/SQL_Builder.py +159 -0
  196. osbot_utils/helpers/sqlite/sql_builder/SQL_Builder__Select.py +12 -0
  197. osbot_utils/helpers/sqlite/sql_builder/__init__.py +0 -0
  198. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Config.py +63 -0
  199. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Edges.py +46 -0
  200. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Files.py +45 -0
  201. osbot_utils/helpers/sqlite/tables/Sqlite__Table__Nodes.py +52 -0
  202. osbot_utils/helpers/sqlite/tables/__init__.py +0 -0
  203. osbot_utils/helpers/trace/Trace_Call.py +120 -0
  204. osbot_utils/helpers/trace/Trace_Call__Config.py +94 -0
  205. osbot_utils/helpers/trace/Trace_Call__Graph.py +26 -0
  206. osbot_utils/helpers/trace/Trace_Call__Handler.py +215 -0
  207. osbot_utils/helpers/trace/Trace_Call__Print_Lines.py +85 -0
  208. osbot_utils/helpers/trace/Trace_Call__Print_Traces.py +170 -0
  209. osbot_utils/helpers/trace/Trace_Call__Stack.py +166 -0
  210. osbot_utils/helpers/trace/Trace_Call__Stack_Node.py +59 -0
  211. osbot_utils/helpers/trace/Trace_Call__Stats.py +71 -0
  212. osbot_utils/helpers/trace/Trace_Call__View_Model.py +75 -0
  213. osbot_utils/helpers/trace/Trace_Files.py +33 -0
  214. osbot_utils/helpers/trace/__init__.py +0 -0
  215. osbot_utils/testing/Catch.py +54 -0
  216. osbot_utils/testing/Duration.py +69 -0
  217. osbot_utils/testing/Hook_Method.py +118 -0
  218. osbot_utils/testing/Log_To_Queue.py +46 -0
  219. osbot_utils/testing/Log_To_String.py +37 -0
  220. osbot_utils/testing/Logging.py +81 -0
  221. osbot_utils/testing/Patch_Print.py +52 -0
  222. osbot_utils/testing/Profiler.py +89 -0
  223. osbot_utils/testing/Stderr.py +19 -0
  224. osbot_utils/testing/Stdout.py +19 -0
  225. osbot_utils/testing/Temp_File.py +46 -0
  226. osbot_utils/testing/Temp_Folder.py +114 -0
  227. osbot_utils/testing/Temp_Sys_Path.py +13 -0
  228. osbot_utils/testing/Temp_Web_Server.py +83 -0
  229. osbot_utils/testing/Temp_Zip.py +45 -0
  230. osbot_utils/testing/Temp_Zip_In_Memory.py +90 -0
  231. osbot_utils/testing/Unit_Test.py +34 -0
  232. osbot_utils/testing/Unzip_File.py +30 -0
  233. osbot_utils/testing/__init__.py +0 -0
  234. osbot_utils/utils/Assert.py +52 -0
  235. osbot_utils/utils/Call_Stack.py +187 -0
  236. osbot_utils/utils/Csv.py +32 -0
  237. osbot_utils/utils/Dev.py +47 -0
  238. osbot_utils/utils/Exceptions.py +7 -0
  239. osbot_utils/utils/Files.py +528 -0
  240. osbot_utils/utils/Functions.py +113 -0
  241. osbot_utils/utils/Http.py +136 -0
  242. osbot_utils/utils/Int.py +6 -0
  243. osbot_utils/utils/Json.py +171 -0
  244. osbot_utils/utils/Json_Cache.py +59 -0
  245. osbot_utils/utils/Lists.py +198 -0
  246. osbot_utils/utils/Misc.py +496 -0
  247. osbot_utils/utils/Objects.py +341 -0
  248. osbot_utils/utils/Png.py +29 -0
  249. osbot_utils/utils/Process.py +73 -0
  250. osbot_utils/utils/Python_Logger.py +301 -0
  251. osbot_utils/utils/Status.py +79 -0
  252. osbot_utils/utils/Str.py +63 -0
  253. osbot_utils/utils/Version.py +16 -0
  254. osbot_utils/utils/Zip.py +97 -0
  255. osbot_utils/utils/__init__.py +16 -0
  256. osbot_utils/version +1 -0
  257. osbot_utils-1.7.7.dist-info/LICENSE +201 -0
  258. osbot_utils-1.7.7.dist-info/METADATA +46 -0
  259. osbot_utils-1.7.7.dist-info/RECORD +260 -0
  260. osbot_utils-1.7.7.dist-info/WHEEL +4 -0
@@ -0,0 +1,496 @@
1
+ import base64
2
+ import hashlib
3
+ import importlib
4
+ import logging
5
+ import os
6
+ import random
7
+ import string
8
+ import sys
9
+ import textwrap
10
+ import re
11
+ import uuid
12
+ import warnings
13
+ from datetime import datetime, timedelta, UTC
14
+ from secrets import token_bytes
15
+ from time import sleep
16
+ from typing import Iterable
17
+ from urllib.parse import quote_plus, unquote_plus
18
+
19
+ def ansi_text_visible_length(text):
20
+ ansi_escape = re.compile(r'\x1b\[[0-9;]*m') # This regex matches the escape sequences used for text formatting
21
+ visible_text = ansi_escape.sub('', text) # Remove the escape sequences
22
+ return len(visible_text) # Return the length of the remaining text
23
+
24
+ def append_random_string(target, length=6, prefix='-'):
25
+ return f'{target}{random_string(length, prefix)}'
26
+
27
+ def attr_value_from_module_name(module_name, attr_name, default_value=None):
28
+ module = importlib.import_module(module_name)
29
+ if hasattr(module, attr_name):
30
+ return getattr(module, attr_name)
31
+ return default_value
32
+
33
+ def bytes_md5(target : bytes):
34
+ return hashlib.md5(target).hexdigest()
35
+
36
+ def bytes_sha256(target : bytes):
37
+ return hashlib.sha256(target).hexdigest()
38
+
39
+ def bytes_sha384(target : bytes):
40
+ return hashlib.sha384(target).hexdigest()
41
+
42
+ def base64_to_bytes(bytes_base64):
43
+ if type(bytes_base64) is str:
44
+ bytes_base64 = bytes_base64.encode()
45
+ return base64.decodebytes(bytes_base64)
46
+
47
+ def base64_to_str(target, encoding='ascii'):
48
+ return bytes_to_str(base64_to_bytes(target), encoding=encoding)
49
+
50
+ def bytes_to_base64(target):
51
+ return base64.b64encode(target).decode()
52
+
53
+ def bytes_to_str(target, encoding='ascii'):
54
+ return target.decode(encoding=encoding)
55
+
56
+ def convert_to_number(value):
57
+ if value:
58
+ try:
59
+ if value[0] in ['£','$','€']:
60
+ return float(re.sub(r'[^\d.]', '', value))
61
+ else:
62
+ return float(value)
63
+ except:
64
+ return 0
65
+ else:
66
+ return 0
67
+
68
+ def date_time_from_to_str(date_time_str, format_from, format_to, print_conversion_error=False):
69
+ try:
70
+ date_time = datetime.strptime(date_time_str, format_from)
71
+ return date_time.strftime(format_to)
72
+ except ValueError as value_error:
73
+ if print_conversion_error:
74
+ print(f"[date_time_from_to_str]: Error: {value_error}") # todo: use log handler
75
+ return None
76
+
77
+
78
+ def date_time_to_str(date_time, date_time_format='%Y-%m-%d %H:%M:%S.%f', milliseconds_numbers=3):
79
+ if date_time:
80
+ date_time_str = date_time.strftime(date_time_format)
81
+ return time_str_milliseconds(datetime_str=date_time_str, datetime_format=date_time_format, milliseconds_numbers=milliseconds_numbers)
82
+ else:
83
+ return ''
84
+
85
+ def date_now(use_utc=True, return_str=True):
86
+ value = date_time_now(use_utc=use_utc, return_str=False)
87
+ if return_str:
88
+ return date_to_str(date=value)
89
+ return value
90
+
91
+ def date_time_now(use_utc=True, return_str=True, milliseconds_numbers=0, date_time_format='%Y-%m-%d %H:%M:%S.%f'):
92
+ if use_utc:
93
+ value = datetime.now(UTC)
94
+ #value = datetime.utcnow() # todo: this has been marked for depreciation in python 11
95
+ # value = datetime.now(UTC) # but this doesn't seem to work in python 10.x : E ImportError: cannot import name 'UTC' from 'datetime' (/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/datetime.py)
96
+
97
+ else:
98
+ value = datetime.now()
99
+ if return_str:
100
+ return date_time_to_str(value, milliseconds_numbers=milliseconds_numbers, date_time_format=date_time_format)
101
+ return value
102
+
103
+ # def date_time_parse(value):
104
+ # if type(value) is datetime:
105
+ # return value
106
+ # return parser.parse(value)
107
+
108
+ def date_time_less_time_delta(date_time, days=0, hours=0, minutes=0, seconds=0, date_time_format='%Y-%m-%d %H:%M:%S' , return_str=True):
109
+ new_date_time = date_time - timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
110
+ if return_str:
111
+ return date_time_to_str(new_date_time, date_time_format=date_time_format)
112
+ return new_date_time
113
+
114
+ def date_time_now_less_time_delta(days=0,hours=0, minutes=0, seconds=0, date_time_format='%Y-%m-%d %H:%M:%S', return_str=True):
115
+ return date_time_less_time_delta(datetime.now(UTC),days=days, hours=hours, minutes=minutes, seconds=seconds,date_time_format=date_time_format, return_str=return_str)
116
+
117
+ def date_to_str(date, date_format='%Y-%m-%d'):
118
+ return date.strftime(date_format)
119
+
120
+ #note: this is here at the moment due to a circular dependency with lists and objects
121
+ def list_set(target):
122
+ if hasattr(target, '__iter__'):
123
+ return sorted(list(set(target)))
124
+ return []
125
+
126
+ def time_str_milliseconds(datetime_str, datetime_format, milliseconds_numbers=0):
127
+ if '.%f' in datetime_format and -1 < milliseconds_numbers < 6:
128
+ chars_to_remove = milliseconds_numbers-6
129
+ if milliseconds_numbers == 0:
130
+ chars_to_remove -= 1
131
+ return datetime_str[:chars_to_remove]
132
+ return datetime_str
133
+
134
+ def flist(target):
135
+ from osbot_utils.fluent.Fluent_List import Fluent_List
136
+ return Fluent_List(target)
137
+
138
+ # todo: check if this should still be here
139
+ def get_random_color(max=5):
140
+ if max > 5: max = 5 # add support for more than 5 colors
141
+ colors = ['skyblue', 'darkseagreen', 'palevioletred', 'coral', 'darkgray']
142
+ return colors[random_number(0, max-1)]
143
+
144
+ def in_github_action():
145
+ return os.getenv('GITHUB_ACTIONS') == 'true'
146
+
147
+ def is_debugging():
148
+ return sys.gettrace() is not None
149
+
150
+ def is_number(value):
151
+ try:
152
+ if type(value) is int or type(value) is float :
153
+ int(value)
154
+ return True
155
+ except:
156
+ pass
157
+ return False
158
+
159
+ def is_int(value):
160
+ try:
161
+ int(value)
162
+ return True
163
+ except ValueError:
164
+ return False
165
+
166
+ def is_float(value):
167
+ try:
168
+ float(value)
169
+ return True
170
+ except ValueError:
171
+ return False
172
+
173
+ def is_guid(value):
174
+ try:
175
+ uuid_obj = uuid.UUID(value)
176
+ return str(uuid_obj) == value.lower()
177
+ except ValueError:
178
+ return False
179
+
180
+
181
+ def ignore_warning__unclosed_ssl():
182
+ warnings.filterwarnings("ignore", category=ResourceWarning, message="unclosed.*<ssl.SSLSocket.*>")
183
+
184
+
185
+ def last_letter(text):
186
+ if text and (type(text) is str) and len(text) > 0:
187
+ return text[-1]
188
+
189
+
190
+ # def log_critical(message): logger().critical(message) # level 50
191
+ # def log_debug (message): logger().debug (message) # level 10
192
+ # def log_error (message): logger().error (message) # level 40
193
+ # def log_info (message): logger().info (message) # level 20
194
+ # def log_warning (message): logger().warning (message) # level 30
195
+
196
+ def log_to_console(level="INFO"):
197
+ logger_set_level(level)
198
+ logger_add_handler__console()
199
+ print() # add extra print so that in pytest the first line is not hidden
200
+
201
+ def log_to_file(level="INFO"):
202
+ logger_set_level(level)
203
+ return logger_add_handler__file()
204
+
205
+ def logger():
206
+ return logging.getLogger()
207
+
208
+ def logger_add_handler(handler):
209
+ logger().addHandler(handler)
210
+
211
+ def logger_add_handler__console():
212
+ logger_add_handler(logging.StreamHandler())
213
+
214
+ def logger_add_handler__file(log_file=None):
215
+ from osbot_utils.utils.Files import temp_file
216
+ log_file = log_file or temp_file(extension=".log")
217
+ logger_add_handler(logging.FileHandler(filename=log_file))
218
+ return log_file
219
+
220
+ def logger_set_level(level):
221
+ logger().setLevel(level)
222
+
223
+ def logger_set_level_critical(): logger_set_level('CRITICAL') # level 50
224
+ def logger_set_level_debug (): logger_set_level('DEBUG' ) # level 10
225
+ def logger_set_level_error (): logger_set_level('ERROR' ) # level 40
226
+ def logger_set_level_info (): logger_set_level('INFO' ) # level 20
227
+ def logger_set_level_warning (): logger_set_level('WARNING' ) # level 30
228
+
229
+ def lower(target : str):
230
+ if target:
231
+ return target.lower()
232
+ return ""
233
+
234
+ def size(target=None):
235
+ if target and hasattr(target, '__len__'):
236
+ return len(target)
237
+ return 0
238
+
239
+ def str_md5(text : str):
240
+ if text:
241
+ return bytes_md5(text.encode())
242
+ return ''
243
+
244
+ def none_or_empty(target,field):
245
+ if target and field:
246
+ value = target.get(field)
247
+ return (value is None) or value == ''
248
+ return True
249
+
250
+ def print_date_now(use_utc=True):
251
+ print(date_time_now(use_utc=use_utc))
252
+
253
+ def print_time_now(use_utc=True):
254
+ print(time_now(use_utc=use_utc))
255
+
256
+ def str_sha256(text: str):
257
+ if text:
258
+ return bytes_sha256(text.encode())
259
+ return None
260
+
261
+ def str_sha384(text:str):
262
+ if text:
263
+ return bytes_sha384(text.encode())
264
+ return
265
+
266
+ def str_sha384_as_base64(text:str, include_prefix=True):
267
+ if text:
268
+ hash_object = hashlib.sha384(text.encode())
269
+ digest = hash_object.digest() # Getting the digest of the hash
270
+ digest_base64 = base64.b64encode(digest).decode() # Converting the digest to Base64 encoding
271
+ if include_prefix:
272
+ return "sha384-" + digest_base64
273
+ return digest_base64
274
+ return
275
+
276
+ def time_delta_to_str(time_delta):
277
+ microseconds = time_delta.microseconds
278
+ milliseconds = int(microseconds / 1000)
279
+ total_seconds = int(time_delta.total_seconds())
280
+ return f'{total_seconds}s {milliseconds}ms'
281
+
282
+ def time_delta_in_days_hours_or_minutes(time_delta):
283
+ total_seconds = int(time_delta.total_seconds())
284
+ days , seconds = divmod(total_seconds, 86400)
285
+ hours , seconds = divmod(seconds , 3600 )
286
+ minutes, seconds = divmod(seconds , 60 )
287
+ if days > 0:
288
+ return f"{days}d {hours}h {minutes}m"
289
+ elif hours > 0:
290
+ return f"{hours:4}h {minutes}m"
291
+ elif minutes >0:
292
+ return f"{minutes}m"
293
+ elif seconds >0:
294
+ return f"{seconds}s"
295
+
296
+
297
+ def time_now(use_utc=True, milliseconds_numbers=1):
298
+ if use_utc:
299
+ datetime_now = datetime.now(UTC)
300
+ else:
301
+ datetime_now = datetime.now()
302
+ return time_to_str(datetime_value=datetime_now,milliseconds_numbers=milliseconds_numbers)
303
+
304
+ def time_to_str(datetime_value, time_format='%H:%M:%S.%f', milliseconds_numbers=3):
305
+ time_str = datetime_value.strftime(time_format)
306
+ return time_str_milliseconds(datetime_str=time_str, datetime_format=time_format, milliseconds_numbers=milliseconds_numbers)
307
+
308
+ def timestamp_utc_now():
309
+ return int(datetime.now(UTC).timestamp() * 1000)
310
+
311
+ def timestamp_utc_now_less_delta(days=0,hours=0, minutes=0, seconds=0):
312
+ date_time = date_time_now_less_time_delta(days=days,hours=hours, minutes=minutes, seconds=seconds, return_str=False)
313
+ return datetime_to_timestamp(date_time)
314
+
315
+ def datetime_to_timestamp(datetime):
316
+ return int(datetime.timestamp() * 1000)
317
+
318
+ def timestamp_to_datetime(timestamp):
319
+ timestamp = float(timestamp) # handle cases when timestamp is a Decimal
320
+ return datetime.fromtimestamp(timestamp/1000)
321
+
322
+ def timestamp_to_str(timestamp, date_time_format='%Y-%m-%d %H:%M:%S.%f'):
323
+ date_time = timestamp_to_datetime(timestamp)
324
+ return datetime_to_str(date_time, date_time_format=date_time_format)
325
+
326
+ def timestamp_to_str_date(timestamp, date_format='%Y-%m-%d'):
327
+ return timestamp_to_str(timestamp, date_format)
328
+
329
+ def timestamp_to_str_time(timestamp, time_format='%H:%M:%S'):
330
+ return timestamp_to_str(timestamp, time_format)
331
+
332
+ def to_string(target):
333
+ if target:
334
+ return str(target)
335
+ return ''
336
+
337
+ def random_bytes(length=24):
338
+ return token_bytes(length)
339
+
340
+ def random_filename(extension='.tmp', length=10):
341
+ from osbot_utils.utils.Files import file_extension_fix
342
+ extension = file_extension_fix(extension)
343
+ return '{0}{1}'.format(''.join(random.choices(string.ascii_lowercase + string.digits, k=length)) , extension)
344
+
345
+ def random_port(min=20000,max=65000):
346
+ return random_number(min, max)
347
+
348
+ def random_number(min=1,max=65000):
349
+ return random.randint(min, max)
350
+
351
+ def random_password(length=24, prefix=''):
352
+ password = prefix + ''.join(random.choices(string.ascii_lowercase +
353
+ string.ascii_uppercase +
354
+ string.punctuation +
355
+ string.digits ,
356
+ k=length))
357
+ # replace these chars with _ (to make prevent errors in command prompts and urls)
358
+ items = ['"', '\'', '`','\\','/','}','?','#',';',':']
359
+ for item in items:
360
+ password = password.replace(item, '_')
361
+ return password
362
+
363
+ def random_string(length:int=8, prefix:str='', postfix:str=''):
364
+ if is_int(length):
365
+ length -= 1 # so that we get the exact length when the value is provided
366
+ else:
367
+ length = 7 # default length
368
+ value = '_' + ''.join(random.choices(string.ascii_uppercase, k=length)).lower()
369
+ return f"{prefix}{value}{postfix}"
370
+
371
+ def random_string_and_numbers(length:int=6,prefix:str=''):
372
+ return prefix + ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))
373
+
374
+ def random_text(prefix:str=None,length:int=12, lowercase=False):
375
+ if prefix is None: prefix = 'text_'
376
+ if last_letter(prefix) not in ['_','/']:
377
+ prefix += '_'
378
+ value = random_string_and_numbers(length=length, prefix=prefix)
379
+ if lowercase:
380
+ return lower(value)
381
+ return value
382
+
383
+ def random_uuid():
384
+ return str(uuid.uuid4())
385
+
386
+ def remove(target_string, string_to_remove): # todo: refactor to str_*
387
+ return replace(target_string, string_to_remove, '')
388
+
389
+ def remove_multiple_spaces(target): # todo: refactor to str_*
390
+ return re.sub(' +', ' ', target)
391
+
392
+ def replace(target_string, string_to_find, string_to_replace): # todo: refactor to str_*
393
+ return target_string.replace(string_to_find, string_to_replace)
394
+
395
+ def remove_html_tags(html):
396
+ if html:
397
+ TAG_RE = re.compile(r'<[^>]+>')
398
+ return TAG_RE.sub('', html).replace('&nbsp;', ' ')
399
+
400
+ def split_lines(text):
401
+ return text.replace('\r\n','\n').split('\n')
402
+
403
+ def split_spaces(target):
404
+ return remove_multiple_spaces(target).split(' ')
405
+
406
+ def sorted_set(target : Iterable):
407
+ if target:
408
+ return sorted(set(target))
409
+ return []
410
+
411
+ def str_to_base64(target):
412
+ return bytes_to_base64(str_to_bytes(target))
413
+
414
+ def str_to_bytes(target):
415
+ return target.encode()
416
+
417
+ def str_to_date(str_date, format='%Y-%m-%d %H:%M:%S.%f'):
418
+ return datetime.strptime(str_date,format)
419
+
420
+ def str_to_date_time(str_date, format='%Y-%m-%d %H:%M:%S'):
421
+ return datetime.strptime(str_date,format)
422
+
423
+ def str_to_int(str_data):
424
+ return int(float(str_data))
425
+
426
+
427
+ def to_int(value, default=0):
428
+ try:
429
+ return int(value)
430
+ except:
431
+ return default
432
+
433
+ def under_debugger():
434
+ return 'pydevd' in sys.modules
435
+
436
+
437
+ def url_encode(data):
438
+ if type(data) is str:
439
+ return quote_plus(data)
440
+
441
+ def url_decode(data):
442
+ if type(data) is str:
443
+ return unquote_plus(data)
444
+
445
+ def utc_now():
446
+ return datetime.now(UTC)
447
+
448
+ def upper(target : str):
449
+ if target:
450
+ return target.upper()
451
+ return ""
452
+
453
+ def wait(seconds):
454
+ if seconds and seconds > 0:
455
+ sleep(seconds)
456
+
457
+ def word_wrap(text,length = 40):
458
+ if text:
459
+ wrapped_text = ""
460
+ for line in text.splitlines(): # handle case when there are newlines inside the text value
461
+ wrapped_text += '\n'.join(textwrap.wrap(line, length))
462
+ wrapped_text += '\n'
463
+ return wrapped_text
464
+ return ''
465
+
466
+ def word_wrap_escaped(text,length = 40):
467
+ if text:
468
+ return '\\n'.join(textwrap.wrap(text, length))
469
+
470
+ bytes_to_string = bytes_to_str
471
+
472
+ convert_to_float = convert_to_number
473
+
474
+ datetime_now = date_time_now
475
+ datetime_to_str = date_time_to_str
476
+ datetime_from_timestamp = timestamp_to_datetime
477
+ datetime_utc_now = utc_now
478
+ date_time_to_timestamp = datetime_to_timestamp
479
+ date_time_from_timestamp = timestamp_to_datetime
480
+ date_time_from_time_stamp = timestamp_to_datetime
481
+ date_time_utc_now = utc_now
482
+
483
+
484
+ new_guid = random_uuid
485
+
486
+ str_lines = split_lines
487
+ str_remove = remove
488
+
489
+ random_id = random_string
490
+ random_int = random_number
491
+ random_guid = random_uuid
492
+ random_value = random_string
493
+
494
+ time_utc = time_now
495
+ wait_for = wait
496
+