abstract-utilities 0.2.2.486__py3-none-any.whl → 0.2.2.593__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 (202) 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/file_utils/type_checks.py +2 -1
  35. abstract_utilities/file_utils/imports/constants.py +84 -4
  36. abstract_utilities/file_utils/imports/imports.py +2 -21
  37. abstract_utilities/file_utils/imports/module_imports.py +2 -7
  38. abstract_utilities/file_utils/module_imports.py +12 -0
  39. abstract_utilities/file_utils/src/__init__.py +7 -0
  40. abstract_utilities/file_utils/src/file_filters/__init__.py +4 -0
  41. abstract_utilities/file_utils/src/file_filters/ensure_utils.py +118 -0
  42. abstract_utilities/file_utils/src/file_filters/filter_params.py +86 -0
  43. abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
  44. abstract_utilities/file_utils/src/file_filters/predicate_utils.py +114 -0
  45. abstract_utilities/file_utils/src/file_filters.py +177 -0
  46. abstract_utilities/file_utils/src/file_reader.py +543 -0
  47. abstract_utilities/file_utils/src/file_utils.py +156 -0
  48. abstract_utilities/file_utils/src/filter_params.py +197 -0
  49. abstract_utilities/file_utils/src/find_collect.py +190 -0
  50. abstract_utilities/file_utils/src/find_content.py +210 -0
  51. abstract_utilities/file_utils/src/initFunctionsGen.py +280 -0
  52. abstract_utilities/file_utils/src/map_utils.py +29 -0
  53. abstract_utilities/file_utils/src/pdf_utils.py +300 -0
  54. abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
  55. abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
  56. abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
  57. abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
  58. abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
  59. abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
  60. abstract_utilities/file_utils/src/type_checks.py +91 -0
  61. abstract_utilities/file_utils (2)/__init__.py +2 -0
  62. abstract_utilities/file_utils (2)/imports/__init__.py +2 -0
  63. abstract_utilities/file_utils (2)/imports/constants.py +118 -0
  64. abstract_utilities/file_utils (2)/imports/imports/__init__.py +3 -0
  65. abstract_utilities/file_utils (2)/imports/imports/constants.py +119 -0
  66. abstract_utilities/file_utils (2)/imports/imports/imports.py +46 -0
  67. abstract_utilities/file_utils (2)/imports/imports/module_imports.py +8 -0
  68. abstract_utilities/file_utils (2)/imports/utils/__init__.py +3 -0
  69. abstract_utilities/file_utils (2)/imports/utils/classes.py +379 -0
  70. abstract_utilities/file_utils (2)/imports/utils/clean_imps.py +155 -0
  71. abstract_utilities/file_utils (2)/imports/utils/filter_utils.py +341 -0
  72. abstract_utilities/file_utils (2)/src/__init__.py +8 -0
  73. abstract_utilities/file_utils (2)/src/file_filters.py +155 -0
  74. abstract_utilities/file_utils (2)/src/file_reader.py +604 -0
  75. abstract_utilities/file_utils (2)/src/find_collect.py +258 -0
  76. abstract_utilities/file_utils (2)/src/initFunctionsGen.py +286 -0
  77. abstract_utilities/file_utils (2)/src/map_utils.py +28 -0
  78. abstract_utilities/file_utils (2)/src/pdf_utils.py +300 -0
  79. abstract_utilities/hash_utils/__init__.py +2 -0
  80. abstract_utilities/hash_utils/hash_utils.py +5 -0
  81. abstract_utilities/hash_utils/imports/__init__.py +2 -0
  82. abstract_utilities/hash_utils/imports/imports.py +1 -0
  83. abstract_utilities/hash_utils/imports/module_imports.py +0 -0
  84. abstract_utilities/history_utils/__init__.py +2 -0
  85. abstract_utilities/history_utils/history_utils.py +37 -0
  86. abstract_utilities/history_utils/imports/__init__.py +2 -0
  87. abstract_utilities/history_utils/imports/imports.py +1 -0
  88. abstract_utilities/history_utils/imports/module_imports.py +0 -0
  89. abstract_utilities/import_utils/__init__.py +2 -0
  90. abstract_utilities/import_utils/circular_import_finder.py +222 -0
  91. abstract_utilities/import_utils/circular_import_finder2.py +118 -0
  92. abstract_utilities/import_utils/imports/__init__.py +4 -0
  93. abstract_utilities/import_utils/imports/constants.py +2 -0
  94. abstract_utilities/import_utils/imports/imports.py +4 -0
  95. abstract_utilities/import_utils/imports/module_imports.py +8 -0
  96. abstract_utilities/import_utils/imports/utils.py +30 -0
  97. abstract_utilities/import_utils/src/__init__.py +7 -0
  98. abstract_utilities/import_utils/src/clean_imports.py +278 -0
  99. abstract_utilities/import_utils/src/dot_utils.py +80 -0
  100. abstract_utilities/import_utils/src/extract_utils.py +46 -0
  101. abstract_utilities/import_utils/src/import_functions.py +90 -0
  102. abstract_utilities/import_utils/src/import_utils.py +299 -0
  103. abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
  104. abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
  105. abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
  106. abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
  107. abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
  108. abstract_utilities/import_utils/src/package_utils.py +140 -0
  109. abstract_utilities/import_utils/src/package_utilss/__init__.py +139 -0
  110. abstract_utilities/import_utils/src/package_utilss/context_utils.py +27 -0
  111. abstract_utilities/import_utils/src/package_utilss/import_collectors.py +53 -0
  112. abstract_utilities/import_utils/src/package_utilss/path_utils.py +28 -0
  113. abstract_utilities/import_utils/src/package_utilss/safe_import.py +27 -0
  114. abstract_utilities/import_utils/src/pkg_utils.py +194 -0
  115. abstract_utilities/import_utils/src/sysroot_utils.py +112 -0
  116. abstract_utilities/imports.py +18 -0
  117. abstract_utilities/json_utils/__init__.py +2 -0
  118. abstract_utilities/json_utils/imports/__init__.py +2 -0
  119. abstract_utilities/json_utils/imports/imports.py +2 -0
  120. abstract_utilities/json_utils/imports/module_imports.py +5 -0
  121. abstract_utilities/json_utils/json_utils.py +743 -0
  122. abstract_utilities/list_utils/__init__.py +2 -0
  123. abstract_utilities/list_utils/imports/__init__.py +2 -0
  124. abstract_utilities/list_utils/imports/imports.py +1 -0
  125. abstract_utilities/list_utils/imports/module_imports.py +0 -0
  126. abstract_utilities/list_utils/list_utils.py +199 -0
  127. abstract_utilities/log_utils/__init__.py +5 -0
  128. abstract_utilities/log_utils/abstractLogManager.py +64 -0
  129. abstract_utilities/log_utils/call_response.py +68 -0
  130. abstract_utilities/log_utils/imports/__init__.py +2 -0
  131. abstract_utilities/log_utils/imports/imports.py +7 -0
  132. abstract_utilities/log_utils/imports/module_imports.py +2 -0
  133. abstract_utilities/log_utils/log_file.py +59 -0
  134. abstract_utilities/log_utils/logger_callable.py +49 -0
  135. abstract_utilities/math_utils/__init__.py +2 -0
  136. abstract_utilities/math_utils/imports/__init__.py +2 -0
  137. abstract_utilities/math_utils/imports/imports.py +2 -0
  138. abstract_utilities/math_utils/imports/module_imports.py +1 -0
  139. abstract_utilities/math_utils/math_utils.py +208 -0
  140. abstract_utilities/parse_utils/__init__.py +2 -0
  141. abstract_utilities/parse_utils/imports/__init__.py +3 -0
  142. abstract_utilities/parse_utils/imports/constants.py +10 -0
  143. abstract_utilities/parse_utils/imports/imports.py +2 -0
  144. abstract_utilities/parse_utils/imports/module_imports.py +4 -0
  145. abstract_utilities/parse_utils/parse_utils.py +516 -0
  146. abstract_utilities/path_utils/__init__.py +2 -0
  147. abstract_utilities/path_utils/imports/__init__.py +3 -0
  148. abstract_utilities/path_utils/imports/imports.py +1 -0
  149. abstract_utilities/path_utils/imports/module_imports.py +8 -0
  150. abstract_utilities/path_utils/path_utils.py +253 -0
  151. abstract_utilities/path_utils.py +95 -14
  152. abstract_utilities/read_write_utils/__init__.py +1 -0
  153. abstract_utilities/read_write_utils/imports/__init__.py +2 -0
  154. abstract_utilities/read_write_utils/imports/imports.py +2 -0
  155. abstract_utilities/read_write_utils/imports/module_imports.py +5 -0
  156. abstract_utilities/read_write_utils/read_write_utils.py +338 -0
  157. abstract_utilities/read_write_utils.py +110 -60
  158. abstract_utilities/safe_utils/__init__.py +2 -0
  159. abstract_utilities/safe_utils/imports/__init__.py +3 -0
  160. abstract_utilities/safe_utils/imports/imports.py +2 -0
  161. abstract_utilities/safe_utils/imports/module_imports.py +2 -0
  162. abstract_utilities/safe_utils/safe_utils.py +166 -0
  163. abstract_utilities/ssh_utils/__init__.py +3 -1
  164. abstract_utilities/ssh_utils/classes.py +0 -1
  165. abstract_utilities/ssh_utils/cmd_utils.py +207 -0
  166. abstract_utilities/ssh_utils/imports/__init__.py +3 -0
  167. abstract_utilities/ssh_utils/imports/imports.py +5 -0
  168. abstract_utilities/ssh_utils/imports/module_imports.py +6 -0
  169. abstract_utilities/ssh_utils/imports/utils.py +189 -0
  170. abstract_utilities/ssh_utils/pexpect_utils.py +11 -18
  171. abstract_utilities/ssh_utils/type_checks.py +92 -0
  172. abstract_utilities/string_utils/__init__.py +4 -0
  173. abstract_utilities/string_utils/clean_utils.py +28 -0
  174. abstract_utilities/string_utils/eat_utils.py +103 -0
  175. abstract_utilities/string_utils/imports/__init__.py +3 -0
  176. abstract_utilities/string_utils/imports/imports.py +2 -0
  177. abstract_utilities/string_utils/imports/module_imports.py +2 -0
  178. abstract_utilities/string_utils/imports/utils.py +81 -0
  179. abstract_utilities/string_utils/replace_utils.py +27 -0
  180. abstract_utilities/thread_utils/__init__.py +2 -0
  181. abstract_utilities/thread_utils/imports/__init__.py +2 -0
  182. abstract_utilities/thread_utils/imports/imports.py +2 -0
  183. abstract_utilities/thread_utils/imports/module_imports.py +2 -0
  184. abstract_utilities/thread_utils/thread_utils.py +140 -0
  185. abstract_utilities/time_utils/__init__.py +2 -0
  186. abstract_utilities/time_utils/imports/__init__.py +2 -0
  187. abstract_utilities/time_utils/imports/imports.py +3 -0
  188. abstract_utilities/time_utils/imports/module_imports.py +1 -0
  189. abstract_utilities/time_utils/time_utils.py +392 -0
  190. abstract_utilities/type_utils/__init__.py +3 -0
  191. abstract_utilities/type_utils/alpha_utils.py +59 -0
  192. abstract_utilities/type_utils/imports/__init__.py +2 -0
  193. abstract_utilities/type_utils/imports/imports.py +4 -0
  194. abstract_utilities/type_utils/imports/module_imports.py +1 -0
  195. abstract_utilities/type_utils/num_utils.py +19 -0
  196. abstract_utilities/type_utils/type_utils.py +981 -0
  197. {abstract_utilities-0.2.2.486.dist-info → abstract_utilities-0.2.2.593.dist-info}/METADATA +1 -1
  198. abstract_utilities-0.2.2.593.dist-info/RECORD +277 -0
  199. imports/__init__.py +36 -0
  200. abstract_utilities-0.2.2.486.dist-info/RECORD +0 -92
  201. {abstract_utilities-0.2.2.486.dist-info → abstract_utilities-0.2.2.593.dist-info}/WHEEL +0 -0
  202. {abstract_utilities-0.2.2.486.dist-info → abstract_utilities-0.2.2.593.dist-info}/top_level.txt +0 -0
