abstract-utilities 0.2.2.442__py3-none-any.whl → 0.2.2.688__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.

Potentially problematic release.


This version of abstract-utilities might be problematic. Click here for more details.

Files changed (236) hide show
  1. abstract_utilities/__init__.py +25 -16
  2. abstract_utilities/circular_import_finder.py +222 -0
  3. abstract_utilities/circular_import_finder2.py +118 -0
  4. abstract_utilities/class_utils/__init__.py +7 -0
  5. abstract_utilities/class_utils/abstract_classes.py +144 -0
  6. abstract_utilities/class_utils/caller_utils.py +92 -0
  7. abstract_utilities/class_utils/class_utils.py +109 -0
  8. abstract_utilities/class_utils/function_utils.py +153 -0
  9. abstract_utilities/class_utils/global_utils.py +71 -0
  10. abstract_utilities/class_utils/imports/__init__.py +2 -0
  11. abstract_utilities/class_utils/imports/imports.py +2 -0
  12. abstract_utilities/class_utils/imports/utils.py +40 -0
  13. abstract_utilities/class_utils/module_utils.py +63 -0
  14. abstract_utilities/class_utils.py +0 -1
  15. abstract_utilities/directory_utils/__init__.py +2 -0
  16. abstract_utilities/directory_utils/directory_utils.py +94 -0
  17. abstract_utilities/directory_utils/imports/__init__.py +2 -0
  18. abstract_utilities/directory_utils/imports/imports.py +1 -0
  19. abstract_utilities/directory_utils/imports/module_imports.py +2 -0
  20. abstract_utilities/directory_utils/name_utils.py +43 -0
  21. abstract_utilities/directory_utils/size_utils.py +57 -0
  22. abstract_utilities/directory_utils/src/__init__.py +4 -0
  23. abstract_utilities/directory_utils/src/directory_utils.py +110 -0
  24. abstract_utilities/directory_utils/src/name_utils.py +43 -0
  25. abstract_utilities/directory_utils/src/size_utils.py +57 -0
  26. abstract_utilities/directory_utils/src/utils.py +116 -0
  27. abstract_utilities/directory_utils/utils.py +116 -0
  28. abstract_utilities/dynimport.py +1 -1
  29. abstract_utilities/env_utils/imports/imports.py +5 -3
  30. abstract_utilities/error_utils/__init__.py +2 -0
  31. abstract_utilities/error_utils/error_utils.py +25 -0
  32. abstract_utilities/error_utils/imports/__init__.py +2 -0
  33. abstract_utilities/error_utils/imports/imports.py +1 -0
  34. abstract_utilities/error_utils/imports/module_imports.py +1 -0
  35. abstract_utilities/file_utils/__init__.py +1 -2
  36. abstract_utilities/file_utils/file_utils/__init__.py +2 -0
  37. abstract_utilities/file_utils/file_utils/file_utils.py +3 -3
  38. abstract_utilities/file_utils/file_utils/find_collect.py +154 -0
  39. abstract_utilities/file_utils/file_utils/imports/__init__.py +3 -0
  40. abstract_utilities/file_utils/file_utils/imports/constants.py +39 -0
  41. abstract_utilities/file_utils/file_utils/imports/file_functions.py +10 -0
  42. abstract_utilities/file_utils/file_utils/imports/imports.py +39 -0
  43. abstract_utilities/file_utils/file_utils/imports/module_imports.py +14 -0
  44. abstract_utilities/file_utils/file_utils/imports.py +9 -0
  45. abstract_utilities/file_utils/file_utils/type_checks.py +92 -0
  46. abstract_utilities/file_utils/imports/__init__.py +1 -2
  47. abstract_utilities/file_utils/imports/classes.py +59 -55
  48. abstract_utilities/file_utils/imports/clean_imps.py +158 -0
  49. abstract_utilities/file_utils/imports/constants.py +84 -4
  50. abstract_utilities/file_utils/imports/file_functions.py +1 -1
  51. abstract_utilities/file_utils/imports/imports.py +40 -8
  52. abstract_utilities/file_utils/imports/module_imports.py +4 -5
  53. abstract_utilities/file_utils/module_imports.py +12 -0
  54. abstract_utilities/file_utils/src/__init__.py +7 -0
  55. abstract_utilities/file_utils/src/file_filters/__init__.py +1 -0
  56. abstract_utilities/file_utils/src/file_filters/ensure_utils.py +490 -0
  57. abstract_utilities/file_utils/src/file_filters/filter_params.py +150 -0
  58. abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
  59. abstract_utilities/file_utils/src/file_filters/predicate_utils.py +44 -0
  60. abstract_utilities/file_utils/src/file_filters.py +177 -0
  61. abstract_utilities/file_utils/src/file_reader.py +543 -0
  62. abstract_utilities/file_utils/src/file_utils.py +156 -0
  63. abstract_utilities/file_utils/src/filter_params.py +197 -0
  64. abstract_utilities/file_utils/src/find_collect.py +200 -0
  65. abstract_utilities/file_utils/src/find_content.py +210 -0
  66. abstract_utilities/file_utils/src/initFunctionsGen.py +293 -0
  67. abstract_utilities/file_utils/src/initFunctionsGens.py +280 -0
  68. abstract_utilities/file_utils/src/map_utils.py +29 -0
  69. abstract_utilities/file_utils/src/pdf_utils.py +300 -0
  70. abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
  71. abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
  72. abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
  73. abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
  74. abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
  75. abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
  76. abstract_utilities/file_utils/src/type_checks.py +91 -0
  77. abstract_utilities/file_utils (2)/__init__.py +2 -0
  78. abstract_utilities/file_utils (2)/imports/__init__.py +2 -0
  79. abstract_utilities/file_utils (2)/imports/constants.py +118 -0
  80. abstract_utilities/file_utils (2)/imports/imports/__init__.py +3 -0
  81. abstract_utilities/file_utils (2)/imports/imports/constants.py +119 -0
  82. abstract_utilities/file_utils (2)/imports/imports/imports.py +46 -0
  83. abstract_utilities/file_utils (2)/imports/imports/module_imports.py +8 -0
  84. abstract_utilities/file_utils (2)/imports/utils/__init__.py +3 -0
  85. abstract_utilities/file_utils (2)/imports/utils/classes.py +379 -0
  86. abstract_utilities/file_utils (2)/imports/utils/clean_imps.py +155 -0
  87. abstract_utilities/file_utils (2)/imports/utils/filter_utils.py +341 -0
  88. abstract_utilities/file_utils (2)/src/__init__.py +8 -0
  89. abstract_utilities/file_utils (2)/src/file_filters.py +155 -0
  90. abstract_utilities/file_utils (2)/src/file_reader.py +604 -0
  91. abstract_utilities/file_utils (2)/src/find_collect.py +258 -0
  92. abstract_utilities/file_utils (2)/src/initFunctionsGen.py +286 -0
  93. abstract_utilities/file_utils (2)/src/map_utils.py +28 -0
  94. abstract_utilities/file_utils (2)/src/pdf_utils.py +300 -0
  95. abstract_utilities/hash_utils/__init__.py +2 -0
  96. abstract_utilities/hash_utils/hash_utils.py +5 -0
  97. abstract_utilities/hash_utils/imports/__init__.py +2 -0
  98. abstract_utilities/hash_utils/imports/imports.py +1 -0
  99. abstract_utilities/hash_utils/imports/module_imports.py +0 -0
  100. abstract_utilities/history_utils/__init__.py +2 -0
  101. abstract_utilities/history_utils/history_utils.py +37 -0
  102. abstract_utilities/history_utils/imports/__init__.py +2 -0
  103. abstract_utilities/history_utils/imports/imports.py +1 -0
  104. abstract_utilities/history_utils/imports/module_imports.py +0 -0
  105. abstract_utilities/import_utils/__init__.py +2 -0
  106. abstract_utilities/import_utils/circular_import_finder.py +222 -0
  107. abstract_utilities/import_utils/circular_import_finder2.py +118 -0
  108. abstract_utilities/import_utils/imports/__init__.py +4 -0
  109. abstract_utilities/import_utils/imports/constants.py +2 -0
  110. abstract_utilities/import_utils/imports/imports.py +4 -0
  111. abstract_utilities/import_utils/imports/init_imports.py +3 -0
  112. abstract_utilities/import_utils/imports/module_imports.py +9 -0
  113. abstract_utilities/import_utils/imports/utils.py +30 -0
  114. abstract_utilities/import_utils/src/__init__.py +8 -0
  115. abstract_utilities/import_utils/src/clean_imports.py +278 -0
  116. abstract_utilities/import_utils/src/dot_utils.py +80 -0
  117. abstract_utilities/import_utils/src/extract_utils.py +46 -0
  118. abstract_utilities/import_utils/src/import_functions.py +110 -0
  119. abstract_utilities/import_utils/src/import_utils.py +349 -0
  120. abstract_utilities/import_utils/src/layze_import_utils/__init__.py +2 -0
  121. abstract_utilities/import_utils/src/layze_import_utils/lazy_utils.py +41 -0
  122. abstract_utilities/import_utils/src/layze_import_utils/nullProxy.py +37 -0
  123. abstract_utilities/import_utils/src/nullProxy.py +30 -0
  124. abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
  125. abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
  126. abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
  127. abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
  128. abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
  129. abstract_utilities/import_utils/src/package_utils.py +140 -0
  130. abstract_utilities/import_utils/src/package_utilss/__init__.py +139 -0
  131. abstract_utilities/import_utils/src/package_utilss/context_utils.py +27 -0
  132. abstract_utilities/import_utils/src/package_utilss/import_collectors.py +53 -0
  133. abstract_utilities/import_utils/src/package_utilss/path_utils.py +28 -0
  134. abstract_utilities/import_utils/src/package_utilss/safe_import.py +27 -0
  135. abstract_utilities/import_utils/src/pkg_utils.py +194 -0
  136. abstract_utilities/import_utils/src/sysroot_utils.py +112 -0
  137. abstract_utilities/imports.py +21 -0
  138. abstract_utilities/json_utils/__init__.py +2 -0
  139. abstract_utilities/json_utils/imports/__init__.py +2 -0
  140. abstract_utilities/json_utils/imports/imports.py +2 -0
  141. abstract_utilities/json_utils/imports/module_imports.py +5 -0
  142. abstract_utilities/json_utils/json_utils.py +777 -0
  143. abstract_utilities/list_utils/__init__.py +2 -0
  144. abstract_utilities/list_utils/imports/__init__.py +2 -0
  145. abstract_utilities/list_utils/imports/imports.py +1 -0
  146. abstract_utilities/list_utils/imports/module_imports.py +0 -0
  147. abstract_utilities/list_utils/list_utils.py +202 -0
  148. abstract_utilities/log_utils/__init__.py +5 -0
  149. abstract_utilities/log_utils/abstractLogManager.py +64 -0
  150. abstract_utilities/log_utils/call_response.py +68 -0
  151. abstract_utilities/log_utils/imports/__init__.py +2 -0
  152. abstract_utilities/log_utils/imports/imports.py +7 -0
  153. abstract_utilities/log_utils/imports/module_imports.py +2 -0
  154. abstract_utilities/log_utils/log_file.py +162 -0
  155. abstract_utilities/log_utils/logger_callable.py +49 -0
  156. abstract_utilities/math_utils/__init__.py +2 -0
  157. abstract_utilities/math_utils/imports/__init__.py +2 -0
  158. abstract_utilities/math_utils/imports/imports.py +2 -0
  159. abstract_utilities/math_utils/imports/module_imports.py +1 -0
  160. abstract_utilities/math_utils/math_utils.py +208 -0
  161. abstract_utilities/parse_utils/__init__.py +2 -0
  162. abstract_utilities/parse_utils/imports/__init__.py +3 -0
  163. abstract_utilities/parse_utils/imports/constants.py +10 -0
  164. abstract_utilities/parse_utils/imports/imports.py +2 -0
  165. abstract_utilities/parse_utils/imports/module_imports.py +4 -0
  166. abstract_utilities/parse_utils/parse_utils.py +539 -0
  167. abstract_utilities/path_utils/__init__.py +2 -0
  168. abstract_utilities/path_utils/imports/__init__.py +3 -0
  169. abstract_utilities/path_utils/imports/imports.py +1 -0
  170. abstract_utilities/path_utils/imports/module_imports.py +8 -0
  171. abstract_utilities/path_utils/path_utils.py +248 -0
  172. abstract_utilities/path_utils.py +95 -14
  173. abstract_utilities/read_write_utils/__init__.py +1 -0
  174. abstract_utilities/read_write_utils/imports/__init__.py +2 -0
  175. abstract_utilities/read_write_utils/imports/imports.py +2 -0
  176. abstract_utilities/read_write_utils/imports/module_imports.py +5 -0
  177. abstract_utilities/read_write_utils/read_write_utils.py +439 -0
  178. abstract_utilities/read_write_utils.py +218 -10
  179. abstract_utilities/robust_reader/imports/imports.py +0 -9
  180. abstract_utilities/robust_readers/import_utils/__init__.py +1 -0
  181. abstract_utilities/robust_readers/import_utils/clean_imports.py +175 -0
  182. abstract_utilities/robust_readers/initFuncGen.py +10 -2
  183. abstract_utilities/safe_utils/__init__.py +2 -0
  184. abstract_utilities/safe_utils/imports/__init__.py +3 -0
  185. abstract_utilities/safe_utils/imports/imports.py +2 -0
  186. abstract_utilities/safe_utils/imports/module_imports.py +2 -0
  187. abstract_utilities/safe_utils/safe_utils.py +166 -0
  188. abstract_utilities/ssh_utils/__init__.py +3 -1
  189. abstract_utilities/ssh_utils/classes.py +0 -1
  190. abstract_utilities/ssh_utils/cmd_utils.py +207 -0
  191. abstract_utilities/ssh_utils/imports/__init__.py +3 -0
  192. abstract_utilities/ssh_utils/imports/imports.py +5 -0
  193. abstract_utilities/ssh_utils/imports/module_imports.py +6 -0
  194. abstract_utilities/ssh_utils/imports/utils.py +189 -0
  195. abstract_utilities/ssh_utils/imports.py +1 -2
  196. abstract_utilities/ssh_utils/pexpect_utils.py +11 -18
  197. abstract_utilities/ssh_utils/type_checks.py +92 -0
  198. abstract_utilities/string_clean.py +40 -1
  199. abstract_utilities/string_utils/__init__.py +4 -0
  200. abstract_utilities/string_utils/clean_utils.py +28 -0
  201. abstract_utilities/string_utils/eat_utils.py +103 -0
  202. abstract_utilities/string_utils/imports/__init__.py +3 -0
  203. abstract_utilities/string_utils/imports/imports.py +2 -0
  204. abstract_utilities/string_utils/imports/module_imports.py +2 -0
  205. abstract_utilities/string_utils/imports/utils.py +81 -0
  206. abstract_utilities/string_utils/replace_utils.py +27 -0
  207. abstract_utilities/string_utils.py +51 -0
  208. abstract_utilities/thread_utils/__init__.py +2 -0
  209. abstract_utilities/thread_utils/imports/__init__.py +2 -0
  210. abstract_utilities/thread_utils/imports/imports.py +2 -0
  211. abstract_utilities/thread_utils/imports/module_imports.py +2 -0
  212. abstract_utilities/thread_utils/thread_utils.py +140 -0
  213. abstract_utilities/time_utils/__init__.py +2 -0
  214. abstract_utilities/time_utils/imports/__init__.py +2 -0
  215. abstract_utilities/time_utils/imports/imports.py +3 -0
  216. abstract_utilities/time_utils/imports/module_imports.py +1 -0
  217. abstract_utilities/time_utils/time_utils.py +392 -0
  218. abstract_utilities/type_utils/__init__.py +7 -0
  219. abstract_utilities/type_utils/alpha_utils.py +59 -0
  220. abstract_utilities/type_utils/get_type.py +120 -0
  221. abstract_utilities/type_utils/imports/__init__.py +3 -0
  222. abstract_utilities/type_utils/imports/constants.py +134 -0
  223. abstract_utilities/type_utils/imports/imports.py +4 -0
  224. abstract_utilities/type_utils/imports/module_imports.py +25 -0
  225. abstract_utilities/type_utils/is_type.py +455 -0
  226. abstract_utilities/type_utils/make_type.py +126 -0
  227. abstract_utilities/type_utils/mime_types.py +68 -0
  228. abstract_utilities/type_utils/num_utils.py +19 -0
  229. abstract_utilities/type_utils/type_utils.py +104 -0
  230. abstract_utilities/type_utils.py +25 -1
  231. {abstract_utilities-0.2.2.442.dist-info → abstract_utilities-0.2.2.688.dist-info}/METADATA +1 -1
  232. abstract_utilities-0.2.2.688.dist-info/RECORD +288 -0
  233. imports/__init__.py +36 -0
  234. abstract_utilities-0.2.2.442.dist-info/RECORD +0 -82
  235. {abstract_utilities-0.2.2.442.dist-info → abstract_utilities-0.2.2.688.dist-info}/WHEEL +0 -0
  236. {abstract_utilities-0.2.2.442.dist-info → abstract_utilities-0.2.2.688.dist-info}/top_level.txt +0 -0
