abstract-utilities 0.2.2.448__py3-none-any.whl → 0.2.2.449__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 (57) hide show
  1. abstract_utilities/__init__.py +43 -17
  2. abstract_utilities/abstract_classes.py +0 -49
  3. abstract_utilities/class_utils.py +3 -39
  4. abstract_utilities/cmd_utils/user_utils.py +1 -1
  5. abstract_utilities/{compare_utils/compare_utils.py → compare_utils.py} +1 -1
  6. abstract_utilities/dynimport.py +15 -7
  7. abstract_utilities/json_utils.py +0 -35
  8. abstract_utilities/log_utils.py +3 -14
  9. abstract_utilities/path_utils.py +6 -90
  10. abstract_utilities/read_write_utils.py +156 -99
  11. abstract_utilities/robust_reader/__init__.py +1 -1
  12. abstract_utilities/{file_utils/file_utils → robust_reader}/file_reader.py +19 -5
  13. abstract_utilities/{file_utils/file_utils → robust_reader}/pdf_utils.py +9 -1
  14. abstract_utilities/robust_readers/__init__.py +1 -0
  15. abstract_utilities/{file_utils/file_utils/file_utils.py → robust_readers/file_filters.py} +1 -2
  16. abstract_utilities/{file_utils/file_utils → robust_readers}/filter_params.py +38 -1
  17. abstract_utilities/robust_readers/initFuncGen.py +74 -82
  18. abstract_utilities/type_utils.py +1 -0
  19. {abstract_utilities-0.2.2.448.dist-info → abstract_utilities-0.2.2.449.dist-info}/METADATA +4 -15
  20. abstract_utilities-0.2.2.449.dist-info/RECORD +49 -0
  21. {abstract_utilities-0.2.2.448.dist-info → abstract_utilities-0.2.2.449.dist-info}/WHEEL +1 -1
  22. abstract_utilities/cmd_utils/imports/__init__.py +0 -1
  23. abstract_utilities/cmd_utils/imports/imports.py +0 -10
  24. abstract_utilities/cmd_utils/pexpect_utils.py +0 -310
  25. abstract_utilities/compare_utils/__init__.py +0 -3
  26. abstract_utilities/compare_utils/best_match.py +0 -150
  27. abstract_utilities/compare_utils/find_value.py +0 -105
  28. abstract_utilities/env_utils/__init__.py +0 -3
  29. abstract_utilities/env_utils/abstractEnv.py +0 -129
  30. abstract_utilities/env_utils/envy_it.py +0 -33
  31. abstract_utilities/env_utils/imports/__init__.py +0 -2
  32. abstract_utilities/env_utils/imports/imports.py +0 -8
  33. abstract_utilities/env_utils/imports/utils.py +0 -122
  34. abstract_utilities/file_utils/__init__.py +0 -3
  35. abstract_utilities/file_utils/file_utils/__init__.py +0 -6
  36. abstract_utilities/file_utils/file_utils/file_filters.py +0 -104
  37. abstract_utilities/file_utils/file_utils/imports.py +0 -1
  38. abstract_utilities/file_utils/file_utils/map_utils.py +0 -29
  39. abstract_utilities/file_utils/imports/__init__.py +0 -5
  40. abstract_utilities/file_utils/imports/classes.py +0 -381
  41. abstract_utilities/file_utils/imports/constants.py +0 -39
  42. abstract_utilities/file_utils/imports/file_functions.py +0 -10
  43. abstract_utilities/file_utils/imports/imports.py +0 -14
  44. abstract_utilities/file_utils/imports/module_imports.py +0 -9
  45. abstract_utilities/file_utils/req.py +0 -329
  46. abstract_utilities/robust_reader/imports/__init__.py +0 -1
  47. abstract_utilities/robust_reader/imports/imports.py +0 -12
  48. abstract_utilities/robust_readers/imports.py +0 -8
  49. abstract_utilities/safe_utils.py +0 -133
  50. abstract_utilities/ssh_utils/__init__.py +0 -3
  51. abstract_utilities/ssh_utils/classes.py +0 -127
  52. abstract_utilities/ssh_utils/imports.py +0 -10
  53. abstract_utilities/ssh_utils/pexpect_utils.py +0 -315
  54. abstract_utilities/ssh_utils/utils.py +0 -188
  55. abstract_utilities/string_utils.py +0 -12
  56. abstract_utilities-0.2.2.448.dist-info/RECORD +0 -83
  57. {abstract_utilities-0.2.2.448.dist-info → abstract_utilities-0.2.2.449.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,49 @@
1
+ abstract_utilities/__init__.py,sha256=07mV5GPv0lff7htzMdIW1nhWo59ykRG9bPIyPgki2Tw,6236
2
+ abstract_utilities/abstract_classes.py,sha256=oKr2j7DRz_vGb7r-uN3hAchF2OcebN405ZOoeWGexUc,783
3
+ abstract_utilities/class_utils.py,sha256=-YHkdbaChRIz9YLXJlFF4m7VkdwUCts_HOUbKXxkrYA,12735
4
+ abstract_utilities/collator_utils.py,sha256=9exNoZAr9rABGYTwZOn7hdLbpnMtRd2AgfU7yjZrXGw,2348
5
+ abstract_utilities/compare_utils.py,sha256=gWcjmeFI2h8-9q72ClaP8OmmxQDeMuB0eptupEwuYFk,14033
6
+ abstract_utilities/doit.py,sha256=a1zkyMJbSGPvE-OmCQcH_dQyLME392UfvQmGztOWyhE,1646
7
+ abstract_utilities/dynimport.py,sha256=QLQLMZZbw259cwbIbbuUluoQm_ckIZwcdEuh0P847es,6971
8
+ abstract_utilities/error_utils.py,sha256=dSMIM3TKe4e9i_akObyjDwy3Zu4fnoWRK9hucg_ryZo,890
9
+ abstract_utilities/global_utils.py,sha256=UkCS1nE561bVbxWsH-YQdFPSeZFMYXV7xg-DAtGUvrI,2204
10
+ abstract_utilities/hash_utils.py,sha256=u7t209ERD9aGONZHqmkYtiQRRadD2qG5ICSTxlYlZMc,206
11
+ abstract_utilities/history_utils.py,sha256=2bG8hMSRzLWMae4mpd2sf1esYtqT2D_3MDxeJnAE2Jw,1633
12
+ abstract_utilities/json_utils.py,sha256=bX0oRHkGt_yW5H7YErhC40IoGcwBxlBRw26vOmpZA9g,26150
13
+ abstract_utilities/list_utils.py,sha256=i1fZ_kZ0mf_ei6w0MOkuEieRiyF-ReeAXzIdoRI1cvo,6298
14
+ abstract_utilities/log_utils.py,sha256=dUu-12aprUygbTJ9rgOH57CBGlgwOciaDJNbsGuaNdE,8999
15
+ abstract_utilities/math_utils.py,sha256=0o1ls1En03UAkYmxTBildCCJDfHygmNuvVnrNrLYtK0,6578
16
+ abstract_utilities/parse_utils.py,sha256=Z5OGRwHuzCzY91fz0JJojk1BPAo1XF2quNNLuBF4_Vk,18602
17
+ abstract_utilities/path_utils.py,sha256=AUOGC1X2HS9DSZHoPiyWky0-GcZ-CJjDNQ4ef97p1PA,16556
18
+ abstract_utilities/read_write_utils.py,sha256=mmRmQaKFVXM5w4YKS_VsQpbQE7-LcyIRg0eyOrykWIY,7308
19
+ abstract_utilities/string_clean.py,sha256=-gY9i2yqjX5UClvSaKsSrzA4GjR7eaNI3GnFjZpt2bo,5923
20
+ abstract_utilities/tetsts.py,sha256=PrejTUew5dAAqNb4erMJwfdSHxDyuuHGWY2fMlWk5hk,21
21
+ abstract_utilities/thread_utils.py,sha256=LhE1ylSuOKkkMErBf6SjZprjO_vfh3IKfvNKJQiCxho,5460
22
+ abstract_utilities/time_utils.py,sha256=yikMjn7i-OBKfmOujfNtDz4R0VTMgi3dfQNrCIZUbQU,13052
23
+ abstract_utilities/type_utils.py,sha256=wAbQKyfXsGFTQxiViV2FJzlNo52LC8UKihdGYPYChxI,27030
24
+ abstract_utilities/utils.py,sha256=SCa_-x_wsWrcokQXKwlhalxndxLn5Wg25-zqRdJUmag,185049
25
+ abstract_utilities/cmd_utils/__init__.py,sha256=StTaaB9uzJexvr4TFGVqp_o0_s9T6rQlE3fOZtb_y_0,51
26
+ abstract_utilities/cmd_utils/cmd_utils.py,sha256=n2DEo91J8LWuIJoSoDkWdApUY_8mHrUW3kjEjjF34Io,7876
27
+ abstract_utilities/cmd_utils/user_utils.py,sha256=d_ZPerAWPovKry0gsQBeCAQW9T7QvKZ2bcJnGa8ysGw,1864
28
+ abstract_utilities/robust_reader/__init__.py,sha256=7JVGEqZ2VFyFF06cqQ8TFz8EyreOB7Jhisnd69rxL-8,28
29
+ abstract_utilities/robust_reader/file_reader.py,sha256=6RuLTdLNVERKWOUyjheqYZZCcUkMOt1j-2u7U3EN0Rg,25097
30
+ abstract_utilities/robust_reader/file_reader2.py,sha256=U-5opkLu-bct091Eb-5CiNBTf0UFoSITYi8zR-Sz38w,25077
31
+ abstract_utilities/robust_reader/file_readers.py,sha256=U-5opkLu-bct091Eb-5CiNBTf0UFoSITYi8zR-Sz38w,25077
32
+ abstract_utilities/robust_reader/pdf_utils.py,sha256=sNEJRBi4ypbA3hXQPFoFnPHVSPstbdBAwCoeyNa18YE,10763
33
+ abstract_utilities/robust_reader/sadfsad.py,sha256=gH2ebI9KfiYFv78jzPGk8WPST_FGtojnd_yDwrcvQoM,25282
34
+ abstract_utilities/robust_readers/__init__.py,sha256=JS5czvP8-_STym3vLQNU_vSGf3N1mAivSuqRuGIBVlI,83
35
+ abstract_utilities/robust_readers/file_filters.py,sha256=O71C2xASPU2UjDOor8pob9i1EJWINHs_B9K3DmK7E5Y,7706
36
+ abstract_utilities/robust_readers/filter_params.py,sha256=hmwPQR6K2m39w7ObWf1m5aL9Wo39dUDrUrefpsD3_pg,4912
37
+ abstract_utilities/robust_readers/initFuncGen.py,sha256=dr2kjrwOvFoL5fu2GNqjghrgr0xV3npBVNpAT0Uy8ko,4615
38
+ abstract_utilities/robust_readers/import_utils/__init__.py,sha256=hKYj8irPXAN-gIm0frFd0_8fnUNQraWEVugRUrSjcLw,166
39
+ abstract_utilities/robust_readers/import_utils/dot_utils.py,sha256=pmwnY461mOnDjIjgHD6H9MhQXFaF-q8kWerJDgJ1DuI,2364
40
+ abstract_utilities/robust_readers/import_utils/function_utils.py,sha256=Q9NKvRov3uAaz2Aal3d6fb_opWNXHF9C8GSKOjgfO8Y,1622
41
+ abstract_utilities/robust_readers/import_utils/import_utils.py,sha256=l0GYdtj5FEYX2yknL-8ru7_U2Sp9Hi1NpegqWPLRMc8,11705
42
+ abstract_utilities/robust_readers/import_utils/impot_functions.py,sha256=1_pzkfgixRAzTzGnICcZi-4ocdkjpB0ENPCx96ET3LM,2499
43
+ abstract_utilities/robust_readers/import_utils/safe_import_utils.py,sha256=L-pwmWkV6eOkYNKA9c4QLTJ5v0DoWQu_v5HukCOo95w,2414
44
+ abstract_utilities/robust_readers/import_utils/sysroot_utils.py,sha256=f8hj20VA9yvvYkqQ9ecuBlzmTOaT5G7ni14QesDtdL0,2098
45
+ abstract_utilities/robust_readers/import_utils/utils.py,sha256=xyMObkdyvQAzAIv_kagLhFdkwSaPd4h0bCjTCYyfGhY,722
46
+ abstract_utilities-0.2.2.449.dist-info/METADATA,sha256=1N5SaK-Xtxb5qpKpnBwdLVQG1AqB3TugQoPO1IGE93Y,27846
47
+ abstract_utilities-0.2.2.449.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
48
+ abstract_utilities-0.2.2.449.dist-info/top_level.txt,sha256=BF0GZ0xVFfN1K-hFIWPO3viNsOs1sSF86n1vHBg39FM,19
49
+ abstract_utilities-0.2.2.449.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1 +0,0 @@
1
- from .imports import *
@@ -1,10 +0,0 @@
1
- # remote_fs.py
2
- from __future__ import annotations
3
- from typing import *
4
- import subprocess, shlex, os, fnmatch, glob, posixpath, re
5
- # ---- import your existing pieces ----
6
- from ...type_utils import make_list # whatever you already have
7
- from ...time_utils import get_sleep
8
- from ...ssh_utils import *
9
- from ...env_utils import *
10
- from ...string_clean import eatOuter
@@ -1,310 +0,0 @@
1
-
2
- from .ssh_utils import *
3
- from ..env_utils import *
4
- # pexpect is optional; import lazily if you prefer
5
-
6
- # keep your execute_cmd; add a thin wrapper that supports stdin text cleanly
7
- def execute_cmd_input(
8
- *args,
9
- input_text: str | None = None,
10
- outfile: str | None = None,
11
- **kwargs
12
- ) -> str:
13
- """
14
- Like execute_cmd, but lets you pass text to stdin (subprocess.run(input=...)).
15
- """
16
- if input_text is not None:
17
- kwargs["input"] = input_text
18
- # ensure text mode so Python passes str not bytes
19
- kwargs.setdefault("text", True)
20
- return execute_cmd(*args, outfile=outfile, **kwargs)
21
-
22
- # -------------------------
23
- # Core: capture + printing
24
- # -------------------------
25
- def exec_sudo_capture(
26
- cmd: str,
27
- *,
28
- password: str | None = None,
29
- key: str | None = None,
30
- user_at_host: str | None = None,
31
- cwd: str | None = None,
32
- print_output: bool = False,
33
- ) -> str:
34
- """
35
- Run a sudo command and return its output (no temp file).
36
- """
37
- if password is None:
38
- password = get_env_value(key=key) if key else get_sudo_password()
39
-
40
- sudo_cmd = f"sudo -S -k {cmd}"
41
-
42
- if user_at_host:
43
- # build the remote command (bash -lc + optional cd)
44
- remote = get_remote_cmd(cmd=sudo_cmd, user_at_host=user_at_host, cwd=cwd)
45
- # feed password to remote's stdin (ssh forwards stdin)
46
- out = execute_cmd_input(remote, input_text=password + "\n",
47
- shell=True, text=True, capture_output=True)
48
- else:
49
- out = execute_cmd_input(sudo_cmd, input_text=password + "\n",
50
- shell=True, text=True, capture_output=True, cwd=cwd)
51
-
52
- if print_output:
53
- print_cmd(cmd, out or "")
54
- return out or ""
55
-
56
-
57
-
58
- # ---------------------------------------------------
59
- # SUDO helpers (local + SSH) with env/password options
60
- # ---------------------------------------------------
61
- def exec_sudo(
62
- cmd: str,
63
- *,
64
- password: Optional[str] = None,
65
- key: Optional[str] = None,
66
- user_at_host: Optional[str] = None,
67
- cwd: Optional[str] = None,
68
- outfile: Optional[str] = None,
69
- print_output: bool = False,
70
- ) -> str:
71
- """
72
- Execute `cmd` via sudo either locally or on remote.
73
- Password order of precedence:
74
- 1) `password` arg
75
- 2) `key` -> get_env_value(key)
76
- 3) get_sudo_password()
77
-
78
- Uses: sudo -S -k (-S read password from stdin, -k invalidate cached timestamp)
79
- """
80
- if password is None:
81
- if key:
82
- password = get_env_value(key=key)
83
- else:
84
- password = get_sudo_password()
85
-
86
- # Compose the sudo command that reads from stdin
87
- sudo_cmd = f"sudo -S -k {cmd}"
88
-
89
- if user_at_host:
90
- # For remote: the password is piped to SSH stdin, which flows to remote sudo's stdin.
91
- remote = get_remote_cmd(cmd=sudo_cmd, user_at_host=user_at_host, cwd=cwd)
92
- full = f"printf %s {shlex.quote(password)} | {remote}"
93
- out = execute_cmd(full, shell=True, text=True, capture_output=True, outfile=outfile)
94
- else:
95
- # Local
96
- full = f"printf %s {shlex.quote(password)} | {sudo_cmd}"
97
- out = execute_cmd(full, shell=True, text=True, capture_output=True, outfile=outfile)
98
-
99
- if print_output:
100
- print_cmd(cmd, out or "")
101
- return out or ""
102
-
103
-
104
- # -------------------------------------------------
105
- # Fire-and-forget (file-backed) compatible runner
106
- # -------------------------------------------------
107
- def cmd_run(
108
- cmd: str,
109
- output_text: str | None = None,
110
- print_output: bool = False,
111
- *,
112
- user_at_host: str | None = None,
113
- cwd: str | None = None,
114
- ) -> str | None:
115
- """
116
- If output_text is None → capture+return output (no file).
117
- If output_text is provided → legacy file-backed behavior.
118
- """
119
- if output_text is None:
120
- # capture mode
121
- if user_at_host:
122
- remote = get_remote_cmd(cmd=cmd, user_at_host=user_at_host, cwd=cwd)
123
- out = execute_cmd(remote, shell=True, text=True, capture_output=True)
124
- else:
125
- out = execute_cmd(cmd, shell=True, text=True, capture_output=True, cwd=cwd)
126
- if print_output:
127
- print_cmd(cmd, out or "")
128
- return out or ""
129
-
130
- # ---- legacy file-backed path (unchanged in spirit) ----
131
- # Clear output file
132
- with open(output_text, 'w'):
133
- pass
134
-
135
- # Append redirection + sentinel
136
- full_cmd = f'{cmd} >> {output_text}; echo END_OF_CMD >> {output_text}'
137
-
138
- # Execute local/remote
139
- if user_at_host:
140
- remote_line = get_remote_cmd(cmd=full_cmd, user_at_host=user_at_host, cwd=cwd)
141
- subprocess.call(remote_line, shell=True)
142
- else:
143
- subprocess.call(full_cmd, shell=True, cwd=cwd)
144
-
145
- # Wait for sentinel
146
- while True:
147
- get_sleep(sleep_timer=0.5)
148
- with open(output_text, 'r') as f:
149
- lines = f.readlines()
150
- if lines and lines[-1].strip() == 'END_OF_CMD':
151
- break
152
-
153
- if print_output:
154
- with open(output_text, 'r') as f:
155
- print_cmd(full_cmd, f.read().strip())
156
-
157
- try:
158
- os.remove(output_text)
159
- except OSError:
160
- pass
161
-
162
- return None
163
-
164
-
165
- # ----------------------------------------------------
166
- # pexpect wrappers (local + SSH) for interactive flows
167
- # ----------------------------------------------------
168
- def exec_expect(
169
- command: str,
170
- child_runs: List[Dict[str, Any]],
171
- *,
172
- user_at_host: Optional[str] = None,
173
- cwd: Optional[str] = None,
174
- print_output: bool = False,
175
- ) -> int:
176
- """
177
- Run `command` and answer interactive prompts.
178
-
179
- child_runs: list of dicts like:
180
- { "prompt": r"Password:", "pass": "xyz" }
181
- { "prompt": r"Enter passphrase:", "key": "MY_KEY", "env_path": "/path/for/.env" }
182
- If "pass" is None, we resolve via get_env_value(key=..., start_path=env_path).
183
-
184
- Returns exitstatus (0=success).
185
- """
186
- if user_at_host:
187
- # Wrap command for remote execution
188
- remote_line = get_remote_cmd(cmd=command, user_at_host=user_at_host, cwd=cwd)
189
- spawn_cmd = f"{remote_line}"
190
- else:
191
- spawn_cmd = f"bash -lc {shlex.quote((f'cd {shlex.quote(cwd)} && {command}') if cwd else command)}"
192
-
193
- child = pexpect.spawn(spawn_cmd)
194
-
195
- for each in child_runs:
196
- child.expect(each["prompt"])
197
-
198
- if each.get("pass") is not None:
199
- pass_phrase = each["pass"]
200
- else:
201
- args = {}
202
- if "key" in each and each["key"] is not None:
203
- args["key"] = each["key"]
204
- if "env_path" in each and each["env_path"] is not None:
205
- args["start_path"] = each["env_path"]
206
- pass_phrase = get_env_value(**args)
207
-
208
- child.sendline(pass_phrase)
209
- if print_output:
210
- print("Answered prompt:", each["prompt"])
211
-
212
- child.expect(pexpect.EOF)
213
- out = child.before.decode("utf-8", errors="ignore")
214
- if print_output:
215
- print_cmd(command, out)
216
-
217
- return child.exitstatus if child.exitstatus is not None else 0
218
-
219
-
220
- # ---------------------------------------
221
- # Convenience shims to mirror your names
222
- # ---------------------------------------
223
- def cmd_run_sudo(
224
- cmd: str,
225
- password: str | None = None,
226
- key: str | None = None,
227
- output_text: str | None = None,
228
- *,
229
- user_at_host: str | None = None,
230
- cwd: str | None = None,
231
- print_output: bool = False,
232
- ) -> str | None:
233
- """
234
- If output_text is None → capture sudo output and return it.
235
- If output_text is provided → legacy file-backed behavior feeding sudo via stdin.
236
- """
237
- if output_text is None:
238
- return exec_sudo_capture(
239
- cmd,
240
- password=password,
241
- key=key,
242
- user_at_host=user_at_host,
243
- cwd=cwd,
244
- print_output=print_output,
245
- )
246
-
247
- # ---- legacy file-backed path ----
248
- # build the underlying sudo command
249
- sudo_cmd = f"sudo -S -k {cmd}"
250
- pw = password if password is not None else (get_env_value(key=key) if key else get_sudo_password())
251
-
252
- # We need to feed password to stdin in the same shell that runs sudo.
253
- # For file-backed mode we’ll inline a small shell that reads from a here-string.
254
- # Local:
255
- if not user_at_host:
256
- full = f'bash -lc {shlex.quote((f"cd {shlex.quote(cwd)} && " if cwd else "") + f"printf %s {shlex.quote(pw)} | {sudo_cmd}")}'
257
- return cmd_run(full, output_text=output_text, print_output=print_output)
258
- # Remote:
259
- # On remote, do the same in the remote bash -lc
260
- remote_sudo_line = f'printf %s {shlex.quote(pw)} | {sudo_cmd}'
261
- remote_full = get_remote_cmd(cmd=remote_sudo_line, user_at_host=user_at_host, cwd=cwd)
262
- return cmd_run(remote_full, output_text=output_text, print_output=print_output)
263
- def pexpect_cmd_with_args(
264
- command: str,
265
- child_runs: list,
266
- output_text: str | None = None,
267
- *,
268
- user_at_host: str | None = None,
269
- cwd: str | None = None,
270
- print_output: bool = False
271
- ) -> int:
272
- """
273
- If output_text is None → return output string via print_output, else write to file then remove (legacy).
274
- """
275
- if user_at_host:
276
- spawn_cmd = get_remote_cmd(cmd=command, user_at_host=user_at_host, cwd=cwd)
277
- else:
278
- spawn_cmd = f"bash -lc {shlex.quote((f'cd {shlex.quote(cwd)} && {command}') if cwd else command)}"
279
-
280
- child = pexpect.spawn(spawn_cmd)
281
-
282
- for each in child_runs:
283
- child.expect(each["prompt"])
284
- if each.get("pass") is not None:
285
- pass_phrase = each["pass"]
286
- else:
287
- args = {}
288
- if "key" in each and each["key"] is not None:
289
- args["key"] = each["key"]
290
- if "env_path" in each and each["env_path"] is not None:
291
- args["start_path"] = each["env_path"]
292
- pass_phrase = get_env_value(**args)
293
- child.sendline(pass_phrase)
294
- if print_output:
295
- print("Answered prompt:", each["prompt"])
296
-
297
- child.expect(pexpect.EOF)
298
- out = child.before.decode("utf-8", errors="ignore")
299
-
300
- if output_text:
301
- with open(output_text, "w") as f:
302
- f.write(out)
303
- if print_output:
304
- print_cmd(command, out)
305
- # keep legacy? your old code removed the file; here we’ll keep it (safer).
306
- # If you want the old behavior, uncomment:
307
- # os.remove(output_text)
308
- else:
309
- if print_output:
310
- print_cmd(command, out)
@@ -1,3 +0,0 @@
1
- from .compare_utils import *
2
- from .find_value import get_first_match, get_all_match
3
- from .best_match import best_match
@@ -1,150 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Any, Iterable, Iterator, Tuple, Union, Dict, List, Optional
3
- import re
4
- from difflib import SequenceMatcher
5
-
6
- JSONLike = Union[dict, list, tuple, set, str, int, float, bool, None]
7
- PathType = Tuple[Union[str, int], ...]
8
-
9
- def iter_values(obj: JSONLike, path: PathType = ()) -> Iterator[Tuple[PathType, Any]]:
10
- if isinstance(obj, dict):
11
- for k, v in obj.items():
12
- yield from iter_values(v, path + (k,))
13
- elif isinstance(obj, (list, tuple)):
14
- for i, v in enumerate(obj):
15
- yield from iter_values(v, path + (i,))
16
- elif isinstance(obj, set):
17
- for v in obj:
18
- yield from iter_values(v, path + ('<setitem>',))
19
- else:
20
- yield path, obj
21
-
22
- def _norm(s: str, case_insensitive: bool) -> str:
23
- return s.lower() if case_insensitive else s
24
-
25
- def _word_boundary_regex(term: str, case_insensitive: bool) -> re.Pattern:
26
- flags = re.IGNORECASE if case_insensitive else 0
27
- # word boundary around the whole term; escape term for literal
28
- return re.compile(rf"\b{re.escape(term)}\b", flags)
29
-
30
- def _score_string(
31
- value: str,
32
- terms: Iterable[str],
33
- *,
34
- case_insensitive: bool = True,
35
- min_ratio: float = 0.6,
36
- ) -> Tuple[float, Dict[str, float]]:
37
- """
38
- Score a *string* against the list of terms. Returns (score, per_term_scores).
39
- Weights:
40
- exact=+3, word-boundary=+2, substring=+1, fuzzy=+0.5*ratio (if ratio>=min_ratio).
41
- +0.2 bonus per extra unique term matched (beyond the first).
42
- """
43
- if not isinstance(value, str):
44
- return 0.0, {}
45
- v = _norm(value, case_insensitive)
46
- per_term: Dict[str, float] = {}
47
- matched_terms = 0
48
-
49
- for term in terms:
50
- t = _norm(term, case_insensitive)
51
- term_score = 0.0
52
-
53
- if v == t:
54
- term_score = max(term_score, 3.0)
55
-
56
- # word boundary
57
- if _word_boundary_regex(term, case_insensitive).search(value):
58
- term_score = max(term_score, 2.0)
59
-
60
- # substring
61
- if t in v:
62
- term_score = max(term_score, 1.0)
63
-
64
- # fuzzy similarity
65
- ratio = SequenceMatcher(None, v, t).ratio() # 0..1
66
- if ratio >= min_ratio:
67
- term_score = max(term_score, 0.5 * ratio)
68
-
69
- if term_score > 0:
70
- matched_terms += 1
71
- per_term[term] = term_score
72
-
73
- # Bonus for covering more than one term
74
- bonus = 0.2 * max(0, matched_terms - 1)
75
- total = sum(per_term.values()) + bonus
76
- return total, per_term
77
-
78
- def best_match(
79
- obj: JSONLike,
80
- *,
81
- terms: Iterable[str],
82
- case_insensitive: bool = True,
83
- min_ratio: float = 0.6,
84
- key_weight: Dict[str, float] | None = None, # e.g. {'window_title': 1.5}
85
- coerce_non_strings: bool = False,
86
- ) -> Optional[Dict[str, Any]]:
87
- """
88
- Return the single best leaf string:
89
- { 'value': str, 'path': PathType, 'score': float, 'per_term': {term:score} }
90
- """
91
- key_weight = key_weight or {}
92
- best: Optional[Dict[str, Any]] = None
93
-
94
- for path, val in iter_values(obj):
95
- s = val
96
- if not isinstance(s, str):
97
- if coerce_non_strings:
98
- s = str(val)
99
- else:
100
- continue
101
-
102
- score, per_term = _score_string(s, terms, case_insensitive=case_insensitive, min_ratio=min_ratio)
103
- if score <= 0:
104
- continue
105
-
106
- # Apply path-based weight if any path segment matches a key in key_weight
107
- weight = 1.0
108
- for seg in path:
109
- if isinstance(seg, str) and seg in key_weight:
110
- weight *= key_weight[seg]
111
- weighted = score * weight
112
-
113
- cand = {'value': s, 'path': path, 'score': weighted, 'per_term': per_term}
114
- if best is None or weighted > best['score']:
115
- best = cand
116
- # Optional tie-breakers (prefer more terms matched, then shorter value)
117
- elif best is not None and abs(weighted - best['score']) < 1e-9:
118
- if len(per_term) > len(best['per_term']):
119
- best = cand
120
- elif len(per_term) == len(best['per_term']) and len(s) < len(best['value']):
121
- best = cand
122
-
123
- return best
124
-
125
- def top_k_matches(
126
- obj: JSONLike,
127
- *,
128
- terms: Iterable[str],
129
- k: int = 5,
130
- **kwargs
131
- ) -> List[Dict[str, Any]]:
132
- """Return top-k matches sorted by score desc."""
133
- items: List[Dict[str, Any]] = []
134
- for path, val in iter_values(obj):
135
- s = val if isinstance(val, str) else (str(val) if kwargs.get('coerce_non_strings') else None)
136
- if s is None:
137
- continue
138
- score, per_term = _score_string(s, terms,
139
- case_insensitive=kwargs.get('case_insensitive', True),
140
- min_ratio=kwargs.get('min_ratio', 0.6))
141
- if score <= 0:
142
- continue
143
- weight = 1.0
144
- for seg in path:
145
- if isinstance(seg, str) and kwargs.get('key_weight', {}).get(seg):
146
- weight *= kwargs['key_weight'][seg]
147
- items.append({'value': s, 'path': path, 'score': score * weight, 'per_term': per_term})
148
-
149
- items.sort(key=lambda d: d['score'], reverse=True)
150
- return items[:k]
@@ -1,105 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Any, Callable, Iterable, Iterator, List, Tuple, Union, Dict
3
- import re
4
-
5
- JSONLike = Union[dict, list, tuple, set, str, int, float, bool, None]
6
- PathType = Tuple[Union[str, int], ...] # ('window_title',) or ('tabs', 2, 'name'), etc.
7
-
8
- def iter_values(obj: JSONLike, path: PathType = ()) -> Iterator[Tuple[PathType, Any]]:
9
- """
10
- Depth-first walk of nested dict/list/tuple/set. Yields (path, value) for every leaf.
11
- Path items are str (dict key) or int (list index).
12
- """
13
- if isinstance(obj, dict):
14
- for k, v in obj.items():
15
- yield from iter_values(v, path + (k,))
16
- elif isinstance(obj, (list, tuple)):
17
- for i, v in enumerate(obj):
18
- yield from iter_values(v, path + (i,))
19
- elif isinstance(obj, set):
20
- for v in obj:
21
- # sets are unordered/no index – use a pseudo-key
22
- yield from iter_values(v, path + ('<setitem>',))
23
- else:
24
- # leaf (scalar)
25
- yield path, obj
26
-
27
- def _mk_predicate(
28
- terms: Iterable[str] | None = None,
29
- *,
30
- case_insensitive: bool = True,
31
- substring: bool = True,
32
- regex: bool = False
33
- ) -> Callable[[Any], bool]:
34
- """
35
- Build a predicate that checks a scalar value against terms.
36
- """
37
- terms = list(terms or [])
38
- if regex:
39
- flags = re.IGNORECASE if case_insensitive else 0
40
- patterns = [re.compile(t, flags) for t in terms]
41
- def pred(value: Any) -> bool:
42
- if not isinstance(value, str):
43
- return False
44
- return any(p.search(value) for p in patterns)
45
- return pred
46
-
47
- # string contains (or equals)
48
- def pred(value: Any) -> bool:
49
- if not isinstance(value, str):
50
- return False
51
- v = value.lower() if case_insensitive else value
52
- for t in terms:
53
- t2 = t.lower() if case_insensitive else t
54
- if (t2 in v) if substring else (t2 == v):
55
- return True
56
- return False
57
-
58
- return pred
59
-
60
- def search_values(
61
- obj: JSONLike,
62
- *,
63
- terms: Iterable[str],
64
- case_insensitive: bool = True,
65
- substring: bool = True,
66
- regex: bool = False,
67
- ) -> List[Tuple[PathType, Any]]:
68
- """
69
- Return all (path, value) where value matches any term.
70
- """
71
- pred = _mk_predicate(terms, case_insensitive=case_insensitive, substring=substring, regex=regex)
72
- results: List[Tuple[PathType, Any]] = []
73
- for p, v in iter_values(obj):
74
- if pred(v):
75
- results.append((p, v))
76
- return results
77
-
78
- def any_match(
79
- obj: JSONLike,
80
- *,
81
- terms: Iterable[str],
82
- **kw
83
- ) -> bool:
84
- """Fast boolean check."""
85
- pred = _mk_predicate(terms, **kw)
86
- for _, v in iter_values(obj):
87
- if pred(v):
88
- return True
89
- return False
90
- def get_first_match(obj: JSONLike, *, terms: Iterable[str], **kw) -> Optional[Any]:
91
- """Return just the first matching value, or None."""
92
- pred = _mk_predicate(terms, **kw)
93
- for _, v in iter_values(obj):
94
- if pred(v):
95
- return v
96
- return None
97
-
98
- def get_all_match(obj: JSONLike, *, terms: Iterable[str], **kw) -> List[Any]:
99
- """Return all matching values as a flat list."""
100
- pred = _mk_predicate(terms, **kw)
101
- results: List[Any] = []
102
- for _, v in iter_values(obj):
103
- if pred(v):
104
- results.append(v)
105
- return results
@@ -1,3 +0,0 @@
1
- from .imports import *
2
- from .abstractEnv import *
3
- from .envy_it import *