@@ -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
@@ -1,3 +1,5 @@
1
+ from .imports import *
1
2
  from .classes import *
2
- from .utils import *
3
+ from .cmd_utils import *
3
4
  from .pexpect_utils import *
5
+ from .type_checks import *
@@ -1,5 +1,4 @@
1
1
  from .imports import *
2
- from .utils import run_local_cmd, run_ssh_cmd,run_any_cmd,run_cmd
3
2
 
4
3
  class PathBackend(Protocol):
5
4
  def join(self, *parts: str) -> str: ...
@@ -0,0 +1,207 @@
1
+ from .imports import *
2
+ def get_output(p):
3
+ """
4
+ Get the output of a subprocess command.
5
+
6
+ This function takes a subprocess Popen object as an argument and returns
7
+ the output generated by the command's execution.
8
+
9
+ Args:
10
+ p (subprocess.Popen): A Popen object representing a subprocess command.
11
+
12
+ Returns:
13
+ tuple: A tuple containing the standard output and standard error streams
14
+ of the executed command.
15
+ """
16
+ return p.communicate()
17
+
18
+ def get_cmd_out(st):
19
+ """
20
+ Get the output of a shell command.
21
+
22
+ This function executes a shell command using the 'cmd_input' function and
23
+ retrieves the output generated by the command's execution.
24
+
25
+ Args:
26
+ st (str): The shell command to execute.
27
+
28
+ Returns:
29
+ tuple: A tuple containing the standard output and standard error streams
30
+ of the executed shell command.
31
+ """
32
+ return get_output(cmd_input(st))
33
+ def cmd_input(st):
34
+ """
35
+ Execute a shell command using subprocess.
36
+
37
+ Args:
38
+ - st (str): Command to be executed.
39
+
40
+ Returns:
41
+ - subprocess.Popen: A Popen object for communication.
42
+ """
43
+ return subprocess.Popen(st, stdout=subprocess.PIPE, shell=True)
44
+ def get_output_text(parent_dir: str = os.getcwd()) -> str:
45
+ """
46
+ Get the path to the 'output.txt' file in the given directory.
47
+
48
+ Args:
49
+ parent_dir (str, optional): Directory path. Defaults to the current working directory.
50
+
51
+ Returns:
52
+ str: Path to the 'output.txt' file.
53
+ """
54
+ return os.path.join(parent_dir,'output.txt')
55
+ def get_env_value(key: str = None, env_path: str = None) -> str:
56
+ """
57
+ Retrieve environment value based on a key from a specified .env file.
58
+
59
+ Args:
60
+ key (str, optional): Environment key to search for. Defaults to None.
61
+ env_path (str, optional): Path to start searching for the .env file. Defaults to None.
62
+
63
+ Returns:
64
+ str: Value corresponding to the given environment key.
65
+ """
66
+ args={}
67
+ if key != None:
68
+ args["key"]=key
69
+ if env_path != None:
70
+ args["start_path"]=env_path
71
+ return find_and_read_env_file(**args)
72
+ def print_cmd(input: str, output: str) -> None:
73
+ """
74
+ Print the input command and its corresponding output.
75
+
76
+ Args:
77
+ input (str): The command that was run.
78
+ output (str): Output produced by the command.
79
+ """
80
+ print(f"Command Line Arguments: {input}")
81
+ print(f"Output:\n{output}")
82
+ def get_sudo_password(key: str = "SUDO_PASSWORD") -> str:
83
+ """
84
+ Retrieve the sudo password from an environment file.
85
+
86
+ Args:
87
+ key (str, optional): Environment key for the sudo password. Defaults to "SUDO_PASSWORD".
88
+
89
+ Returns:
90
+ str: The sudo password.
91
+ """
92
+ return find_and_read_env_file(key=key)
93
+ def cmd_run_sudo(cmd: str, password: str = None, key: str = None, output_text: str = None) -> None:
94
+ """
95
+ Execute a command with sudo privileges using either provided password or retrieving it from an environment file.
96
+
97
+ Args:
98
+ cmd (str): Command to be executed.
99
+ password (str, optional): Password for sudo. Defaults to None.
100
+ key (str, optional): Environment key to retrieve sudo password. Defaults to None.
101
+ output_text (str, optional): Path to store the command output. Defaults to None.
102
+ """
103
+ if password !=None:
104
+ cmd_run(f'echo "{password}" | sudo -S -k {cmd}',output_text)
105
+ elif key != None:
106
+ cmd_run(f'echo "{get_env_value(key)}" | sudo -S -k {cmd}',output_text)
107
+ else:
108
+ cmd_run(f'echo "{get_sudo_password()}" | sudo -S -k {cmd}',output_text)
109
+ def cmd_run(cmd: str, output_text: str = None, print_output: bool = False) -> None:
110
+ if output_text is None:
111
+ output_text = get_output_text()
112
+
113
+ # Clear output file
114
+ with open(output_text, 'w') as f:
115
+ pass
116
+
117
+ # Append output redirection
118
+ full_cmd = f'{cmd} >> {output_text}; echo END_OF_CMD >> {output_text}'
119
+
120
+ if print_output:
121
+ print(full_cmd)
122
+
123
+ subprocess.call(full_cmd, shell=True)
124
+
125
+ # Wait until END_OF_CMD appears
126
+ while True:
127
+ get_sleep(sleep_timer=0.5)
128
+ with open(output_text, 'r') as f:
129
+ lines = f.readlines()
130
+ if lines and lines[-1].strip() == 'END_OF_CMD':
131
+ break
132
+
133
+ if print_output:
134
+ with open(output_text, 'r') as f:
135
+ print_cmd(full_cmd, f.read().strip())
136
+
137
+ os.remove(output_text)
138
+
139
+ def pexpect_cmd_with_args(command: str, child_runs: list, output_text: str = os.getcwd(),print_output:bool=False) -> int:
140
+ """
141
+ Run a command using pexpect and handle its prompts with specified responses.
142
+
143
+ Args:
144
+ command (str): Command to be executed.
145
+ child_runs (list): List of prompts and their respective responses.
146
+ output_text (str, optional): Path to store the command output. Defaults to the current working directory.
147
+
148
+ Returns:
149
+ int: Exit status of the command.
150
+ """
151
+ child = pexpect.spawn(command)
152
+
153
+ for each in child_runs:
154
+ # Wait for the process to prompt for the input and respond with it
155
+ child.expect(each["prompt"])
156
+
157
+ # Respond with the corresponding input
158
+ if each["pass"] is not None:
159
+ pass_phrase = each["pass"]
160
+ else:
161
+ args = {}
162
+ if "key" in each:
163
+ if each["key"] is not None:
164
+ args["key"] = each["key"]
165
+ if "env_path" in each:
166
+ if each["env_path"] is not None:
167
+ args["start_path"] = each["env_path"]
168
+
169
+ pass_phrase = get_env_value(**args)
170
+
171
+ child.sendline(pass_phrase)
172
+ if print_output:
173
+ print("Output after handling prompt:")
174
+ print(each["prompt"])
175
+
176
+ # Wait for the process to finish
177
+ child.expect(pexpect.EOF)
178
+ output = child.before.decode("utf-8")
179
+
180
+ # Write output to the output file
181
+ with open(get_output_text(), "w") as f:
182
+ f.write(output)
183
+ if print_output:
184
+ print_cmd(command, output)
185
+
186
+ return child.exitstatus
187
+ def get_user_pass_host_key(**kwargs):
188
+ args = ['password','user_at_host','host','key','user']
189
+ kwargs['del_kwarg']=kwargs.get('del_kwarg',False)
190
+ values,kwargs = get_from_kwargs(*args,**kwargs)
191
+ return values
192
+
193
+ # --- Base remote checker -----------------------------------------------------
194
+ def _remote_test(path: str, test_flag: str, timeout: int = 5,*args, **kwargs) -> bool:
195
+ """
196
+ Run a remote shell test (e.g. -f, -d) via SSH.
197
+ Returns True if test succeeds, False otherwise.
198
+ """
199
+ try:
200
+ kwargs['cmd']=f"[ {test_flag} {shlex.quote(path)} ] && echo 1 || echo 0"
201
+ kwargs['text']=True
202
+ kwargs['timeout']=timeout
203
+ kwargs['stderr']=subprocess.DEVNULL
204
+ result = run_pruned_func(run_cmd,**kwargs)
205
+ return result.strip() == "1"
206
+ except Exception:
207
+ return False
@@ -0,0 +1,3 @@
1
+ from .imports import *
2
+ from .module_imports import *
3
+ from .utils import *
@@ -0,0 +1,5 @@
1
+ # remote_fs.py
2
+ from __future__ import annotations
3
+ from typing import *
4
+ from ...imports import shlex, os,subprocess,pexpect, fnmatch, glob, posixpath, re
5
+
@@ -0,0 +1,6 @@
1
+ from ...string_utils import get_from_kwargs,eatAll,eatOuter
2
+ from ...type_utils import make_list # whatever you already have
3
+ from ...time_utils import get_sleep
4
+ from abstract_security import *
5
+
6
+ from ...class_utils import get_caller, get_caller_path, get_caller_dir,SingletonMeta,run_pruned_func
@@ -0,0 +1,189 @@
1
+ from .imports import *
2
+ from .module_imports import *
3
+ def get_pass_from_key(key=None,env_path=None):
4
+ if key:
5
+ return get_env_value(key=key,path=env_path)
6
+ def get_password(password=None,key=None,env_path=None):
7
+ password = password or get_pass_from_key(key=key,env_path=env_path)
8
+ return password
9
+
10
+ def get_print_sudo_cmd(
11
+ cmd: str,
12
+ password=None,
13
+ key=None,
14
+ env_path=None
15
+ ):
16
+ password = get_password(password=password,key=key,env_path=env_path)
17
+ if password != None:
18
+
19
+ cmd = get_password_cmd(password=password,cmd=cmd)
20
+ return cmd
21
+ def get_password_cmd(password:str,cmd:str):
22
+ sudo_cmd = get_sudo_cmd(cmd)
23
+ password_sudo_cmd = get_raw_password_sudo_cmd(password=password,sudo_cmd=sudo_cmd)
24
+ return password_sudo_cmd
25
+ def get_sudo_cmd(cmd: str):
26
+ return f"sudo -S -k {cmd}"
27
+ def get_raw_password_sudo_cmd(password:str,sudo_cmd:str):
28
+ return f"printf %s {shlex.quote(password)} | {sudo_cmd}"
29
+ def get_remote_bash(
30
+ cmd: str,
31
+ cwd: str | None = None
32
+ ):
33
+ return f"bash -lc {shlex.quote((f'cd {shlex.quote(cwd)} && {cmd}') if cwd else cmd)}"
34
+ def get_remote_ssh(
35
+ user_at_host: str=None,
36
+ remote:str=None
37
+ ):
38
+ return f"ssh {shlex.quote(user_at_host)} {shlex.quote(remote)}"
39
+ def get_remote_cmd(
40
+ cmd: str,
41
+ user_at_host: str,
42
+ cwd: str | None = None,
43
+ password=None,
44
+ key=None,
45
+ env_path=None
46
+
47
+ ):
48
+ cmd = get_print_sudo_cmd(
49
+ cmd=cmd,
50
+ password=password,
51
+ key=key,
52
+ env_path=env_path
53
+ )
54
+ remote = get_remote_bash(
55
+ cmd=cmd,
56
+ cwd=cwd
57
+ )
58
+ full = get_remote_ssh(
59
+ user_at_host=user_at_host,
60
+ remote=remote
61
+ )
62
+ return full
63
+
64
+
65
+ def execute_cmd(
66
+ *args,
67
+ outfile=None,
68
+ **kwargs
69
+ ) -> str:
70
+ proc = subprocess.run(*args, **kwargs)
71
+ output = (proc.stdout or "") + (proc.stderr or "")
72
+ if outfile:
73
+ try:
74
+ with open(outfile, "w", encoding="utf-8", errors="ignore") as f:
75
+ f.write(output)
76
+ except Exception:
77
+ pass
78
+ return output
79
+
80
+ def run_local_cmd(
81
+ cmd: str,
82
+ cwd: str | None = None,
83
+ outfile: Optional[str] = None,
84
+ shell=True,
85
+ text=True,
86
+ capture_output=True,
87
+ user_at_host: str=None,
88
+ password=None,
89
+ key=None,
90
+ env_path=None
91
+ ) -> str:
92
+ cmd = get_print_sudo_cmd(
93
+ cmd=cmd,
94
+ password=password,
95
+ key=key,
96
+ env_path=env_path
97
+ )
98
+ return execute_cmd(
99
+ cmd,
100
+ outfile=outfile,
101
+ shell=shell,
102
+ cwd=cwd,
103
+ text=text,
104
+ capture_output=capture_output
105
+ )
106
+
107
+ def run_remote_cmd(
108
+ user_at_host: str,
109
+ cmd: str,
110
+ cwd: str | None = None,
111
+ outfile: Optional[str] = None,
112
+ shell=True,
113
+ text=True,
114
+ capture_output=True,
115
+ password=None,
116
+ key=None,
117
+ env_path=None
118
+ ) -> str:
119
+ """
120
+ Run on remote via SSH; capture stdout+stderr locally; write to local outfile.
121
+ NOTE: we do *not* try to write the file on the remote to avoid later scp.
122
+ """
123
+ cmd = get_print_sudo_cmd(
124
+ cmd=cmd,
125
+ password=password,
126
+ key=key,
127
+ env_path=env_path
128
+ )
129
+ # wrap in bash -lc for PATH/profile + allow 'cd && ...'
130
+ cmd = get_remote_cmd(
131
+ cmd=cmd,
132
+ user_at_host=user_at_host,
133
+ cwd=cwd
134
+ )
135
+ return execute_cmd(
136
+ cmd,
137
+ outfile=outfile,
138
+ shell=shell,
139
+ text=text,
140
+ capture_output=capture_output
141
+ )
142
+
143
+ def run_cmd(
144
+ cmd: str=None,
145
+ cwd: str | None = None,
146
+ outfile: Optional[str] = None,
147
+ shell=True,
148
+ text=True,
149
+ capture_output=True,
150
+ user_at_host: str=None,
151
+ password=None,
152
+ key=None,
153
+ env_path=None
154
+ ) -> str:
155
+
156
+ if user_at_host:
157
+ return run_ssh_cmd(
158
+ user_at_host=user_at_host,
159
+ cmd=cmd,
160
+ cwd=cwd,
161
+ outfile=outfile,
162
+ shell=shell,
163
+ text=text,
164
+ capture_output=capture_output,
165
+ password=password,
166
+ key=key,
167
+ env_path=env_path
168
+ )
169
+ return run_local_cmd(
170
+ cmd=cmd,
171
+ cwd=cwd,
172
+ outfile=outfile,
173
+ shell=shell,
174
+ text=text,
175
+ capture_output=capture_output,
176
+ password=password,
177
+ key=key,
178
+ env_path=env_path
179
+ )
180
+ run_ssh_cmd = run_remote_cmd
181
+ remote_cmd = run_remote_cmd
182
+ ssh_cmd = run_remote_cmd
183
+
184
+ local_cmd = run_local_cmd
185
+
186
+
187
+ run_any_cmd = run_cmd
188
+ any_cmd = run_cmd
189
+ cmd_run = run_cmd
@@ -1,6 +1,4 @@
1
- from .classes import *
2
- from .utils import *
3
- from ..env_utils import *
1
+ from .imports import *
4
2
  # pexpect is optional; import lazily if you prefer