@@ -12,12 +12,16 @@ Usage:
12
12
  from abstract_utilities.read_write_utils import *
13
13
  """
14
14
 
15
- import os
16
-
15
+ import os,shlex
16
+ from .string_clean import *
17
+ from .ssh_utils.utils import run_cmd,get_print_sudo_cmd,run_local_cmd,run_remote_cmd
18
+ from .abstract_classes import run_pruned_func
19
+ from .string_utils import get_from_kwargs
20
+ from .path_utils import get_all_files,is_file,is_dir,get_user_pass_host_key,is_exists
17
21
  _FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
18
22
  _CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
19
23
 
20
-
24
+
21
25
  # --- Helper utilities --------------------------------------------------------
22
26
  def string_in_keys(strings, kwargs):
23
27
  """Find a matching keyword in kwargs that contains any of the given substrings."""
@@ -26,26 +30,81 @@ def string_in_keys(strings, kwargs):
26
30
  if s.lower() in key.lower():
27
31
  return key
28
32
  return None
33
+ def make_dirs(path, exist_ok=True, **kwargs):
34
+ remote = get_user_pass_host_key(**kwargs)
35
+
36
+ if remote:
37
+ kwargs['cmd'] = f"mkdir -p {path}"
38
+
39
+ resp = run_pruned_func(run_cmd, **kwargs)
40
+
41
+ else:
42
+ os.makedirs(path, exist_ok=exist_ok)
43
+ return path
44
+ def make_path(path, home_dir=None, file=None, **kwargs):
45
+ if not path:
46
+ return None
47
+
48
+ basename = os.path.basename(path)
49
+ parts = [p for p in path.split('/') if p]
50
+
51
+ # Detect whether this is a file or a folder
52
+ is_file = file if file is not None else ('.' in basename)
53
+ pieces = parts[:-1] if is_file else parts
54
+
55
+ full_dir = home_dir or '/'
56
+ for piece in pieces:
57
+ full_dir = os.path.join(full_dir, piece)
58
+ make_dirs(full_dir, exist_ok=True, **kwargs)
59
+
60
+ if is_file:
61
+ full_dir = os.path.join(full_dir, basename)
29
62
 
63
+ return full_dir
64
+ def get_rel_path(src,src_rel,dst,**kwargs):
65
+ if src.startswith(src_rel):
66
+ nu_src = src[len(src_rel):]
67
+ nu_src= eatAll(nu_src,'/')
68
+ directory= eatOuter(dst,'/')
69
+ rel_path = os.path.join(dst,nu_src)
70
+ return rel_path
71
+ def make_relative_path(src,src_rel,dst,**kwargs):
30
72
 
31
- def get_path(paths):
73
+ if src.startswith(src_rel):
74
+ rel_path = get_rel_path(src,src_rel,dst)
75
+
76
+ path = make_path(rel_path,**kwargs)
77
+
78
+ return path
79
+
80
+ def path_join(*args):
81
+ path = None
82
+ for i,arg in enumerate(args):
83
+ if arg:
84
+ if i == 0:
85
+ path = arg
86
+ else:
87
+ path = os.path.join(path,arg)
88
+ return path
89
+
90
+ def get_path(paths,**kwargs):
32
91
  """Return the first valid path among given paths."""
33
92
  for path in paths:
34
93
  if isinstance(path, str):
35
- if os.path.isfile(path):
94
+ if is_file(path,**kwargs):
36
95
  return path
37
96
  dirname = os.path.dirname(path)
38
- if os.path.exists(dirname):
97
+ if is_exists(dirname,**kwargs):
39
98
  return path
40
99
  return None
41
100
 
42
101
 
43
- def break_down_find_existing(path):
102
+ def break_down_find_existing(path,**kwargs):
44
103
  """Return the first non-existent subpath within a path chain."""
45
104
  test_path = ''
46
105
  for part in path.split(os.sep):
47
106
  test_path = os.path.join(test_path, part)
48
- if not os.path.exists(test_path):
107
+ if not is_exists(test_path,**kwargs):
49
108
  return test_path if test_path else None
50
109
  return test_path
51
110
 
@@ -72,7 +131,73 @@ def check_read_write_params(*args, **kwargs):
72
131
  raise ValueError("Missing file_path argument.")
73
132
  return file_path, contents
74
133
 
134
+ def write_to_path(
135
+ file_path: str,
136
+ contents: str,
137
+ *,
138
+ user_at_host: str = None,
139
+ cwd: str | None = None,
140
+ password=None,
141
+ key=None,
142
+ env_path=None,
143
+ **kwargs
144
+ ) -> str:
145
+ """
146
+ Completely overwrite a file (locally or remotely).
147
+ Supports sudo and password-based remote execution.
148
+ """
149
+
150
+ # sanitize for shell safety
151
+ quoted_path = shlex.quote(file_path)
152
+ quoted_data = shlex.quote(str(contents))
153
+
154
+ # shell command that fully overwrites
155
+ # (no append, replaces contents entirely)
156
+ base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
75
157
 
158
+ # optional sudo password injection
159
+ full_cmd = get_print_sudo_cmd(
160
+ cmd=base_cmd,
161
+ password=password,
162
+ key=key,
163
+ env_path=env_path
164
+ )
165
+
166
+ # local or remote dispatch
167
+ if user_at_host:
168
+ return run_remote_cmd(
169
+ user_at_host=user_at_host,
170
+ cmd=full_cmd,
171
+ cwd=cwd,
172
+ password=password,
173
+ key=key,
174
+ env_path=env_path,
175
+ **kwargs
176
+ )
177
+ else:
178
+ return run_local_cmd(
179
+ cmd=full_cmd,
180
+ cwd=cwd,
181
+ password=password,
182
+ key=key,
183
+ env_path=env_path,
184
+ **kwargs
185
+ )
186
+ ### --- Core functionality -------------------------------------------------------
187
+ ##def write_to_file(*args, **kwargs):
188
+ ## """
189
+ ## Write contents to a file (create if missing).
190
+ ##
191
+ ## Returns the file_path written.
192
+ ## """
193
+ ## file_path, contents = check_read_write_params(*args, **kwargs)
194
+ ## if contents is None:
195
+ ## raise ValueError("Missing contents to write.")
196
+ ##
197
+ ## os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
198
+ ## with open(file_path, "w", encoding="utf-8") as f:
199
+ ## f.write(str(contents))
200
+ ## return file_path
76
201
  # --- Core functionality -------------------------------------------------------
