abstract-utilities 0.2.2.467__py3-none-any.whl → 0.2.2.513__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 (174) hide show
  1. abstract_utilities/__init__.py +6 -10
  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 +74 -0
  6. abstract_utilities/class_utils/caller_utils.py +35 -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 +56 -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 +4 -0
  16. abstract_utilities/directory_utils/directory_utils.py +94 -0
  17. abstract_utilities/directory_utils/name_utils.py +43 -0
  18. abstract_utilities/directory_utils/size_utils.py +57 -0
  19. abstract_utilities/directory_utils/utils.py +116 -0
  20. abstract_utilities/env_utils/imports/imports.py +5 -3
  21. abstract_utilities/error_utils/__init__.py +2 -0
  22. abstract_utilities/error_utils/error_utils.py +25 -0
  23. abstract_utilities/error_utils/imports/__init__.py +2 -0
  24. abstract_utilities/error_utils/imports/imports.py +1 -0
  25. abstract_utilities/error_utils/imports/module_imports.py +1 -0
  26. abstract_utilities/file_utils/__init__.py +1 -2
  27. abstract_utilities/file_utils/file_utils/imports/__init__.py +0 -2
  28. abstract_utilities/file_utils/file_utils/imports/module_imports.py +2 -1
  29. abstract_utilities/file_utils/file_utils/type_checks.py +34 -24
  30. abstract_utilities/file_utils/imports/__init__.py +0 -1
  31. abstract_utilities/file_utils/imports/clean_imps.py +158 -0
  32. abstract_utilities/file_utils/imports/constants.py +6 -0
  33. abstract_utilities/file_utils/imports/file_functions.py +1 -1
  34. abstract_utilities/file_utils/imports/imports.py +20 -10
  35. abstract_utilities/file_utils/imports/module_imports.py +2 -7
  36. abstract_utilities/file_utils/module_imports.py +12 -0
  37. abstract_utilities/file_utils/src/__init__.py +9 -0
  38. abstract_utilities/file_utils/src/file_filters.py +110 -0
  39. abstract_utilities/file_utils/src/file_reader.py +607 -0
  40. abstract_utilities/file_utils/src/file_utils.py +279 -0
  41. abstract_utilities/file_utils/src/filter_params.py +155 -0
  42. abstract_utilities/file_utils/src/find_collect.py +270 -0
  43. abstract_utilities/file_utils/src/initFunctionsGen.py +286 -0
  44. abstract_utilities/file_utils/src/map_utils.py +29 -0
  45. abstract_utilities/file_utils/src/pdf_utils.py +300 -0
  46. abstract_utilities/file_utils/src/type_checks.py +91 -0
  47. abstract_utilities/hash_utils/__init__.py +2 -0
  48. abstract_utilities/hash_utils/hash_utils.py +5 -0
  49. abstract_utilities/hash_utils/imports/__init__.py +2 -0
  50. abstract_utilities/hash_utils/imports/imports.py +1 -0
  51. abstract_utilities/hash_utils/imports/module_imports.py +0 -0
  52. abstract_utilities/history_utils/__init__.py +2 -0
  53. abstract_utilities/history_utils/history_utils.py +37 -0
  54. abstract_utilities/history_utils/imports/__init__.py +2 -0
  55. abstract_utilities/history_utils/imports/imports.py +1 -0
  56. abstract_utilities/history_utils/imports/module_imports.py +0 -0
  57. abstract_utilities/import_utils/__init__.py +2 -0
  58. abstract_utilities/import_utils/imports/__init__.py +4 -0
  59. abstract_utilities/import_utils/imports/constants.py +2 -0
  60. abstract_utilities/import_utils/imports/imports.py +4 -0
  61. abstract_utilities/import_utils/imports/module_imports.py +6 -0
  62. abstract_utilities/import_utils/imports/utils.py +30 -0
  63. abstract_utilities/import_utils/src/__init__.py +7 -0
  64. abstract_utilities/import_utils/src/clean_imports.py +147 -0
  65. abstract_utilities/import_utils/src/dot_utils.py +69 -0
  66. abstract_utilities/import_utils/src/extract_utils.py +42 -0
  67. abstract_utilities/import_utils/src/import_functions.py +46 -0
  68. abstract_utilities/import_utils/src/import_utils.py +299 -0
  69. abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
  70. abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
  71. abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
  72. abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
  73. abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
  74. abstract_utilities/import_utils/src/package_utils.py +140 -0
  75. abstract_utilities/import_utils/src/package_utilss/__init__.py +139 -0
  76. abstract_utilities/import_utils/src/package_utilss/context_utils.py +27 -0
  77. abstract_utilities/import_utils/src/package_utilss/import_collectors.py +53 -0
  78. abstract_utilities/import_utils/src/package_utilss/path_utils.py +28 -0
  79. abstract_utilities/import_utils/src/package_utilss/safe_import.py +27 -0
  80. abstract_utilities/import_utils/src/pkg_utils.py +140 -0
  81. abstract_utilities/import_utils/src/sysroot_utils.py +57 -0
  82. abstract_utilities/imports.py +18 -0
  83. abstract_utilities/json_utils/__init__.py +2 -0
  84. abstract_utilities/json_utils/imports/__init__.py +2 -0
  85. abstract_utilities/json_utils/imports/imports.py +2 -0
  86. abstract_utilities/json_utils/imports/module_imports.py +5 -0
  87. abstract_utilities/json_utils/json_utils.py +743 -0
  88. abstract_utilities/list_utils/__init__.py +2 -0
  89. abstract_utilities/list_utils/imports/__init__.py +2 -0
  90. abstract_utilities/list_utils/imports/imports.py +1 -0
  91. abstract_utilities/list_utils/imports/module_imports.py +0 -0
  92. abstract_utilities/list_utils/list_utils.py +199 -0
  93. abstract_utilities/log_utils/__init__.py +5 -0
  94. abstract_utilities/log_utils/abstractLogManager.py +64 -0
  95. abstract_utilities/log_utils/call_response.py +68 -0
  96. abstract_utilities/log_utils/imports/__init__.py +2 -0
  97. abstract_utilities/log_utils/imports/imports.py +7 -0
  98. abstract_utilities/log_utils/imports/module_imports.py +2 -0
  99. abstract_utilities/log_utils/log_file.py +58 -0
  100. abstract_utilities/log_utils/logger_callable.py +49 -0
  101. abstract_utilities/math_utils/__init__.py +2 -0
  102. abstract_utilities/math_utils/imports/__init__.py +2 -0
  103. abstract_utilities/math_utils/imports/imports.py +2 -0
  104. abstract_utilities/math_utils/imports/module_imports.py +1 -0
  105. abstract_utilities/math_utils/math_utils.py +208 -0
  106. abstract_utilities/parse_utils/__init__.py +2 -0
  107. abstract_utilities/parse_utils/imports/__init__.py +3 -0
  108. abstract_utilities/parse_utils/imports/constants.py +10 -0
  109. abstract_utilities/parse_utils/imports/imports.py +2 -0
  110. abstract_utilities/parse_utils/imports/module_imports.py +4 -0
  111. abstract_utilities/parse_utils/parse_utils.py +516 -0
  112. abstract_utilities/path_utils/__init__.py +2 -0
  113. abstract_utilities/path_utils/imports/__init__.py +3 -0
  114. abstract_utilities/path_utils/imports/imports.py +1 -0
  115. abstract_utilities/path_utils/imports/module_imports.py +8 -0
  116. abstract_utilities/path_utils/path_utils.py +251 -0
  117. abstract_utilities/path_utils.py +95 -14
  118. abstract_utilities/read_write_utils/__init__.py +1 -0
  119. abstract_utilities/read_write_utils/imports/__init__.py +2 -0
  120. abstract_utilities/read_write_utils/imports/imports.py +2 -0
  121. abstract_utilities/read_write_utils/imports/module_imports.py +5 -0
  122. abstract_utilities/read_write_utils/read_write_utils.py +338 -0
  123. abstract_utilities/read_write_utils.py +142 -20
  124. abstract_utilities/robust_reader/imports/imports.py +0 -9
  125. abstract_utilities/robust_readers/import_utils/__init__.py +1 -0
  126. abstract_utilities/robust_readers/import_utils/clean_imports.py +175 -0
  127. abstract_utilities/safe_utils/__init__.py +2 -0
  128. abstract_utilities/safe_utils/imports/__init__.py +3 -0
  129. abstract_utilities/safe_utils/imports/imports.py +2 -0
  130. abstract_utilities/safe_utils/imports/module_imports.py +2 -0
  131. abstract_utilities/safe_utils/safe_utils.py +136 -0
  132. abstract_utilities/ssh_utils/__init__.py +3 -1
  133. abstract_utilities/ssh_utils/classes.py +0 -1
  134. abstract_utilities/ssh_utils/cmd_utils.py +207 -0
  135. abstract_utilities/ssh_utils/imports/__init__.py +3 -0
  136. abstract_utilities/ssh_utils/imports/imports.py +5 -0
  137. abstract_utilities/ssh_utils/imports/module_imports.py +6 -0
  138. abstract_utilities/ssh_utils/imports/utils.py +189 -0
  139. abstract_utilities/ssh_utils/pexpect_utils.py +11 -18
  140. abstract_utilities/ssh_utils/type_checks.py +92 -0
  141. abstract_utilities/string_clean.py +40 -1
  142. abstract_utilities/string_utils/__init__.py +4 -0
  143. abstract_utilities/string_utils/clean_utils.py +28 -0
  144. abstract_utilities/string_utils/eat_utils.py +103 -0
  145. abstract_utilities/string_utils/imports/__init__.py +3 -0
  146. abstract_utilities/string_utils/imports/imports.py +2 -0
  147. abstract_utilities/string_utils/imports/module_imports.py +2 -0
  148. abstract_utilities/string_utils/imports/utils.py +81 -0
  149. abstract_utilities/string_utils/replace_utils.py +27 -0
  150. abstract_utilities/string_utils.py +39 -0
  151. abstract_utilities/thread_utils/__init__.py +2 -0
  152. abstract_utilities/thread_utils/imports/__init__.py +2 -0
  153. abstract_utilities/thread_utils/imports/imports.py +2 -0
  154. abstract_utilities/thread_utils/imports/module_imports.py +2 -0
  155. abstract_utilities/thread_utils/thread_utils.py +140 -0
  156. abstract_utilities/time_utils/__init__.py +2 -0
  157. abstract_utilities/time_utils/imports/__init__.py +2 -0
  158. abstract_utilities/time_utils/imports/imports.py +3 -0
  159. abstract_utilities/time_utils/imports/module_imports.py +1 -0
  160. abstract_utilities/time_utils/time_utils.py +392 -0
  161. abstract_utilities/type_utils/__init__.py +3 -0
  162. abstract_utilities/type_utils/alpha_utils.py +59 -0
  163. abstract_utilities/type_utils/imports/__init__.py +2 -0
  164. abstract_utilities/type_utils/imports/imports.py +4 -0
  165. abstract_utilities/type_utils/imports/module_imports.py +1 -0
  166. abstract_utilities/type_utils/num_utils.py +19 -0
  167. abstract_utilities/type_utils/type_utils.py +981 -0
  168. abstract_utilities/type_utils.py +25 -1
  169. {abstract_utilities-0.2.2.467.dist-info → abstract_utilities-0.2.2.513.dist-info}/METADATA +1 -1
  170. abstract_utilities-0.2.2.513.dist-info/RECORD +237 -0
  171. imports/__init__.py +36 -0
  172. abstract_utilities-0.2.2.467.dist-info/RECORD +0 -90
  173. {abstract_utilities-0.2.2.467.dist-info → abstract_utilities-0.2.2.513.dist-info}/WHEEL +0 -0
  174. {abstract_utilities-0.2.2.467.dist-info → abstract_utilities-0.2.2.513.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,338 @@
1
+ """
2
+ read_write_utils.py
3
+ -------------------
4
+ Unified read/write utility for safe file operations.
5
+ Supports:
6
+ - Writing content to a file
7
+ - Reading content from a file
8
+ - Creating and reading if missing
9
+ - Detecting file/content params via positional args or kwargs
10
+
11
+ Usage:
12
+ from abstract_utilities.read_write_utils import *
13
+ """
14
+
15
+ from .imports import *
16
+ _FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
17
+ _CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
18
+
19
+
20
+ # --- Helper utilities --------------------------------------------------------
21
+ def string_in_keys(strings, kwargs):
22
+ """Find a matching keyword in kwargs that contains any of the given substrings."""
23
+ for key in kwargs:
24
+ for s in strings:
25
+ if s.lower() in key.lower():
26
+ return key
27
+ return None
28
+ def make_dirs(path, exist_ok=True, **kwargs):
29
+ remote = get_user_pass_host_key(**kwargs)
30
+
31
+ if remote:
32
+ kwargs['cmd'] = f"mkdir -p {path}"
33
+
34
+ resp = run_pruned_func(run_cmd, **kwargs)
35
+
36
+ else:
37
+ os.makedirs(path, exist_ok=exist_ok)
38
+ return path
39
+ def make_path(path, home_dir=None, file=None, **kwargs):
40
+ if not path:
41
+ return None
42
+
43
+ basename = os.path.basename(path)
44
+ parts = [p for p in path.split('/') if p]
45
+
46
+ # Detect whether this is a file or a folder
47
+ is_file = file if file is not None else ('.' in basename)
48
+ pieces = parts[:-1] if is_file else parts
49
+
50
+ full_dir = home_dir or '/'
51
+ for piece in pieces:
52
+ full_dir = os.path.join(full_dir, piece)
53
+ make_dirs(full_dir, exist_ok=True, **kwargs)
54
+
55
+ if is_file:
56
+ full_dir = os.path.join(full_dir, basename)
57
+
58
+ return full_dir
59
+ def get_rel_path(src,src_rel,dst,**kwargs):
60
+ if src.startswith(src_rel):
61
+ nu_src = src[len(src_rel):]
62
+ nu_src= eatAll(nu_src,'/')
63
+ directory= eatOuter(dst,'/')
64
+ rel_path = os.path.join(dst,nu_src)
65
+ return rel_path
66
+ def make_relative_path(src,src_rel,dst,**kwargs):
67
+
68
+ if src.startswith(src_rel):
69
+ rel_path = get_rel_path(src,src_rel,dst)
70
+
71
+ path = make_path(rel_path,**kwargs)
72
+
73
+ return path
74
+
75
+ def path_join(*args):
76
+ path = None
77
+ for i,arg in enumerate(args):
78
+ if arg:
79
+ if i == 0:
80
+ path = arg
81
+ else:
82
+ path = os.path.join(path,arg)
83
+ return path
84
+
85
+ def get_path(paths,**kwargs):
86
+ """Return the first valid path among given paths."""
87
+ for path in paths:
88
+ if isinstance(path, str):
89
+ if is_file(path,**kwargs):
90
+ return path
91
+ dirname = os.path.dirname(path)
92
+ if is_exists(dirname,**kwargs):
93
+ return path
94
+ return None
95
+
96
+
97
+ def break_down_find_existing(path,**kwargs):
98
+ """Return the first non-existent subpath within a path chain."""
99
+ test_path = ''
100
+ for part in path.split(os.sep):
101
+ test_path = os.path.join(test_path, part)
102
+ if not is_exists(test_path,**kwargs):
103
+ return test_path if test_path else None
104
+ return test_path
105
+
106
+
107
+ # --- Parameter parsing --------------------------------------------------------
108
+ def check_read_write_params(*args, **kwargs):
109
+ """
110
+ Determine file_path and contents from arguments.
111
+ Returns a tuple: (file_path, contents)
112
+ """
113
+ file_key = string_in_keys(_FILE_PATH_KEYS, kwargs)
114
+ content_key = string_in_keys(_CONTENTS_KEYS, kwargs)
115
+
116
+ file_path = kwargs.get(file_key) if file_key else None
117
+ contents = kwargs.get(content_key) if content_key else None
118
+
119
+ # Handle positional args (fallback)
120
+ if file_path is None and len(args) > 0:
121
+ file_path = args[0]
122
+ if contents is None and len(args) > 1:
123
+ contents = args[1]
124
+
125
+ if file_path is None:
126
+ raise ValueError("Missing file_path argument.")
127
+ return file_path, contents
128
+
129
+ def write_to_path(
130
+ file_path: str,
131
+ contents: str,
132
+ *,
133
+ user_at_host: str = None,
134
+ cwd: str | None = None,
135
+ password=None,
136
+ key=None,
137
+ env_path=None,
138
+ **kwargs
139
+ ) -> str:
140
+ """
141
+ Completely overwrite a file (locally or remotely).
142
+ Supports sudo and password-based remote execution.
143
+ """
144
+
145
+ # sanitize for shell safety
146
+ quoted_path = shlex.quote(file_path)
147
+ quoted_data = shlex.quote(str(contents))
148
+
149
+ # shell command that fully overwrites
150
+ # (no append, replaces contents entirely)
151
+ base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
152
+
153
+ # optional sudo password injection
154
+ full_cmd = get_print_sudo_cmd(
155
+ cmd=base_cmd,
156
+ password=password,
157
+ key=key,
158
+ env_path=env_path
159
+ )
160
+
161
+ # local or remote dispatch
162
+ if user_at_host:
163
+ return run_remote_cmd(
164
+ user_at_host=user_at_host,
165
+ cmd=full_cmd,
166
+ cwd=cwd,
167
+ password=password,
168
+ key=key,
169
+ env_path=env_path,
170
+ **kwargs
171
+ )
172
+ else:
173
+ return run_local_cmd(
174
+ cmd=full_cmd,
175
+ cwd=cwd,
176
+ password=password,
177
+ key=key,
178
+ env_path=env_path,
179
+ **kwargs
180
+ )
181
+ ### --- Core functionality -------------------------------------------------------
182
+ ##def write_to_file(*args, **kwargs):
183
+ ## """
184
+ ## Write contents to a file (create if missing).
185
+ ##
186
+ ## Returns the file_path written.
187
+ ## """
188
+ ## file_path, contents = check_read_write_params(*args, **kwargs)
189
+ ## if contents is None:
190
+ ## raise ValueError("Missing contents to write.")
191
+ ##
192
+ ## os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
193
+ ## with open(file_path, "w", encoding="utf-8") as f:
194
+ ## f.write(str(contents))
195
+ ## return file_path
196
+ # --- Core functionality -------------------------------------------------------
197
+ def write_to_file(*args, **kwargs):
198
+ """
199
+ Write contents to a file (create if missing).
200
+
201
+ Returns the file_path written.
202
+ """
203
+ file_path, contents = check_read_write_params(*args, **kwargs)
204
+ values,kwargs = get_from_kwargs(['file_path','contents'],del_kwarg=True,**kwargs)
205
+ dirname = os.path.dirname(file_path)
206
+
207
+ if contents is None:
208
+ raise ValueError("Missing contents to write.")
209
+ user_at_host = kwargs.get("user_at_host")
210
+ if get_user_pass_host_key(**kwargs):
211
+ make_dirs(dirname, exist_ok=True,**kwargs)
212
+ kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
213
+ # sanitize for shell safety
214
+ quoted_path = shlex.quote(file_path)
215
+ quoted_data = shlex.quote(str(contents))
216
+ # shell command that fully overwrites
217
+ # (no append, replaces contents entirely)
218
+ kwargs["cmd"] = f'sh -c "echo {quoted_data} > {quoted_path}"'
219
+ if not kwargs.get('password') and not kwargs.get('key'):
220
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
221
+ result = run_pruned_func(run_cmd,**kwargs)
222
+ if 'file_path' in kwargs:
223
+ del kwargs['file_path']
224
+ if not is_file(file_path,**kwargs) or str(contents) != read_from_file(file_path,**kwargs):
225
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
226
+ result = run_pruned_func(run_cmd,**kwargs)
227
+ return result
228
+
229
+ make_dirs(dirname or ".", exist_ok=True)
230
+ with open(file_path, "w", encoding="utf-8") as f:
231
+ f.write(str(contents))
232
+ return file_path
233
+
234
+
235
+ def read_from_file(file_path,**kwargs):
236
+ if get_user_pass_host_key(**kwargs):
237
+ kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
238
+ basename = os.path.basename(file_path)
239
+ kwargs["cmd"] = f'cat {basename}'
240
+ return run_pruned_func(run_cmd,**kwargs)
241
+ """Read text content from a file."""
242
+ with open(file_path, "r", encoding="utf-8") as f:
243
+ return f.read()
244
+
245
+
246
+ def copy_dirs(dirs, dst_root, src_rel=None, **kwargs):
247
+ """
248
+ Recursively copy directory structures (without files) from dirs → dst_root.
249
+ """
250
+ for src in dirs:
251
+ # build destination path preserving relative structure
252
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else dst_root
253
+ make_path(dst_path, **kwargs) # ensures directory exists
254
+
255
+
256
+
257
+ def copy_file(src, dst_root, src_rel=None, **kwargs):
258
+ """
259
+ Copy a single file to dst_root, preserving relative structure if src_rel provided.
260
+ Supports remote copy via read/write.
261
+ """
262
+ # derive destination file path
263
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else os.path.join(dst_root, os.path.basename(src))
264
+ make_path(dst_path, **kwargs)
265
+
266
+ if get_user_pass_host_key(**kwargs): # remote mode
267
+ contents = read_from_file(src, **kwargs)
268
+ write_to_file(contents=contents, file_path=dst_path, **kwargs)
269
+ else: # local
270
+ os.makedirs(os.path.dirname(dst_path), exist_ok=True)
271
+ shutil.copy2(src, dst_path)
272
+
273
+
274
+ return dst_path
275
+
276
+
277
+ def copy_files(files, dst_root, src_rel=None, **kwargs):
278
+ """
279
+ Copy a list of files to dst_root.
280
+ """
281
+ for src in files:
282
+ copy_file(src=src, dst_root=dst_root, src_rel=src_rel, **kwargs)
283
+
284
+ def create_and_read_file(*args, **kwargs):
285
+ """
286
+ Create the file (if missing) and read contents from it.
287
+ """
288
+ file_path, contents = check_read_write_params(*args, **kwargs)
289
+ if not os.path.isfile(file_path):
290
+ write_to_file(file_path, contents or "")
291
+ return read_from_file(file_path)
292
+
293
+
294
+ def is_file_extension(obj: str) -> bool:
295
+ """Return True if obj looks like a filename with extension."""
296
+ if not isinstance(obj, str):
297
+ return False
298
+ root, ext = os.path.splitext(obj)
299
+ return bool(root and ext)
300
+
301
+
302
+ def delete_file(file_path: str):
303
+ """Safely delete a file if it exists."""
304
+ if os.path.isfile(file_path):
305
+ os.remove(file_path)
306
+ return True
307
+ return False
308
+
309
+
310
+ def get_content_lines(*args, **kwargs):
311
+ """Return a list of lines from string or file path."""
312
+ file_path, contents = check_read_write_params(*args, **kwargs)
313
+ if os.path.isfile(file_path):
314
+ contents = read_from_file(filepath)
315
+
316
+ if isinstance(contents, str):
317
+ return contents.splitlines()
318
+ elif isinstance(contents, list):
319
+ return contents
320
+ return []
321
+ def collate_text_docs(directory=None):
322
+ return [read_from_file(item) for item in get_all_files(directory=directory)]
323
+ def get_content(*paths):
324
+ item_path = os.path.join(*paths)
325
+ if os.path.isfile(item_path):
326
+ try:
327
+ content = read_from_file(item_path)
328
+ return content
329
+ except:
330
+ pass
331
+ return None
332
+ def get_text_or_read(text=None,file_path=None):
333
+ text = text or ''
334
+ imports_js = {}
335
+ if not text and file_path and os.path.isfile(file_path):
336
+ text=read_from_file(file_path)
337
+ return text
338
+ ##
@@ -12,15 +12,16 @@ Usage:
12
12
  from abstract_utilities.read_write_utils import *
13
13
  """
14
14
 
15
- import os
16
- import shlex
15
+ import os,shlex
16
+ from .string_clean import *
17
17
  from .ssh_utils.utils import run_cmd,get_print_sudo_cmd,run_local_cmd,run_remote_cmd
18
- from .file_utils.file_utils.type_checks import is_file,is_dir
19
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
20
21
  _FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
21
22
  _CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
22
23
 
23
-
24
+
24
25
  # --- Helper utilities --------------------------------------------------------
25
26
  def string_in_keys(strings, kwargs):
26
27
  """Find a matching keyword in kwargs that contains any of the given substrings."""
@@ -29,26 +30,81 @@ def string_in_keys(strings, kwargs):
29
30
  if s.lower() in key.lower():
30
31
  return key
31
32
  return None
32
-
33
-
34
- def get_path(paths):
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)
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):
72
+
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):
35
91
  """Return the first valid path among given paths."""
36
92
  for path in paths:
37
93
  if isinstance(path, str):
38
- if os.path.isfile(path):
94
+ if is_file(path,**kwargs):
39
95
  return path
40
96
  dirname = os.path.dirname(path)
41
- if os.path.exists(dirname):
97
+ if is_exists(dirname,**kwargs):
42
98
  return path
43
99
  return None
44
100
 
45
101
 
46
- def break_down_find_existing(path):
102
+ def break_down_find_existing(path,**kwargs):
47
103
  """Return the first non-existent subpath within a path chain."""
48
104
  test_path = ''
49
105
  for part in path.split(os.sep):
50
106
  test_path = os.path.join(test_path, part)
51
- if not os.path.exists(test_path):
107
+ if not is_exists(test_path,**kwargs):
52
108
  return test_path if test_path else None
53
109
  return test_path
54
110
 
@@ -97,7 +153,7 @@ def write_to_path(
97
153
 
98
154
  # shell command that fully overwrites
99
155
  # (no append, replaces contents entirely)
100
- base_cmd = f"echo {quoted_data} > {quoted_path}"
156
+ base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
101
157
 
102
158
  # optional sudo password injection
103
159
  full_cmd = get_print_sudo_cmd(
@@ -150,29 +206,39 @@ def write_to_file(*args, **kwargs):
150
206
  Returns the file_path written.
151
207
  """
152
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
+
153
212
  if contents is None:
154
213
  raise ValueError("Missing contents to write.")
155
214
  user_at_host = kwargs.get("user_at_host")
156
- if user_at_host:
215
+ if get_user_pass_host_key(**kwargs):
216
+ make_dirs(dirname, exist_ok=True,**kwargs)
157
217
  kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
158
218
  # sanitize for shell safety
159
219
  quoted_path = shlex.quote(file_path)
160
220
  quoted_data = shlex.quote(str(contents))
161
221
  # shell command that fully overwrites
162
222
  # (no append, replaces contents entirely)
163
- kwargs["cmd"] = f"echo {quoted_data} > {quoted_path}"
164
- return run_pruned_func(run_cmd,**kwargs)
165
-
166
-
167
- os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
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
233
+
234
+ make_dirs(dirname or ".", exist_ok=True)
168
235
  with open(file_path, "w", encoding="utf-8") as f:
169
236
  f.write(str(contents))
170
237
  return file_path
171
238
 
172
239
 
173
240
  def read_from_file(file_path,**kwargs):
174
- user_at_host = kwargs.get("user_at_host")
175
- if user_at_host:
241
+ if get_user_pass_host_key(**kwargs):
176
242
  kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
177
243
  basename = os.path.basename(file_path)
178
244
  kwargs["cmd"] = f'cat {basename}'
@@ -182,6 +248,44 @@ def read_from_file(file_path,**kwargs):
182
248
  return f.read()
183
249
 
184
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
+
185
289
  def create_and_read_file(*args, **kwargs):
186
290
  """
187
291
  Create the file (if missing) and read contents from it.
@@ -219,3 +323,21 @@ def get_content_lines(*args, **kwargs):
219
323
  elif isinstance(contents, list):
220
324
  return contents
221
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 *