abstract-utilities 0.2.2.492__py3-none-any.whl → 0.2.2.583__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 (201) 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 +53 -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 +57 -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/directory_utils/__init__.py +2 -0
  15. abstract_utilities/directory_utils/directory_utils.py +94 -0
  16. abstract_utilities/directory_utils/imports/__init__.py +2 -0
  17. abstract_utilities/directory_utils/imports/imports.py +1 -0
  18. abstract_utilities/directory_utils/imports/module_imports.py +2 -0
  19. abstract_utilities/directory_utils/name_utils.py +43 -0
  20. abstract_utilities/directory_utils/size_utils.py +57 -0
  21. abstract_utilities/directory_utils/src/__init__.py +4 -0
  22. abstract_utilities/directory_utils/src/directory_utils.py +108 -0
  23. abstract_utilities/directory_utils/src/name_utils.py +43 -0
  24. abstract_utilities/directory_utils/src/size_utils.py +57 -0
  25. abstract_utilities/directory_utils/src/utils.py +116 -0
  26. abstract_utilities/directory_utils/utils.py +116 -0
  27. abstract_utilities/env_utils/imports/imports.py +5 -3
  28. abstract_utilities/error_utils/__init__.py +2 -0
  29. abstract_utilities/error_utils/error_utils.py +25 -0
  30. abstract_utilities/error_utils/imports/__init__.py +2 -0
  31. abstract_utilities/error_utils/imports/imports.py +1 -0
  32. abstract_utilities/error_utils/imports/module_imports.py +1 -0
  33. abstract_utilities/file_utils/__init__.py +1 -2
  34. abstract_utilities/file_utils/imports/constants.py +84 -4
  35. abstract_utilities/file_utils/imports/imports.py +2 -21
  36. abstract_utilities/file_utils/imports/module_imports.py +2 -7
  37. abstract_utilities/file_utils/module_imports.py +12 -0
  38. abstract_utilities/file_utils/src/__init__.py +7 -0
  39. abstract_utilities/file_utils/src/file_filters/__init__.py +4 -0
  40. abstract_utilities/file_utils/src/file_filters/ensure_utils.py +116 -0
  41. abstract_utilities/file_utils/src/file_filters/filter_params.py +86 -0
  42. abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
  43. abstract_utilities/file_utils/src/file_filters/predicate_utils.py +114 -0
  44. abstract_utilities/file_utils/src/file_filters.py +177 -0
  45. abstract_utilities/file_utils/src/file_reader.py +543 -0
  46. abstract_utilities/file_utils/src/file_utils.py +156 -0
  47. abstract_utilities/file_utils/src/filter_params.py +197 -0
  48. abstract_utilities/file_utils/src/find_collect.py +190 -0
  49. abstract_utilities/file_utils/src/find_content.py +210 -0
  50. abstract_utilities/file_utils/src/initFunctionsGen.py +280 -0
  51. abstract_utilities/file_utils/src/map_utils.py +29 -0
  52. abstract_utilities/file_utils/src/pdf_utils.py +300 -0
  53. abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
  54. abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
  55. abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
  56. abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
  57. abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
  58. abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
  59. abstract_utilities/file_utils/src/type_checks.py +91 -0
  60. abstract_utilities/file_utils (2)/__init__.py +2 -0
  61. abstract_utilities/file_utils (2)/imports/__init__.py +2 -0
  62. abstract_utilities/file_utils (2)/imports/constants.py +118 -0
  63. abstract_utilities/file_utils (2)/imports/imports/__init__.py +3 -0
  64. abstract_utilities/file_utils (2)/imports/imports/constants.py +119 -0
  65. abstract_utilities/file_utils (2)/imports/imports/imports.py +46 -0
  66. abstract_utilities/file_utils (2)/imports/imports/module_imports.py +8 -0
  67. abstract_utilities/file_utils (2)/imports/utils/__init__.py +3 -0
  68. abstract_utilities/file_utils (2)/imports/utils/classes.py +379 -0
  69. abstract_utilities/file_utils (2)/imports/utils/clean_imps.py +155 -0
  70. abstract_utilities/file_utils (2)/imports/utils/filter_utils.py +341 -0
  71. abstract_utilities/file_utils (2)/src/__init__.py +8 -0
  72. abstract_utilities/file_utils (2)/src/file_filters.py +155 -0
  73. abstract_utilities/file_utils (2)/src/file_reader.py +604 -0
  74. abstract_utilities/file_utils (2)/src/find_collect.py +258 -0
  75. abstract_utilities/file_utils (2)/src/initFunctionsGen.py +286 -0
  76. abstract_utilities/file_utils (2)/src/map_utils.py +28 -0
  77. abstract_utilities/file_utils (2)/src/pdf_utils.py +300 -0
  78. abstract_utilities/hash_utils/__init__.py +2 -0
  79. abstract_utilities/hash_utils/hash_utils.py +5 -0
  80. abstract_utilities/hash_utils/imports/__init__.py +2 -0
  81. abstract_utilities/hash_utils/imports/imports.py +1 -0
  82. abstract_utilities/hash_utils/imports/module_imports.py +0 -0
  83. abstract_utilities/history_utils/__init__.py +2 -0
  84. abstract_utilities/history_utils/history_utils.py +37 -0
  85. abstract_utilities/history_utils/imports/__init__.py +2 -0
  86. abstract_utilities/history_utils/imports/imports.py +1 -0
  87. abstract_utilities/history_utils/imports/module_imports.py +0 -0
  88. abstract_utilities/import_utils/__init__.py +2 -0
  89. abstract_utilities/import_utils/circular_import_finder.py +222 -0
  90. abstract_utilities/import_utils/circular_import_finder2.py +118 -0
  91. abstract_utilities/import_utils/imports/__init__.py +4 -0
  92. abstract_utilities/import_utils/imports/constants.py +2 -0
  93. abstract_utilities/import_utils/imports/imports.py +4 -0
  94. abstract_utilities/import_utils/imports/module_imports.py +8 -0
  95. abstract_utilities/import_utils/imports/utils.py +30 -0
  96. abstract_utilities/import_utils/src/__init__.py +7 -0
  97. abstract_utilities/import_utils/src/clean_imports.py +278 -0
  98. abstract_utilities/import_utils/src/dot_utils.py +80 -0
  99. abstract_utilities/import_utils/src/extract_utils.py +46 -0
  100. abstract_utilities/import_utils/src/import_functions.py +91 -0
  101. abstract_utilities/import_utils/src/import_utils.py +299 -0
  102. abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
  103. abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
  104. abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
  105. abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
  106. abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
  107. abstract_utilities/import_utils/src/package_utils.py +140 -0
  108. abstract_utilities/import_utils/src/package_utilss/__init__.py +139 -0
  109. abstract_utilities/import_utils/src/package_utilss/context_utils.py +27 -0
  110. abstract_utilities/import_utils/src/package_utilss/import_collectors.py +53 -0
  111. abstract_utilities/import_utils/src/package_utilss/path_utils.py +28 -0
  112. abstract_utilities/import_utils/src/package_utilss/safe_import.py +27 -0
  113. abstract_utilities/import_utils/src/pkg_utils.py +194 -0
  114. abstract_utilities/import_utils/src/sysroot_utils.py +112 -0
  115. abstract_utilities/imports.py +18 -0
  116. abstract_utilities/json_utils/__init__.py +2 -0
  117. abstract_utilities/json_utils/imports/__init__.py +2 -0
  118. abstract_utilities/json_utils/imports/imports.py +2 -0
  119. abstract_utilities/json_utils/imports/module_imports.py +5 -0
  120. abstract_utilities/json_utils/json_utils.py +743 -0
  121. abstract_utilities/list_utils/__init__.py +2 -0
  122. abstract_utilities/list_utils/imports/__init__.py +2 -0
  123. abstract_utilities/list_utils/imports/imports.py +1 -0
  124. abstract_utilities/list_utils/imports/module_imports.py +0 -0
  125. abstract_utilities/list_utils/list_utils.py +199 -0
  126. abstract_utilities/log_utils/__init__.py +5 -0
  127. abstract_utilities/log_utils/abstractLogManager.py +64 -0
  128. abstract_utilities/log_utils/call_response.py +68 -0
  129. abstract_utilities/log_utils/imports/__init__.py +2 -0
  130. abstract_utilities/log_utils/imports/imports.py +7 -0
  131. abstract_utilities/log_utils/imports/module_imports.py +2 -0
  132. abstract_utilities/log_utils/log_file.py +59 -0
  133. abstract_utilities/log_utils/logger_callable.py +49 -0
  134. abstract_utilities/math_utils/__init__.py +2 -0
  135. abstract_utilities/math_utils/imports/__init__.py +2 -0
  136. abstract_utilities/math_utils/imports/imports.py +2 -0
  137. abstract_utilities/math_utils/imports/module_imports.py +1 -0
  138. abstract_utilities/math_utils/math_utils.py +208 -0
  139. abstract_utilities/parse_utils/__init__.py +2 -0
  140. abstract_utilities/parse_utils/imports/__init__.py +3 -0
  141. abstract_utilities/parse_utils/imports/constants.py +10 -0
  142. abstract_utilities/parse_utils/imports/imports.py +2 -0
  143. abstract_utilities/parse_utils/imports/module_imports.py +4 -0
  144. abstract_utilities/parse_utils/parse_utils.py +516 -0
  145. abstract_utilities/path_utils/__init__.py +2 -0
  146. abstract_utilities/path_utils/imports/__init__.py +3 -0
  147. abstract_utilities/path_utils/imports/imports.py +1 -0
  148. abstract_utilities/path_utils/imports/module_imports.py +8 -0
  149. abstract_utilities/path_utils/path_utils.py +253 -0
  150. abstract_utilities/path_utils.py +95 -14
  151. abstract_utilities/read_write_utils/__init__.py +1 -0
  152. abstract_utilities/read_write_utils/imports/__init__.py +2 -0
  153. abstract_utilities/read_write_utils/imports/imports.py +2 -0
  154. abstract_utilities/read_write_utils/imports/module_imports.py +5 -0
  155. abstract_utilities/read_write_utils/read_write_utils.py +338 -0
  156. abstract_utilities/read_write_utils.py +66 -34
  157. abstract_utilities/safe_utils/__init__.py +2 -0
  158. abstract_utilities/safe_utils/imports/__init__.py +3 -0
  159. abstract_utilities/safe_utils/imports/imports.py +2 -0
  160. abstract_utilities/safe_utils/imports/module_imports.py +2 -0
  161. abstract_utilities/safe_utils/safe_utils.py +166 -0
  162. abstract_utilities/ssh_utils/__init__.py +3 -1
  163. abstract_utilities/ssh_utils/classes.py +0 -1
  164. abstract_utilities/ssh_utils/cmd_utils.py +207 -0
  165. abstract_utilities/ssh_utils/imports/__init__.py +3 -0
  166. abstract_utilities/ssh_utils/imports/imports.py +5 -0
  167. abstract_utilities/ssh_utils/imports/module_imports.py +6 -0
  168. abstract_utilities/ssh_utils/imports/utils.py +189 -0
  169. abstract_utilities/ssh_utils/pexpect_utils.py +11 -18
  170. abstract_utilities/ssh_utils/type_checks.py +92 -0
  171. abstract_utilities/string_utils/__init__.py +4 -0
  172. abstract_utilities/string_utils/clean_utils.py +28 -0
  173. abstract_utilities/string_utils/eat_utils.py +103 -0
  174. abstract_utilities/string_utils/imports/__init__.py +3 -0
  175. abstract_utilities/string_utils/imports/imports.py +2 -0
  176. abstract_utilities/string_utils/imports/module_imports.py +2 -0
  177. abstract_utilities/string_utils/imports/utils.py +81 -0
  178. abstract_utilities/string_utils/replace_utils.py +27 -0
  179. abstract_utilities/thread_utils/__init__.py +2 -0
  180. abstract_utilities/thread_utils/imports/__init__.py +2 -0
  181. abstract_utilities/thread_utils/imports/imports.py +2 -0
  182. abstract_utilities/thread_utils/imports/module_imports.py +2 -0
  183. abstract_utilities/thread_utils/thread_utils.py +140 -0
  184. abstract_utilities/time_utils/__init__.py +2 -0
  185. abstract_utilities/time_utils/imports/__init__.py +2 -0
  186. abstract_utilities/time_utils/imports/imports.py +3 -0
  187. abstract_utilities/time_utils/imports/module_imports.py +1 -0
  188. abstract_utilities/time_utils/time_utils.py +392 -0
  189. abstract_utilities/type_utils/__init__.py +3 -0
  190. abstract_utilities/type_utils/alpha_utils.py +59 -0
  191. abstract_utilities/type_utils/imports/__init__.py +2 -0
  192. abstract_utilities/type_utils/imports/imports.py +4 -0
  193. abstract_utilities/type_utils/imports/module_imports.py +1 -0
  194. abstract_utilities/type_utils/num_utils.py +19 -0
  195. abstract_utilities/type_utils/type_utils.py +981 -0
  196. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.583.dist-info}/METADATA +1 -1
  197. abstract_utilities-0.2.2.583.dist-info/RECORD +277 -0
  198. imports/__init__.py +36 -0
  199. abstract_utilities-0.2.2.492.dist-info/RECORD +0 -92
  200. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.583.dist-info}/WHEEL +0 -0
  201. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.583.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,379 @@