77
202
  def write_to_file(*args, **kwargs):
78
203
  """
@@ -81,21 +206,86 @@ def write_to_file(*args, **kwargs):
81
206
  Returns the file_path written.
82
207
  """
83
208
  file_path, contents = check_read_write_params(*args, **kwargs)
209
+ values,kwargs = get_from_kwargs(['file_path','contents'],del_kwarg=True,**kwargs)
210
+ dirname = os.path.dirname(file_path)
211
+
84
212
  if contents is None:
85
213
  raise ValueError("Missing contents to write.")
214
+ user_at_host = kwargs.get("user_at_host")
215
+ if get_user_pass_host_key(**kwargs):
216
+ make_dirs(dirname, exist_ok=True,**kwargs)
217
+ kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
218
+ # sanitize for shell safety
219
+ quoted_path = shlex.quote(file_path)
220
+ quoted_data = shlex.quote(str(contents))
221
+ # shell command that fully overwrites
222
+ # (no append, replaces contents entirely)
223
+ kwargs["cmd"] = f'sh -c "echo {quoted_data} > {quoted_path}"'
224
+ if not kwargs.get('password') and not kwargs.get('key'):
225
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
226
+ result = run_pruned_func(run_cmd,**kwargs)
227
+ if 'file_path' in kwargs:
228
+ del kwargs['file_path']
229
+ if not is_file(file_path,**kwargs) or str(contents) != read_from_file(file_path,**kwargs):
230
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
231
+ result = run_pruned_func(run_cmd,**kwargs)
232
+ return result
86
233
 