5
3
 
6
4
  # keep your execute_cmd; add a thin wrapper that supports stdin text cleanly
@@ -36,17 +34,17 @@ def exec_sudo_capture(
36
34
  """
37
35
  if password is None:
38
36
  password = get_env_value(key=key) if key else get_sudo_password()
39
- password = f"{password}\n" if password else password
37
+
40
38
  sudo_cmd = f"sudo -S -k {cmd}"
41
39
 
42
40
  if user_at_host:
43
41
  # build the remote command (bash -lc + optional cd)
44
42
  remote = get_remote_cmd(cmd=sudo_cmd, user_at_host=user_at_host, cwd=cwd)
45
43
  # feed password to remote's stdin (ssh forwards stdin)
46
- out = execute_cmd_input(remote, input_text=password,
44
+ out = execute_cmd_input(remote, input_text=password + "\n",
47
45
  shell=True, text=True, capture_output=True)
48
46
  else:
49
- out = execute_cmd_input(sudo_cmd, input_text=password,
47
+ out = execute_cmd_input(sudo_cmd, input_text=password + "\n",
50
48
  shell=True, text=True, capture_output=True, cwd=cwd)
51
49
 
52
50
  if print_output:
@@ -123,8 +121,8 @@ def cmd_run(
123
121
  out = execute_cmd(remote, shell=True, text=True, capture_output=True)
124
122
  else:
125
123
  out = execute_cmd(cmd, shell=True, text=True, capture_output=True, cwd=cwd)
126
- ## if print_output:
127
- ## print_cmd(cmd, out or "")
124
+ if print_output:
125
+ print_cmd(cmd, out or "")
128
126
  return out or ""
129
127
 
130
128
  # ---- legacy file-backed path (unchanged in spirit) ----
@@ -150,10 +148,9 @@ def cmd_run(
150
148
  if lines and lines[-1].strip() == 'END_OF_CMD':
151
149
  break
152
150
 
153
- ## if print_output:
154
- ## print(full_cmd)
155
- ## with open(output_text, 'r') as f:
156
- ## print_cmd(full_cmd, f.read().strip())
151
+ if print_output:
152
+ with open(output_text, 'r') as f:
153
+ print_cmd(full_cmd, f.read().strip())
157
154
 
158
155
  try:
159
156
  os.remove(output_text)
@@ -212,8 +209,8 @@ def exec_expect(
212
209
 
213
210
  child.expect(pexpect.EOF)
214
211
  out = child.before.decode("utf-8", errors="ignore")
215
- ## if print_output:
216
- ## print_cmd(command, out)
212
+ if print_output:
213
+ print_cmd(command, out)
217
214
 
218
215
  return child.exitstatus if child.exitstatus is not None else 0
219
216
 
@@ -261,7 +258,6 @@ def cmd_run_sudo(
261
258
  remote_sudo_line = f'printf %s {shlex.quote(pw)} | {sudo_cmd}'
262
259
  remote_full = get_remote_cmd(cmd=remote_sudo_line, user_at_host=user_at_host, cwd=cwd)
263
260
  return cmd_run(remote_full, output_text=output_text, print_output=print_output)
264
-
265
261
  def pexpect_cmd_with_args(
266
262
  command: str,
267
263
  child_runs: list,
@@ -310,6 +306,3 @@ def pexpect_cmd_with_args(
310
306
  else:
311
307
  if print_output:
312
308
  print_cmd(command, out)
313
-
314
- return child.exitstatus if child.exitstatus is not None else 0
315
- cmd_input = execute_cmd_input