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,47 @@
1
+ import json
2
+ import pprint as original_pprint
3
+
4
+ from osbot_utils.utils.Misc import date_time_now
5
+
6
+
7
+ class Dev:
8
+ @staticmethod
9
+ def jformat(data):
10
+ return json.dumps(data, indent=4) # use json.dumps to format
11
+
12
+ @staticmethod
13
+ def jprint(data):
14
+ print() # add a line before
15
+ print(json.dumps(data, indent=4)) # use json.dumps to format
16
+ return data
17
+
18
+ @staticmethod
19
+ def pformat(data):
20
+ return original_pprint.pformat(data, indent=2) # use a pprint to format
21
+
22
+ @staticmethod
23
+ def pprint(*args):
24
+ print() # add a line before
25
+ for arg in args:
26
+ original_pprint.pprint(arg, indent=2) # use a pprint to format
27
+ if len(args) == 1:
28
+ return args[0]
29
+ return args
30
+
31
+ @staticmethod
32
+ def nprint(data):
33
+ print() # add a line before
34
+ print(data)
35
+ return data
36
+
37
+ @staticmethod
38
+ def print_now():
39
+ print(date_time_now())
40
+
41
+ jformat = Dev.jformat
42
+ jprint = Dev.jprint
43
+ pformat = Dev.pformat
44
+ pprint = Dev.pprint
45
+ nprint = Dev.nprint
46
+
47
+ print_now = Dev.print_now
@@ -0,0 +1,7 @@
1
+ def syntax_error(error):
2
+ if type(error) is SyntaxError:
3
+ error_message = f"{error.msg} in {error.filename} at line {error.lineno} column {error.offset}\n\n"
4
+ error_message += f" {error.text}"
5
+ error_message += f" {' ' * (error.offset - 1)}^"
6
+ return Exception(f'[SyntaxError] \n\nError parsing code: {error_message}')
7
+ return Exception(f'{error}')
@@ -0,0 +1,528 @@
1
+ import gzip
2
+
3
+ import os
4
+ import glob
5
+ import pickle
6
+ import re
7
+ import shutil
8
+ import tempfile
9
+ from os.path import abspath, join
10
+ from pathlib import Path, PosixPath
11
+ from osbot_utils.utils.Misc import bytes_to_base64, base64_to_bytes, random_string
12
+
13
+
14
+ class Files:
15
+ @staticmethod
16
+ def bytes(path):
17
+ with open(path, 'rb') as file:
18
+ return file.read()
19
+
20
+ @staticmethod
21
+ def copy(source:str, destination:str) -> str:
22
+ if file_exists(source): # make sure source file exists
23
+ destination_parent_folder = parent_folder(destination) # get target parent folder
24
+ folder_create(destination_parent_folder) # ensure targer folder exists # todo: check if this is still needed (we should be using a copy method that creates the required fodlers)
25
+ return shutil.copy(source, destination) # copy file and returns file destination
26
+
27
+ @staticmethod
28
+ def contains(path, content):
29
+ text = Files.contents(path)
30
+ if type(content) is list:
31
+ for item in content:
32
+ if item not in text:
33
+ return False
34
+ return True
35
+ return content in text
36
+
37
+ @staticmethod
38
+ def contents(path, mode='rt'):
39
+ if file_exists(path):
40
+ with file_open(path, mode) as file:
41
+ return file.read()
42
+
43
+ @staticmethod
44
+ def contents_gz(path, mode='rt'):
45
+ if file_exists(path):
46
+ with file_open_gz(path, mode) as file:
47
+ return file.read()
48
+
49
+ @staticmethod
50
+ def contents_md5(path):
51
+ from osbot_utils.utils.Misc import bytes_md5
52
+ return bytes_md5(file_contents_as_bytes(path))
53
+
54
+ @staticmethod
55
+ def contents_sha256(path):
56
+ from osbot_utils.utils.Misc import bytes_sha256
57
+ return bytes_sha256(file_contents_as_bytes(path))
58
+
59
+ @staticmethod
60
+ def current_folder():
61
+ return Files.path_combine(".","")
62
+
63
+ @staticmethod
64
+ def delete(path):
65
+ if Files.exists(path):
66
+ os.remove(path)
67
+ return Files.exists(path) is False
68
+ return False
69
+
70
+ @staticmethod
71
+ def exists(path):
72
+ return is_file(str(path))
73
+ # if path and is_file(path):
74
+ # return os.path.exists(path)
75
+ # return False
76
+
77
+ @staticmethod
78
+ def find(path_pattern, recursive=True):
79
+ return glob.glob(path_pattern, recursive=recursive)
80
+
81
+ @staticmethod
82
+ def files(path, pattern= '*.*'): # todo: check behaviour and improve ability to detect file (vs folders)
83
+ result = []
84
+ for file in Path(path).rglob(pattern):
85
+ result.append(str(file)) # todo: see if there is a better way to do this conversion to string
86
+ return sorted(result)
87
+
88
+ @staticmethod
89
+ def files_names(files : list, check_if_exists=True):
90
+ result = []
91
+ for file in files:
92
+ if is_file(file):
93
+ result.append(file_name(file, check_if_exists=check_if_exists))
94
+ return result
95
+
96
+ @staticmethod
97
+ def file_create_all_parent_folders(file_path):
98
+ if file_path:
99
+ parent_path = parent_folder(file_path)
100
+ if parent_path:
101
+ path = Path(parent_path)
102
+ path.mkdir(parents=True, exist_ok=True)
103
+ return parent_path
104
+
105
+ @staticmethod
106
+ def file_name(path, check_if_exists=True):
107
+ if is_file(path) or check_if_exists is False:
108
+ return os.path.basename(path)
109
+
110
+ @staticmethod
111
+ def file_name_without_extension(path):
112
+ if path:
113
+ path_file_name = file_name(path)
114
+ extension = file_extension(path_file_name)
115
+ if extension:
116
+ return path_file_name.replace(extension, '')
117
+
118
+
119
+ @staticmethod
120
+ def file_extension(path):
121
+ if path and '.' in path:
122
+ return os.path.splitext(path)[1]
123
+ return ''
124
+
125
+ @staticmethod
126
+ def file_extension_fix(extension):
127
+ if extension is None or len(extension) == 0: # if it None or empty return default .tmp extension
128
+ return '.tmp'
129
+ if extension[0] != '.': # make sure that the extension starts with a dot
130
+ return '.' + extension
131
+ return extension
132
+
133
+ @staticmethod
134
+ def file_to_base64(path):
135
+ return bytes_to_base64(file_bytes(path))
136
+
137
+ @staticmethod
138
+ def file_from_base64(bytes_base64, path=None, extension=None):
139
+ bytes_ = base64_to_bytes(bytes_base64)
140
+ return file_create_bytes(bytes=bytes_, path=path, extension=None)
141
+
142
+ @staticmethod
143
+ def file_size(path):
144
+ return file_stats(path).st_size
145
+
146
+ @staticmethod
147
+ def file_stats(path):
148
+ return os.stat(path)
149
+
150
+ @staticmethod
151
+ def filter_parent_folder(items, folder):
152
+ all_relative_items = []
153
+ for item in items:
154
+ all_relative_items.append(item.replace(folder, '')[1:])
155
+ return sorted(all_relative_items)
156
+
157
+ @staticmethod
158
+ def files_recursive(parent_dir, include_folders=False):
159
+ all_files = []
160
+ if os.path.isdir(parent_dir):
161
+ for item in os.listdir(parent_dir):
162
+ item_path = os.path.join(parent_dir, item)
163
+ if os.path.isfile(item_path):
164
+ all_files.append(item_path)
165
+ elif os.path.isdir(item_path):
166
+ if include_folders:
167
+ all_files.append(item_path + '/')
168
+ all_files.extend(files_recursive(item_path,include_folders=include_folders))
169
+
170
+
171
+ return sorted(all_files)
172
+
173
+
174
+ @staticmethod
175
+ def folder_exists(path):
176
+ return is_folder(path)
177
+
178
+ @staticmethod
179
+ def folder_copy(source, destination, ignore_pattern=None):
180
+ if ignore_pattern:
181
+ if type(ignore_pattern) is str:
182
+ ignore_pattern = [ignore_pattern]
183
+ ignore = shutil.ignore_patterns(*ignore_pattern) # for example ignore_pattern = ['*.pyc','.DS_Store']
184
+ else:
185
+ ignore = None
186
+ return shutil.copytree(src=source, dst=destination, ignore=ignore)
187
+
188
+ @staticmethod
189
+ def folder_create(path):
190
+ if folder_exists(path):
191
+ return path
192
+
193
+ os.makedirs(path)
194
+ return path
195
+
196
+ @staticmethod
197
+ def folder_create_in_parent(path, name):
198
+ folder_path = path_combine(path, name)
199
+ return folder_create(folder_path)
200
+
201
+ @staticmethod
202
+ def folder_delete(target_folder):
203
+ if folder_exists(target_folder):
204
+ try:
205
+ os.rmdir(target_folder)
206
+ return True
207
+ except OSError:
208
+ pass
209
+ return False
210
+
211
+ @staticmethod
212
+ def folder_delete_all(path): # this will remove recursively
213
+ if folder_exists(path):
214
+ shutil.rmtree(path)
215
+ return folder_exists(path) is False
216
+ return False
217
+
218
+ @staticmethod
219
+ def folder_name(path):
220
+ if path:
221
+ return os.path.basename(path)
222
+
223
+ @staticmethod
224
+ def folder_not_exists(path):
225
+ return folder_exists(path) is False
226
+
227
+ @staticmethod
228
+ def folder_sub_folders(path):
229
+ result = []
230
+ item: os.DirEntry
231
+ if Files.is_folder(path):
232
+ for item in os.scandir(path):
233
+ if item.is_dir():
234
+ result.append(item.path)
235
+ return result
236
+
237
+ @staticmethod
238
+ def folders_names(folders : list):
239
+ result = []
240
+ for folder in folders:
241
+ if folder:
242
+ result.append(folder_name(folder))
243
+ return sorted(result)
244
+
245
+ @staticmethod
246
+ def folders_sub_folders(folders : list):
247
+ result = []
248
+ for folder in folders:
249
+ result.extend(Files.folder_sub_folders(folder))
250
+ return result
251
+
252
+ @staticmethod
253
+ def folders_recursive(parent_dir):
254
+ subdirectories = []
255
+ for item in os.listdir(parent_dir):
256
+ item_path = os.path.join(parent_dir, item)
257
+ if os.path.isdir(item_path):
258
+ subdirectories.append(item_path)
259
+ subdirectories.extend(folders_recursive(item_path))
260
+
261
+ return sorted(subdirectories)
262
+
263
+
264
+ @staticmethod
265
+ def is_file(target):
266
+ if isinstance(target, Path):
267
+ return target.is_file()
268
+ if type(target) is str:
269
+ return os.path.isfile(target)
270
+ return False
271
+
272
+ @staticmethod
273
+ def is_folder(target):
274
+ if isinstance(target, Path):
275
+ return target.is_dir()
276
+ if type(target) is str:
277
+ return os.path.isdir(target)
278
+ return False
279
+
280
+ @staticmethod
281
+ def lines(path):
282
+ with open(path, "rt") as file:
283
+ for line in file:
284
+ yield line
285
+
286
+ @staticmethod
287
+ def lines_gz(path):
288
+ with gzip.open(path, "rt") as file:
289
+ for line in file:
290
+ yield line
291
+
292
+ @staticmethod
293
+ def not_exists(path):
294
+ return os.path.exists(str(path)) is False
295
+
296
+ @staticmethod
297
+ def open(path, mode='r'):
298
+ return open(path, mode=mode)
299
+
300
+ @staticmethod
301
+ def open_gz(path, mode='r'):
302
+ return gzip.open(path, mode=mode)
303
+
304
+ @staticmethod
305
+ def open_bytes(path):
306
+ return Files.open(path, mode='rb')
307
+
308
+ @staticmethod
309
+ def path_combine(path1, path2):
310
+ if type(path1) in [str, Path] and type(path2) in [str, Path]:
311
+ return abspath(join(str(path1), str(path2)))
312
+
313
+ @staticmethod
314
+ def parent_folder(path):
315
+ if path:
316
+ return os.path.dirname(path)
317
+
318
+ @staticmethod
319
+ def parent_folder_combine(file, path):
320
+ return Files.path_combine(os.path.dirname(file),path)
321
+
322
+ @staticmethod
323
+ def pickle_save_to_file(object_to_save, path=None):
324
+ path = path or temp_file(extension=".pickle")
325
+ file_to_store = open(path, "wb")
326
+ pickle.dump(object_to_save, file_to_store)
327
+ file_to_store.close()
328
+ return path
329
+
330
+ @staticmethod
331
+ def pickle_load_from_file(path=None):
332
+ file_to_read = open(path, "rb")
333
+ loaded_object = pickle.load(file_to_read)
334
+ file_to_read.close()
335
+ return loaded_object
336
+
337
+ @staticmethod
338
+ def safe_file_name(file_name):
339
+ if type(file_name) is not str:
340
+ file_name = f"{file_name}"
341
+ return re.sub(r'[^a-zA-Z0-9_.-]', '_',file_name or '')
342
+
343
+ @staticmethod
344
+ def save(contents, path=None, extension=None):
345
+ path = path or temp_file(extension=extension)
346
+ file_create(path, contents)
347
+ return path
348
+
349
+ @staticmethod
350
+ def sub_folders(target):
351
+ if type(target) is list:
352
+ return Files.folders_sub_folders(target)
353
+ if type(target) is str:
354
+ return Files.folder_sub_folders(target)
355
+ return []
356
+
357
+ @staticmethod
358
+ def save_bytes_as_file(bytes_to_save, path=None, extension=None):
359
+ if path is None:
360
+ path = Files.temp_file(extension)
361
+ with open(path, 'wb') as fp:
362
+ fp.write(bytes_to_save)
363
+ return path
364
+
365
+ @staticmethod
366
+ def temp_file(extension = '.tmp', contents=None, target_folder=None):
367
+ extension = file_extension_fix(extension)
368
+ if target_folder is None:
369
+ (fd, tmp_file) = tempfile.mkstemp(extension)
370
+ file_delete(tmp_file)
371
+ else:
372
+ tmp_file = path_combine(target_folder, temp_filename(extension))
373
+
374
+ if contents:
375
+ file_create(tmp_file, contents)
376
+ return tmp_file
377
+
378
+ @staticmethod
379
+ def temp_file_in_folder(target_folder, prefix="temp_file_", postfix='.txt'):
380
+ if is_folder(target_folder):
381
+ path_to_file = path_combine(target_folder, random_string(prefix=prefix, postfix=postfix))
382
+ file_create(path_to_file, random_string())
383
+ return path_to_file
384
+
385
+
386
+
387
+ @staticmethod
388
+ def temp_filename(extension='.tmp'):
389
+ return file_name(temp_file(extension), check_if_exists=False)
390
+
391
+ @staticmethod
392
+ def temp_folder(prefix=None, suffix=None,target_folder=None):
393
+ return tempfile.mkdtemp(suffix, prefix, target_folder)
394
+
395
+ @staticmethod
396
+ def temp_folder_current():
397
+ return tempfile.gettempdir()
398
+
399
+ @staticmethod
400
+ def temp_folder_with_temp_file(prefix=None, suffix=None,parent_folder=None, file_name='temp_file.txt', file_contents='temp_file'):
401
+ folder = temp_folder(prefix,suffix,parent_folder)
402
+ file_create(path_combine(folder,file_name), file_contents)
403
+ return folder
404
+
405
+ @staticmethod
406
+ def write(path = None,contents=None, extension=None, mode='w'):
407
+ path = path or temp_file(extension)
408
+ contents = contents or ''
409
+ with open(file=path, mode=mode) as file:
410
+ file.write(contents)
411
+ return path
412
+
413
+ @staticmethod
414
+ def write_bytes(path=None, bytes=None, extension=None):
415
+ return Files.write(path=path, contents=bytes, extension=extension, mode='wb')
416
+
417
+ @staticmethod
418
+ def write_gz(path=None, contents=None):
419
+ path = path or temp_file(extension='.gz')
420
+ contents = contents or ''
421
+ if type(contents) is str:
422
+ contents = contents.encode()
423
+ with gzip.open(path, "w") as file:
424
+ file.write(contents)
425
+ return path
426
+
427
+ # todo: refactor the methods above into static methods
428
+
429
+
430
+
431
+ # helper methods
432
+ # todo: all all methods above (including the duplicated mappings at the top)
433
+
434
+ create_folder = Files.folder_create
435
+ create_folder_in_parent = Files.folder_create_in_parent
436
+ create_temp_file = Files.write
437
+ current_folder = Files.current_folder
438
+ current_temp_folder = Files.temp_folder_current
439
+
440
+ file_bytes = Files.bytes
441
+ file_contains = Files.contains
442
+ file_contents = Files.contents
443
+ file_contents_gz = Files.contents_gz
444
+ file_contents_md5 = Files.contents_md5
445
+ file_contents_sha256 = Files.contents_sha256
446
+ file_contents_as_bytes = Files.bytes
447
+ file_create_all_parent_folders = Files.file_create_all_parent_folders
448
+ file_copy = Files.copy
449
+ file_delete = Files.delete
450
+ file_create = Files.write
451
+ file_create_bytes = Files.write_bytes
452
+ file_create_from_bytes = Files.write_bytes
453
+ file_create_gz = Files.write_gz
454
+ file_exists = Files.exists
455
+ file_extension = Files.file_extension
456
+ file_extension_fix = Files.file_extension_fix
457
+ file_lines = Files.lines
458
+ file_lines_gz = Files.lines_gz
459
+ file_md5 = Files.contents_md5
460
+ file_name = Files.file_name
461
+ file_name_without_extension = Files.file_name_without_extension
462
+ file_not_exists = Files.not_exists
463
+ file_open = Files.open
464
+ file_open_gz = Files.open_gz
465
+ file_open_bytes = Files.open_bytes
466
+ file_to_base64 = Files.file_to_base64
467
+ file_from_base64 = Files.file_from_base64
468
+ file_save = Files.save
469
+ file_sha256 = Files.contents_sha256
470
+ file_size = Files.file_size
471
+ file_stats = Files.file_stats
472
+ file_write = Files.write
473
+ file_write_bytes = Files.write_bytes
474
+ file_write_gz = Files.write_gz
475
+ filter_parent_folder = Files.filter_parent_folder
476
+ files_find = Files.find
477
+ files_recursive = Files.files_recursive
478
+ files_list = Files.files
479
+ files_names = Files.files_names
480
+
481
+ find_files = Files.files
482
+
483
+ folder_create = Files.folder_create
484
+ folder_create_in_parent = Files.folder_create_in_parent
485
+ folder_create_temp = Files.temp_folder
486
+ folder_copy = Files.folder_copy
487
+ folder_copy_except = Files.folder_copy
488
+ folder_delete = Files.folder_delete
489
+ folder_delete_all = Files.folder_delete_all
490
+ folder_delete_recursively = Files.folder_delete_all
491
+ folder_exists = Files.folder_exists
492
+ folder_not_exists = Files.folder_not_exists
493
+ folder_name = Files.folder_name
494
+ folder_temp = Files.temp_folder
495
+ folder_files = Files.files
496
+ folder_sub_folders = Files.folder_sub_folders
497
+
498
+ folders_in_folder = Files.folder_sub_folders
499
+ folders_names = Files.folders_names
500
+ folders_recursive = Files.folders_recursive
501
+ folders_sub_folders = Files.folders_sub_folders
502
+
503
+ is_file = Files.is_file
504
+ is_folder = Files.is_folder
505
+
506
+ load_file = Files.contents
507
+ load_file_gz = Files.contents_gz
508
+
509
+ path_append = Files.path_combine
510
+ path_combine = Files.path_combine
511
+ path_current = Files.current_folder
512
+ parent_folder = Files.parent_folder
513
+ parent_folder_combine = Files.parent_folder_combine
514
+ pickle_load_from_file = Files.pickle_load_from_file
515
+ pickle_save_to_file = Files.pickle_save_to_file
516
+
517
+ safe_file_name = Files.safe_file_name
518
+ save_bytes_as_file = Files.save_bytes_as_file
519
+ save_string_as_file = Files.save
520
+ sub_folders = Files.sub_folders
521
+
522
+ temp_file = Files.temp_file
523
+ temp_file_in_folder = Files.temp_file_in_folder
524
+ temp_filename = Files.temp_filename
525
+ temp_folder = Files.temp_folder
526
+ temp_folder_current = Files.temp_folder_current
527
+ temp_folder_with_temp_file = Files.temp_folder_with_temp_file
528
+
@@ -0,0 +1,113 @@
1
+ import builtins
2
+ import inspect
3
+ import textwrap
4
+ import types
5
+
6
+ from osbot_utils.utils.Files import parent_folder
7
+
8
+ def function_args(function):
9
+ if isinstance(function, types.FunctionType):
10
+ return inspect.getfullargspec(function)
11
+
12
+ def function_file(function):
13
+ if isinstance(function, types.FunctionType):
14
+ return inspect.getfile(function)
15
+
16
+ def function_folder(function):
17
+ if isinstance(function, types.FunctionType):
18
+ return parent_folder(inspect.getfile(function))
19
+
20
+ def function_module(function):
21
+ if isinstance(function, types.FunctionType):
22
+ return inspect.getmodule(function)
23
+
24
+ def function_name(function):
25
+ if isinstance(function, types.FunctionType):
26
+ return function.__name__
27
+
28
+ def function_source_code(function):
29
+ if isinstance(function, types.FunctionType):
30
+ source_code = inspect.getsource(function)
31
+ source_code = textwrap.dedent(source_code).strip()
32
+ return source_code
33
+ elif isinstance(function, str):
34
+ return function
35
+ return None
36
+
37
+ def get_line_number(function):
38
+ try:
39
+ code, line = inspect.getsourcelines(function)
40
+ return line
41
+ except Exception:
42
+ return None
43
+
44
+ def is_callable(target):
45
+ return callable(target)
46
+
47
+ def method_params(target):
48
+ params = {}
49
+ method_signature = signature(target)
50
+ if method_signature:
51
+ parameters = method_signature.get('parameters')
52
+ args = []
53
+ kwargs = {}
54
+ for name, data in parameters.items():
55
+ if 'default' in set(data):
56
+ kwargs[name] = data['default']
57
+ else:
58
+ args.append(name)
59
+ params['args' ] = args
60
+ params['kwargs'] = kwargs
61
+ return params
62
+
63
+
64
+ def module_file(module):
65
+ if isinstance(module, types.ModuleType):
66
+ return inspect.getfile(module)
67
+
68
+ def module_folder(module):
69
+ if isinstance(module, types.ModuleType):
70
+ return parent_folder(inspect.getfile(module))
71
+
72
+ def module_full_name(module):
73
+ if isinstance(module, types.ModuleType):
74
+ return module.__name__
75
+
76
+ def module_name(module):
77
+ if isinstance(module, types.ModuleType):
78
+ return module.__name__.split('.')[-1]
79
+
80
+ # todo Improve this method to return more usefull set of data (like an signature str,better view of the param.kind, annotations )
81
+ def signature(callable_obj):
82
+ if not isinstance(callable_obj, (types.FunctionType, types.MethodType)):
83
+ return {}
84
+
85
+ signature = inspect.signature(callable_obj)
86
+ parameters = {}
87
+ sig_dict = { 'name' : callable_obj.__name__,
88
+ 'parameters': parameters }
89
+
90
+ for name, param in signature.parameters.items():
91
+ value = {'kind' : str(param.kind)}
92
+ if param.default is not inspect.Parameter.empty:
93
+ value['default'] = param.default
94
+
95
+ if param.annotation is not inspect.Parameter.empty:
96
+ value['annotation'] = str(param.annotation)
97
+
98
+ sig_dict['parameters'][name] = value
99
+ return sig_dict
100
+
101
+ def python_file(target):
102
+ if isinstance(target, type) or type(target) in [types.ModuleType , types.MethodType,
103
+ types.FunctionType, types.TracebackType,
104
+ types.FrameType, types.CodeType]:
105
+ return inspect.getfile(target)
106
+
107
+ def type_file(target):
108
+ if isinstance(target, type):
109
+ return python_file(target)
110
+
111
+
112
+ function_line_number = get_line_number
113
+ method_line_number = get_line_number