87
- os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
234
+ make_dirs(dirname or ".", exist_ok=True)
88
235
  with open(file_path, "w", encoding="utf-8") as f:
89
236
  f.write(str(contents))
90
237
  return file_path
91
238
 
92
239
 
93
- def read_from_file(file_path):
240
+ def read_from_file(file_path,**kwargs):
241
+ if get_user_pass_host_key(**kwargs):
242
+ kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
243
+ basename = os.path.basename(file_path)
244
+ kwargs["cmd"] = f'cat {basename}'
245
+ return run_pruned_func(run_cmd,**kwargs)
94
246
  """Read text content from a file."""
95
247
  with open(file_path, "r", encoding="utf-8") as f:
96
248
  return f.read()
97
249
 
98
250
 
251
+ def copy_dirs(dirs, dst_root, src_rel=None, **kwargs):
252
+ """
253
+ Recursively copy directory structures (without files) from dirs → dst_root.
254
+ """
255
+ for src in dirs:
256
+ # build destination path preserving relative structure
257
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else dst_root
258
+ make_path(dst_path, **kwargs) # ensures directory exists
259
+
260
+
261
+
262
+ def copy_file(src, dst_root, src_rel=None, **kwargs):
263
+ """
264
+ Copy a single file to dst_root, preserving relative structure if src_rel provided.
265
+ Supports remote copy via read/write.
266
+ """
267
+ # derive destination file path
268
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else os.path.join(dst_root, os.path.basename(src))
269
+ make_path(dst_path, **kwargs)
270
+
271
+ if get_user_pass_host_key(**kwargs): # remote mode
272
+ contents = read_from_file(src, **kwargs)
273
+ write_to_file(contents=contents, file_path=dst_path, **kwargs)
274
+ else: # local
275
+ os.makedirs(os.path.dirname(dst_path), exist_ok=True)
276
+ shutil.copy2(src, dst_path)
277
+
278
+
279
+ return dst_path
280
+
281
+
282
+ def copy_files(files, dst_root, src_rel=None, **kwargs):
283
+ """
284
+ Copy a list of files to dst_root.
285
+ """
286
+ for src in files:
287
+ copy_file(src=src, dst_root=dst_root, src_rel=src_rel, **kwargs)
288
+
99
289
  def create_and_read_file(*args, **kwargs):