1
+ from ..imports import *
2
+ def get_item_check_cmd(path, file=True, directory=False, exists=False):
3
+ if (directory and file) or exists:
4
+ typ = "e"
5
+ elif file:
6
+ typ = "f"
7
+ elif directory:
8
+ typ = "d"
9
+ elif isinstance(file, str):
10
+ if "f" in file:
11
+ typ = "f"
12
+ elif "d" in file:
13
+ typ = "d"
14
+ else:
15
+ typ = "e"
16
+ else:
17
+ typ = "e"
18
+ return f"test -{typ} {shlex.quote(path)} && echo __OK__ || true"
19
+
20
+
21
+ def get_all_item_check_cmd(path, file=True, directory=True, exists=True):
22
+ collects = []
23
+ out_js = {}
24
+
25
+ if file:
26
+ collects.append("file")
27
+ if directory:
28
+ collects.append("dir")
29
+ if exists:
30
+ collects.append("exists")
31
+
32
+ if not collects:
33
+ return out_js
34
+
35
+ path = shlex.quote(path)
36
+ for typ in collects:
37
+ t = typ[0] # f, d, or e
38
+ out_js[typ] = f"test -{t} {path} && echo __OK__ || true"
39
+
40
+ return out_js
41
+
42
+
43
+ def is_file(
44
+ path,
45
+ user_at_host=None,
46
+ password=None,
47
+ key=None,
48
+ env_path=None,
49
+ **kwargs
50
+ ):
51
+ contingencies = list(set([user_at_host,password,key,env_path]))
52
+ len_contingencies = len(contingencies)
53
+ is_potential = (len_contingencies >1 or (None not in contingencies))
54
+ if not is_potential:
55
+ return os.path.isfile(path)
56
+ cmd = get_item_check_cmd(path,file=True)
57
+ return run_cmd(cmd=cmd,
58
+ user_at_host=user_at_host,
59
+ password=password,
60
+ key=key,
61
+ env_path=env_path,
62
+ **kwargs
63
+ )
64
+ def is_dir(
65
+ path,
66
+ user_at_host=None,
67
+ password=None,
68
+ key=None,
69
+ env_path=None,
70
+ **kwargs
71
+ ):
72
+ contingencies = list(set([user_at_host,password,key,env_path]))
73
+ len_contingencies = len(contingencies)
74
+ is_potential = (len_contingencies >1 or (None not in contingencies))
75
+ if not is_potential:
76
+ return os.path.isdir(path)
77
+ cmd = get_item_check_cmd(path,file=False,directory=True)
78
+ return run_cmd(cmd=cmd,
79
+ user_at_host=user_at_host,
80
+ password=password,
81
+ key=key,
82
+ env_path=env_path,
83
+ **kwargs
84
+ )
85
+ def is_exists(
86
+ path,
87
+ user_at_host=None,
88
+ password=None,
89
+ key=None,
90
+ env_path=None,
91
+ **kwargs
92
+ ):
93
+ contingencies = list(set([user_at_host,password,key,env_path]))
94
+ len_contingencies = len(contingencies)
95
+ is_potential = (len_contingencies >1 or (None not in contingencies))
96
+ if not is_potential:
97
+ return os.path.exists(path)
98
+ if is_potential == True:
99
+ cmd = get_item_check_cmd(path,exists=True)
100
+ return run_cmd(cmd=cmd,
101
+ user_at_host=user_at_host,
102
+ password=password,
103
+ key=key,
104
+ env_path=env_path,
105
+ **kwargs
106
+ )
107
+ def is_any(
108
+ path,
109
+ user_at_host=None,
110
+ password=None,
111
+ key=None,
112
+ env_path=None,
113
+ **kwargs
114
+ ):
115
+ contingencies = list(set([user_at_host,password,key,env_path]))
116
+ len_contingencies = len(contingencies)
117
+ is_potential = (len_contingencies >1 or (None not in contingencies))
118
+ if not is_potential:
119
+ return os.path.exists(path)
120
+ if is_potential == True:
121
+ out_js = get_all_item_check_cmd(path,file=True,directory=True,exists=True)
122
+ for typ,cmd in out_js.items():
123
+ response = run_cmd(cmd=cmd,
124
+ user_at_host=user_at_host,
125
+ password=password,
126
+ key=key,
127
+ env_path=env_path,
128
+ **kwargs
129
+ )
130
+ result = "__OK__" in (response or "")
131
+ if result:
132
+ return typ
133
+ return None
134
+ class PathBackend(Protocol):
135
+ def join(self, *parts: str) -> str: ...
136
+ def isfile(self, path: str) -> bool: ...
137
+ def isdir(self, path: str) -> bool: ...
138
+ def glob_recursive(self, base: str, **opts) -> List[str]: ...
139
+ def listdir(self, base: str) -> List[str]: ...
140
+
141
+ class LocalFS:
142
+ def __init__(self, get_type=False, get_is_dir=False, get_is_file=False, get_is_exists=False, **kwargs):
143
+ self.get_type = get_type
144
+ self.get_is_dir = get_is_dir
145
+ self.get_is_file = get_is_file
146
+ self.get_is_exists = get_is_exists
147
+
148
+ def join(self, *parts: str) -> str:
149
+ return os.path.join(*parts)
150
+
151
+ def isfile(self, path: str) -> bool:
152
+ return os.path.isfile(path)
153
+
154
+ def isdir(self, path: str) -> bool:
155
+ return os.path.isdir(path)
156
+
157
+ def isexists(self, path: str) -> bool:
158
+ return os.path.exists(path)
159
+
160
+ def istype(self, path: str) -> str | None:
161
+ funcs_js = {"file": os.path.isfile, "dir": os.path.isdir, "exists": os.path.exists}
162
+ for key, func in funcs_js.items():
163
+ if func(path):
164
+ return key
165
+ return None
166
+
167
+ def is_included(self, path, **kwargs):
168
+ include_js = {}
169
+ if self.get_type:
170
+ include_js["typ"] = self.istype(path)
171
+ if self.get_is_dir:
172
+ include_js["dir"] = self.isdir(path)
173
+ if self.get_is_file:
174
+ include_js["file"] = self.isfile(path)
175
+ if self.get_is_exists:
176
+ include_js["exists"] = self.isexists(path)
177
+ return include_js
178
+ def glob_recursive(self, base: str, **opts) -> List[str]:
179
+ """
180
+ opts:
181
+ - maxdepth: int | None
182
+ - mindepth: int (default 1)
183
+ - follow_symlinks: bool
184
+ - include_dirs: bool
185
+ - include_files: bool
186
+ - exclude_hidden: bool
187
+ """
188
+ maxdepth = opts.get("maxdepth")
189
+ mindepth = opts.get("mindepth", 1)
190
+ follow = opts.get("follow_symlinks", False)
191
+ want_d = opts.get("include_dirs", True)
192
+ want_f = opts.get("include_files", True)
193
+ hide = opts.get("exclude_hidden", False)
194
+
195
+ results: List[str] = []
196
+ base_depth = os.path.normpath(base).count(os.sep)
197
+
198
+ for root, dirs, files in os.walk(base, followlinks=follow):
199
+ depth = os.path.normpath(root).count(os.sep) - base_depth
200
+ if maxdepth is not None and depth > maxdepth:
201
+ dirs[:] = []
202
+ continue
203
+ if want_d and depth >= mindepth:
204
+ for d in dirs:
205
+ if hide and d.startswith("."): continue
206
+ results.append(os.path.join(root, d))
207
+ if want_f and depth >= mindepth:
208
+ for f in files:
209
+ if hide and f.startswith("."): continue
210
+ results.append(os.path.join(root, f))
211
+ return results
212
+
213
+ def listdir(self, base: str) -> List[str]:
214
+ try:
215
+ return [os.path.join(base, name) for name in os.listdir(base)]
216
+ except Exception:
217
+ return []
218
+ def get_spec_kwargs(
219
+ user_at_host=None,
220
+ password=None,
221
+ key=None,
222
+ env_path=None,
223
+ kwargs=None
224
+ ):
225
+ kwargs = kwargs or {}
226
+ kwargs["user_at_host"] = kwargs.get("user_at_host") or user_at_host
227
+ kwargs["password"] = kwargs.get("password") or password
228
+ kwargs["key"] = kwargs.get("key") or key
229
+ kwargs["env_path"] = kwargs.get("env_path") or env_path
230
+ return kwargs
231
+ class SSHFS:
232
+ """Remote POSIX backend via run_remote_cmd."""
233
+ def __init__(self, password=None, key=None, env_path=None,
234
+ get_type=False, get_is_dir=False, get_is_file=False, get_is_exists=False, **kwargs):
235
+ self.user_at_host = kwargs.get('user_at_host') or kwargs.get('user') or kwargs.get('host')
236
+ self.password = password
237
+ self.key = key
238
+ self.env_path = env_path
239
+ self.get_type = get_type
240
+ self.get_is_dir = get_is_dir
241
+ self.get_is_file = get_is_file
242
+ self.get_is_exists = get_is_exists
243
+
244
+ def cell_spec_kwargs(self, func, path, **kwargs):
245
+ kwargs = get_spec_kwargs(
246
+ user_at_host=self.user_at_host,
247
+ password=self.password,
248
+ key=self.key,
249
+ env_path=self.env_path,
250
+ kwargs=kwargs
251
+ )
252
+ return func(path, **kwargs)
253
+
254
+ def is_included(self, path, **kwargs):
255
+ include_js = {}
256
+ if self.get_type:
257
+ include_js["typ"] = self.istype(path, **kwargs)
258
+ if self.get_is_dir:
259
+ include_js["dir"] = self.isdir(path, **kwargs)
260
+ if self.get_is_file:
261
+ include_js["file"] = self.isfile(path, **kwargs)
262
+ if self.get_is_exists:
263
+ include_js["exists"] = self.isexists(path, **kwargs)
264
+ return include_js
265
+
266
+ def join(self, *parts: str) -> str:
267
+ return posixpath.join(*parts)
268
+
269
+ def isfile(self, path: str, **kwargs) -> bool:
270
+ out = self.cell_spec_kwargs(is_file, path, **kwargs)
271
+ return "__OK__" in (out or "")
272
+
273
+ def isdir(self, path: str, **kwargs) -> bool:
274
+ out = self.cell_spec_kwargs(is_dir, path, **kwargs)
275
+ return "__OK__" in (out or "")
276
+
277
+ def isexists(self, path: str, **kwargs) -> bool:
278
+ out = self.cell_spec_kwargs(is_exists, path, **kwargs)
279
+ return "__OK__" in (out or "")
280
+
281
+ def istype(self, path: str, **kwargs) -> str | None:
282
+ out = self.cell_spec_kwargs(is_any, path, **kwargs)
283
+ return out
284
+
285
+ def glob_recursive(self, base: str, **opts) -> List[str]:
286
+ maxdepth = opts.get("maxdepth")
287
+ mindepth = opts.get("mindepth", 1)
288
+ follow = opts.get("follow_symlinks", False)
289
+ want_d = opts.get("include_dirs", True)
290
+ want_f = opts.get("include_files", True)
291
+ hide = opts.get("exclude_hidden", False)
292
+
293
+ parts = []
294
+ if follow:
295
+ parts.append("-L")
296
+ parts += ["find", shlex.quote(base)]
297
+ if mindepth is not None:
298
+ parts += ["-mindepth", str(mindepth)]
299
+ if maxdepth is not None:
300
+ parts += ["-maxdepth", str(maxdepth)]
301
+
302
+ type_filters = []
303
+ if want_d and not want_f:
304
+ type_filters = ["-type", "d"]
305
+ elif want_f and not want_d:
306
+ type_filters = ["-type", "f"]
307
+
308
+ hidden_filter = []
309
+ if hide:
310
+ hidden_filter = ["!", "-regex", r".*/\..*"]
311
+
312
+ cmd = " ".join(parts + type_filters + hidden_filter + ["-printf", r"'%p\n'"]) + " 2>/dev/null"
313
+ out = run_remote_cmd(self.user_at_host, cmd)
314
+ return [line.strip().strip("'") for line in (out or "").splitlines() if line.strip()]
315
+
316
+ def listdir(self, base: str) -> List[str]:
317
+ cmd = f"find {shlex.quote(base)} -maxdepth 1 -mindepth 1 -printf '%p\\n' 2>/dev/null"
318
+ out = run_remote_cmd(self.user_at_host, cmd)
319
+ return [line.strip() for line in (out or "").splitlines() if line.strip()]
320
+
321
+
322
+
323
+ def try_group(pre,item,strings):
324
+
325
+ try:
326
+ m = pre.match(item)
327
+ for i,string in enumerate(strings):
328
+ strings[i] = m.group(string)
329
+
330
+ except:
331
+ return None
332
+ return strings
333
+ def normalize_items(
334
+ paths: Iterable[str],
335
+ user_at_host=None,
336
+ get_type=True,
337
+ get_is_dir=False,
338
+ get_is_file=False,
339
+ get_is_exists=False,
340
+ **kwargs
341
+ ) -> List[tuple[PathBackend, str, dict]]:
342
+ pairs: List[tuple[PathBackend, str, dict]] = []
343
+ host = user_at_host or kwargs.get("host") or kwargs.get("user")
344
+ paths = make_list(paths)
345
+ for item in paths:
346
+ if not item:
347
+ continue
348
+
349
+ strings = try_group(REMOTE_RE, item, ["host", "path"])
350
+ fs_host = None
351
+ nuhost = None
352
+
353
+ if (strings and None not in strings) or host:
354
+ if strings and None not in strings:
355
+ nuhost = strings[0]
356
+ item = strings[1] or item
357
+ nuhost = nuhost or host
358
+ fs_host = SSHFS(
359
+ nuhost,
360
+ user_at_host=user_at_host,
361
+ get_type=get_type,
362
+ get_is_dir=get_is_dir,
363
+ get_is_file=get_is_file,
364
+ get_is_exists=get_is_exists,
365
+ **kwargs
366
+ )
367
+ else:
368
+ fs_host = LocalFS(
369
+ get_type=get_type,
370
+ get_is_dir=get_is_dir,
371
+ get_is_file=get_is_file,
372
+ get_is_exists=get_is_exists
373
+ )
374
+
375
+ includes = fs_host.is_included(item)
376
+ pairs.append((fs_host, item, includes))
377
+ return pairs
378
+
379
+
@@ -0,0 +1,155 @@
1
+ from ..imports import *
2
+ # ============================================================
3
+ # Constants
4
+ # ============================================================
5
+ import_tag = 'import '
6
+ from_tag = 'from '
7
+
8
+ # ============================================================
9
+ # Helpers
10
+ # ============================================================
11
+ def get_caller_path(i=None):
12
+ i = i or 1
13
+ frame = inspect.stack()[i]
14
+ return os.path.abspath(frame.filename)
15
+
16
+ def make_list(obj: any) -> list:
17
+ if isinstance(obj, str) and ',' in obj:
18
+ obj = obj.split(',')
19
+ if isinstance(obj, (set, tuple)):
20
+ return list(obj)
21
+ if isinstance(obj, list):
22
+ return obj
23
+ return [obj]
24
+
25
+ def eatElse(stringObj, chars=None):
26
+ chars = make_list(chars or []) + list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_')
27
+ while stringObj:
28
+ if stringObj and stringObj[0] not in chars:
29
+ stringObj = stringObj[1:]
30
+ continue
31
+ if stringObj and stringObj[-1] not in chars:
32
+ stringObj = stringObj[:-1]
33
+ continue
34
+ break
35
+ return stringObj
36
+
37
+ def clean_line(line):
38
+ return eatAll(line, [' ', '', '\t', '\n'])
39
+
40
+ def is_line_import(line):
41
+ return bool(line and line.startswith(import_tag) and 'from ' not in line)
42
+
43
+ def is_line_from_import(line):
44
+ return bool(line and line.startswith(from_tag) and ' import ' in line)
45
+
46
+ def is_from_group_start(line):
47
+ return bool(line and line.startswith(from_tag) and 'import' in line and '(' in line and not line.rstrip().endswith(')'))
48
+
49
+ def is_from_group_end(line):
50
+ return bool(line and ')' in line)
51
+
52
+ def clean_imports(imports):
53
+ if isinstance(imports, str):
54
+ imports = imports.split(',')
55
+ return [eatElse(imp.strip()) for imp in imports if imp.strip()]
56
+
57
+ # ============================================================
58
+ # Combine lone import statements
59
+ # ============================================================
60
+ def combine_lone_imports(text=None, file_path=None):
61
+ text = text or ''
62
+ if file_path and os.path.isfile(file_path):
63
+ text += read_from_file(file_path)
64
+ lines = text.split('\n')
65
+
66
+ cleaned_import_list = []
67
+ nu_lines = []
68
+ j = None
69
+
70
+ for i, line in enumerate(lines):
71
+ if is_line_import(line):
72
+ if j is None:
73
+ nu_lines.append(import_tag)
74
+ j = i
75
+ cleaned_import_list += clean_imports(line.split(import_tag)[1])
76
+ else:
77
+ nu_lines.append(line)
78
+
79
+ if j is None:
80
+ return '\n'.join(nu_lines)
81
+ cleaned_import_list = sorted(set(cleaned_import_list))
82
+ nu_lines[j] += ', '.join(cleaned_import_list)
83
+ return '\n'.join(nu_lines)
84
+
85
+ # ============================================================
86
+ # Merge repeated 'from pkg import ...' (1-line only)
87
+ # Preserve multi-line grouped imports
88
+ # ============================================================
89
+ def merge_from_import_groups(text=None, file_path=None):
90
+ if file_path and os.path.isfile(file_path):
91
+ text = read_from_file(file_path)
92
+ text = text or ''
93
+ lines = text.split('\n')
94
+
95
+ pkg_to_imports: Dict[str, Set[str]] = {}
96
+ pkg_to_line_index: Dict[str, int] = {}
97
+ nu_lines: List[str] = []
98
+
99
+ in_group = False
100
+ for i, line in enumerate(lines):
101
+ stripped = line.strip()
102
+
103
+ # preserve multi-line grouped blocks intact
104
+ if in_group:
105
+ nu_lines.append(line)
106
+ if is_from_group_end(line):
107
+ in_group = False
108
+ continue
109
+
110
+ if is_from_group_start(line):
111
+ in_group = True
112
+ nu_lines.append(line)
113
+ continue
114
+
115
+ if is_line_from_import(line):
116
+ try:
117
+ pkg_part, imps_part = line.split(' import ', 1)
118
+ pkg_name = pkg_part.replace('from ', '').strip()
119
+ imps = clean_imports(imps_part)
120
+ except Exception:
121
+ nu_lines.append(line)
122
+ continue
123
+
124
+ if pkg_name not in pkg_to_imports:
125
+ pkg_to_imports[pkg_name] = set(imps)
126
+ pkg_to_line_index[pkg_name] = len(nu_lines)
127
+ nu_lines.append(line)
128
+ else:
129
+ pkg_to_imports[pkg_name].update(imps)
130
+ else:
131
+ nu_lines.append(line)
132
+
133
+ # Rewrite first occurrences
134
+ for pkg, idx in pkg_to_line_index.items():
135
+ all_imps = sorted(pkg_to_imports[pkg])
136
+ nu_lines[idx] = f"from {pkg} import {', '.join(all_imps)}"
137
+
138
+ return '\n'.join(nu_lines)
139
+
140
+ # ============================================================
141
+ # Pipeline
142
+ # ============================================================
143
+ def clean_imports_pipeline(path: str):
144
+ raw = read_from_file(path)
145
+ step1 = combine_lone_imports(text=raw)
146
+ step2 = merge_from_import_groups(text=step1)
147
+ return step2
148
+
149
+ # ============================================================
150
+ # Standalone Run
151
+ # ============================================================
152
+ if __name__ == "__main__":
153
+ abs_path = "/home/flerb/Documents/pythonTools/modules/src/modules/abstract_utilities/src/abstract_utilities/file_utils/imports/imports.py"
154
+ cleaned = clean_imports_pipeline(abs_path)
155
+ print(cleaned)