100
290
  """
101
291
  Create the file (if missing) and read contents from it.
@@ -133,3 +323,21 @@ def get_content_lines(*args, **kwargs):
133
323
  elif isinstance(contents, list):
134
324
  return contents
135
325
  return []
326
+ def collate_text_docs(directory=None):
327
+ return [read_from_file(item) for item in get_all_files(directory=directory)]
328
+ def get_content(*paths):
329
+ item_path = os.path.join(*paths)
330
+ if os.path.isfile(item_path):
331
+ try:
332
+ content = read_from_file(item_path)
333
+ return content
334
+ except:
335
+ pass
336
+ return None
337
+ def get_text_or_read(text=None,file_path=None):
338
+ text = text or ''
339
+ imports_js = {}
340
+ if not text and file_path and os.path.isfile(file_path):
341
+ text=read_from_file(file_path)
342
+ return text
343
+ ##
@@ -1,12 +1,3 @@
1
- import os,tempfile,shutil,logging,ezodf,fnmatch,pytesseract,pdfplumber
2
- import pandas as pd
3
- import geopandas as gpd
4
- from datetime import datetime
5
- from pathlib import Path
6
- from typing import *
7
- from werkzeug.utils import secure_filename
8
- from werkzeug.datastructures import FileStorage
9
- from pdf2image import convert_from_path # only used for OCR fallback
10
1
  from ...abstract_classes import SingletonMeta
11
2
  from ..pdf_utils import *
12
3
  from ...read_write_utils import *
@@ -4,3 +4,4 @@ from .import_utils import *
4
4
  from .sysroot_utils import *
5
5
  from .utils import *
6
6
  from .safe_import_utils import *
7
+ from .clean_imports import *
@@ -0,0 +1,175 @@
1
+ from ...read_write_utils import read_from_file,write_to_file
2
+ from ...string_clean import eatAll,eatElse,clean_line
3
+ from ...class_utils import get_caller_path
4
+ from ...list_utils import make_list
5
+ import os
6
+ import_tag = 'import '
7
+ from_tag = 'from '
8
+ def get_text_or_read(text=None,file_path=None):
9
+ text = text or ''
10
+ imports_js = {}
11
+ if not text and file_path and os.path.isfile(file_path):
12
+ text=read_from_file(file_path)
13
+ return text
14
+ def is_line_import(line):
15
+ if line and (line.startswith(from_tag) or line.startswith(import_tag)):
16
+ return True
17
+ return False
18
+ def is_line_group_import(line):
19
+ if line and (line.startswith(from_tag) and import_tag in line):
20
+ return True
21
+ return False
22
+ def get_import_pkg(line):
23
+ if is_line_group_import(line):
24
+ return clean_line(line.split(from_tag)[1].split(import_tag)[0])
25
+ def get_imports_from_import_pkg(line):
26
+ if is_line_group_import(line):
27
+ return get_cleaned_import_list(line,commaClean=True)
28
+
29
+ def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None):
30
+ import_pkg_js = import_pkg_js or {}
31
+ imports = clean_imports(imports)
32
+ if import_pkg not in import_pkg_js:
33
+ i = len(import_pkg_js["nulines"])
34
+ import_pkg_js[import_pkg]={"imports":imports,"line":i}
35
+ import_line = f"from {import_pkg} import "
36
+ if import_pkg == "import":
37
+ import_line = import_tag
38
+ import_pkg_js["nulines"].append(import_line)
39
+ else:
40
+ import_pkg_js[import_pkg]["imports"]+=imports
41
+ return import_pkg_js
42
+ def update_import_pkg_js(line,import_pkg_js=None):
43
+ import_pkg_js = import_pkg_js or {}
44
+ if is_line_group_import(line):
45
+ import_pkg = get_import_pkg(line)
46
+ imports = get_imports_from_import_pkg(line)
47
+ import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=import_pkg_js)
48
+ else:
49
+ if len(import_pkg_js["nulines"]) >0 and line == '' and is_line_import(import_pkg_js["nulines"][-1]):
50
+ pass
51
+ else:
52
+ import_pkg_js["nulines"].append(line)
53
+ return import_pkg_js
54
+ def is_from_line_group(line):
55
+ if line and line.startswith(from_tag) and import_tag in line and '(' in line:
56
+ import_spl = line.split(import_tag)[-1]
57
+ import_spl_clean = clean_line(line)
58
+ if not import_spl_clean.endswith(')'):
59
+ return True
60
+ return False
61
+ def clean_imports(imports,commaClean=True):
62
+ chars=["*"]
63
+ if not commaClean:
64
+ chars.append(',')
65
+ if isinstance(imports,str):
66
+ imports = imports.split(',')
67
+ return [eatElse(imp,chars=chars) for imp in imports if imp]
68
+ def get_cleaned_import_list(line,commaClean=True):
69
+ cleaned_import_list=[]
70
+ if import_tag in line:
71
+ imports = line.split(import_tag)[1]
72
+ cleaned_import_list+=clean_imports(imports,commaClean=commaClean)
73
+ return cleaned_import_list
74
+ def get_all_imports(text=None,file_path=None,import_pkg_js=None):
75
+ text = get_text_or_read(text=text,file_path=file_path)
76
+ lines = text.split('\n')
77
+ cleaned_import_list=[]
78
+ nu_lines = []
79
+ is_from_group = False
80
+ import_pkg_js = import_pkg_js or {}
81
+ if "nulines" not in import_pkg_js:
82
+ import_pkg_js["nulines"]=[]
83
+ if "file_path" not in import_pkg_js:
84
+ import_pkg_js["file_path"]=file_path
85
+ if "all_data" not in import_pkg_js:
86
+ import_pkg_js["all_data"]=[]
87
+ if file_path and file_path != import_pkg_js["file_path"]:
88
+ found=False
89
+ nu_data = {"file_path":import_pkg_js["file_path"],"nulines":import_pkg_js["nulines"]}
90
+ for i,data in enumerate(import_pkg_js["all_data"]):
91
+ if data.get('file_path') == import_pkg_js["file_path"]:
92
+ import_pkg_js["all_data"][i] = nu_data
93
+ found = True
94
+ break
95
+ if found == False:
96
+ import_pkg_js["all_data"].append(nu_data)
97
+ import_pkg_js["nulines"]=[]
98
+ import_pkg_js["file_path"]=file_path
99
+
100
+ for line in lines:
101
+ if line.startswith(import_tag) and ' from ' not in line:
102
+ cleaned_import_list = get_cleaned_import_list(line)
103
+ import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js)
104
+ else:
105
+ if is_from_group:
106
+ import_pkg=is_from_group
107
+ line = clean_line(line)
108
+ if line.endswith(')'):
109
+ is_from_group=False
110
+ line=line[:-1]
111
+ imports_from_import_pkg = clean_imports(line)
112
+ import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports_from_import_pkg,import_pkg_js=import_pkg_js)
113
+
114
+ else:
115
+ import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js)
116
+ if is_from_line_group(line) and is_from_group == False:
117
+ is_from_group=get_import_pkg(line)
118
+ return import_pkg_js
119
+ def clean_all_imports(text=None,file_path=None,import_pkg_js=None):
120
+ if not import_pkg_js:
121
+ import_pkg_js = get_all_imports(text=text,file_path=file_path)
122
+ nu_lines = import_pkg_js["nulines"]
123
+ for pkg,values in import_pkg_js.items():
124
+ comments = []
125
+ if pkg not in ["nulines","file_path","all_data"]:
126
+ line = values.get('line')
127
+ imports = values.get('imports')
128
+ for i,imp in enumerate(imports):
129
+ if '#' in imp:
130
+ imp_spl = imp.split('#')
131
+ comments.append(imp_spl[-1])
132
+ imports[i] = clean_line(imp_spl[0])
133
+ imports = list(set(imports))
134
+ if '*' in imports:
135
+ imports="*"
136
+ else:
137
+ imports=','.join(imports)
138
+ if comments:
139
+ comments=','.join(comments)
140
+ imports+=f" #{comments}"
141
+ import_pkg_js[pkg]["imports"]=imports
142
+ nu_lines[line] += imports
143
+ import_pkg_js["nulines"]=nu_lines
144
+ return import_pkg_js
145
+
146
+ def get_all_real_imps(file):
147
+ contents = read_from_file(file)
148
+ lines = contents.split('\n')
149
+ for line in lines:
150
+ if line.startswith('from '):
151
+ from_line = line.split('from ')[-1]
152
+ dot_fro = ""
153
+ dirname = file
154
+ for char in from_line:
155
+ if char != '.':
156
+ line = f"from {dot_fro}{eatAll(from_line,'.')}"
157
+ if line in all_imps:
158
+ line = ""
159
+ break
160
+ if dot_fro == "":
161
+ dot_fro = ""
162
+ dirname = os.path.dirname(dirname)
163
+ dirbase = os.path.basename(dirname)
164
+ dot_fro = f"{dirbase}.{dot_fro}"
165
+ if line:
166
+ all_imps.append(line)
167
+
168
+ return '\n'.join(all_imps)
169
+ def save_cleaned_imports(text=None,file_path=None,write=False,import_pkg_js=None):
170
+ import_pkg_js=get_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
171
+ import_pkg_js = clean_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
172
+ contents = '\n'.join(import_pkg_js["nulines"])
173
+ if file_path and write:
174
+ write_to_file(contents=contents,file_path=file_path)
175
+ return contents
@@ -6,9 +6,17 @@ def call_for_all_tabs(root = None,tab_control=True):
6
6
  root = root or get_caller_dir()
7
7
  get_for_all_tabs(root,tab_control=tab_control)
8
8
 
9
- def clean_imports():
9
+ def get_clean_list(*args):
10
+ objs = []
11
+ for arg in args:
12
+ objs+= make_list(arg)
13
+ return list(set(objs))
14
+ def clean_imports(*args,**kwargs):
15
+ for pkg,imps in kwargs.items():
16
+ f"from {pkg} import make_list(imps)"
17
+
10
18
  alls = str(list(set("""os,re,subprocess,sys,re,traceback,pydot, enum, inspect, sys, traceback, threading,json,traceback,logging,requests""".replace('\n','').replace(' ','').replace('\t','').split(','))))[1:-1].replace('"','').replace("'",'')
11
- input(alls)
19
+ return
12
20
  def isTab(item):
13
21
  item_lower = item.lower()
14
22
  for key in ['console','tab']:
@@ -0,0 +1,2 @@
1
+ from .imports import *
2
+ from .safe_utils import *
@@ -0,0 +1,3 @@
1
+ from .imports import *
2
+
3
+ from .module_imports import *
@@ -0,0 +1,2 @@
1
+ from ...imports import *
2
+ from typing import *
@@ -0,0 +1,2 @@
1
+ from ...type_utils import is_number
2
+ from ...class_utils import get_caller_dir
@@ -0,0 +1,166 @@
1
+ """
2
+ abstract_safeops.py
3
+ -------------------
4
+ Utility functions for safely splitting, slicing, and retrieving elements from iterable or string objects
5
+ without raising exceptions on invalid input or out-of-range indices.
6
+
7
+ Designed for compatibility with the abstract_ ecosystem (e.g. abstract_utilities, abstract_math, etc.).
8
+ """
9
+
10
+ from .imports import *
11
+ _BASE_DIR = get_caller_dir()
12
+
13
+ class PathOutsideBase(Exception):
14
+ pass
15
+
16
+ def safe_join_base(base: Union[str, Path], *parts: Union[str, Path], must_exist: bool = False) -> Path:
17
+ """
18
+ Join base with parts, normalize, and ensure the result lives under base.
19
+ Prevents '../' traversal and ignores leading slashes in parts.
20
+ """
21
+ base = Path(base).resolve(strict=True)
22
+ # Disallow absolute/drive-anchored parts by stripping their anchors before joining.
23
+ cleaned = []
24
+ for p in parts:
25
+ p = Path(p)
26
+ # Convert absolute to relative (security: we won't allow escaping base anyway)
27
+ if p.is_absolute():
28
+ p = Path(*p.parts[1:]) # drop leading '/'
29
+ cleaned.append(p)
30
+
31
+ # Build and resolve (non-strict so missing files are allowed unless must_exist=True)
32
+ target = (base.joinpath(*cleaned)).resolve(strict=False)
33
+
34
+ # Containment check (works even if target doesn't exist)
35
+ try:
36
+ target.relative_to(base)
37
+ except ValueError:
38
+ raise PathOutsideBase(f"{target} escapes base {base}")
39
+
40
+ if must_exist and not target.exists():
41
+ raise FileNotFoundError(target)
42
+
43
+ return target
44
+ def safe_split(
45
+ string: Any,
46
+ char: Any,
47
+ i: Optional[int] = None,
48
+ default: Union[bool, Any] = False
49
+ ) -> Union[str, List[str], Any, None]:
50
+ """
51
+ Safely split a string by a character and optionally return index i.
52
+
53
+ Args:
54
+ string: Input string (or any object convertible to string).
55
+ char: Delimiter to split on.
56
+ i: Optional index to retrieve from the split result.
57
+ default: If True, return the original string on error.
58
+ If any other value, return that instead of raising.
59
+
60
+ Returns:
61
+ The split list, or the element at index i, or default behavior on error.
62
+ """
63
+ if string is None or char is None:
64
+ return string
65
+
66
+ s, c = str(string), str(char)
67
+ if c not in s:
68
+ return string
69
+
70
+ parts = s.split(c)
71
+
72
+ if i is None:
73
+ return parts
74
+
75
+ if is_number(i):
76
+ idx = int(i)
77
+ if 0 <= idx < len(parts):
78
+ return parts[idx]
79
+
80
+ if default:
81
+ return string if default is True else default
82
+
83
+ return None
84
+
85
+
86
+ def safe_slice(
87
+ obj: Any,
88
+ i: Optional[int] = None,
89
+ k: Optional[int] = None,
90
+ default: Union[bool, Any] = False
91
+ ) -> Any:
92
+ """
93
+ Safely slice an iterable object or string, with fallback behavior on invalid indices.
94
+
95
+ Args:
96
+ obj: Iterable or string-like object.
97
+ i: Start index (can be negative).
98
+ k: End index (can be negative).
99
+ default: If True, returns the original object on error.
100
+ If any other value, return that value on error.
101
+
102
+ Returns:
103
+ The sliced object, or default behavior on error.
104
+ """
105
+ # Null or invalid base case
106
+ if obj is None or isinstance(obj, bool):
107
+ return obj if default is True else default if default else None
108
+
109
+ # Non-iterable guard
110
+ if not hasattr(obj, "__getitem__"):
111
+ return obj if default is True else default if default else None
112
+
113
+ obj_len = len(obj)
114
+
115
+ # Normalize negative indices
116
+ if isinstance(i, int) and i < 0:
117
+ i = obj_len + i
118
+ if isinstance(k, int) and k < 0:
119
+ k = obj_len + k
120
+
121
+ # Bound indices
122
+ if i is not None:
123
+ i = max(0, min(i, obj_len))
124
+ if k is not None:
125
+ k = max(0, min(k, obj_len))
126
+
127
+ try:
128
+ return obj[i:k]
129
+ except Exception:
130
+ return obj if default is True else default if default else None
131
+
132
+ def safe_join(*paths):
133
+ paths = list(paths)
134
+ paths = [path for path in paths if path]
135
+ return os.path.join(*paths)
136
+ def safe_get(
137
+ obj: Any,
138
+ key: Union[int, str, None] = None,
139
+ default: Union[bool, Any] = False
140
+ ) -> Any:
141
+ """
142
+ Generalized safe getter for both indexable and mapping types.
143
+
144
+ Args:
145
+ obj: The object to access (list, dict, string, etc.).
146
+ key: Index or key to retrieve.
147
+ default: Fallback value or True for "return obj".
148
+
149
+ Returns:
150
+ Retrieved element, or default value on failure.
151
+ """
152
+ if obj is None or key is None:
153
+ return obj if default is True else default if default else None
154
+
155
+ try:
156
+ if isinstance(obj, dict):
157
+ return obj.get(key, obj if default is True else default if default else None)
158
+ return obj[key]
159
+ except Exception:
160
+ return obj if default is True else default if default else None
161
+ def get_slash(path):
162
+ if '/' in path:
163
+ return '/'
164
+ else:
165
+ return '//'
166
+ join_path=safe_join