abstract-utilities 0.2.2.513__py3-none-any.whl → 0.2.2.627__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 (73) hide show
  1. abstract_utilities/__init__.py +11 -3
  2. abstract_utilities/class_utils/caller_utils.py +19 -0
  3. abstract_utilities/class_utils/global_utils.py +35 -20
  4. abstract_utilities/class_utils/imports/imports.py +1 -1
  5. abstract_utilities/directory_utils/__init__.py +2 -4
  6. abstract_utilities/directory_utils/imports/__init__.py +2 -0
  7. abstract_utilities/directory_utils/imports/imports.py +1 -0
  8. abstract_utilities/directory_utils/imports/module_imports.py +2 -0
  9. abstract_utilities/directory_utils/src/__init__.py +4 -0
  10. abstract_utilities/directory_utils/src/directory_utils.py +110 -0
  11. abstract_utilities/directory_utils/src/name_utils.py +43 -0
  12. abstract_utilities/directory_utils/src/size_utils.py +57 -0
  13. abstract_utilities/directory_utils/src/utils.py +116 -0
  14. abstract_utilities/file_utils/imports/constants.py +81 -7
  15. abstract_utilities/file_utils/imports/imports.py +0 -4
  16. abstract_utilities/file_utils/imports/module_imports.py +1 -1
  17. abstract_utilities/file_utils/src/__init__.py +2 -4
  18. abstract_utilities/file_utils/src/file_filters/__init__.py +4 -0
  19. abstract_utilities/file_utils/src/file_filters/ensure_utils.py +118 -0
  20. abstract_utilities/file_utils/src/file_filters/filter_params.py +86 -0
  21. abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
  22. abstract_utilities/file_utils/src/file_filters/predicate_utils.py +116 -0
  23. abstract_utilities/file_utils/src/file_filters.py +114 -47
  24. abstract_utilities/file_utils/src/file_reader.py +0 -64
  25. abstract_utilities/file_utils/src/file_utils.py +7 -130
  26. abstract_utilities/file_utils/src/filter_params.py +128 -86
  27. abstract_utilities/file_utils/src/find_collect.py +85 -165
  28. abstract_utilities/file_utils/src/find_content.py +210 -0
  29. abstract_utilities/file_utils/src/initFunctionsGen.py +35 -28
  30. abstract_utilities/file_utils/src/initFunctionsGens.py +280 -0
  31. abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
  32. abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
  33. abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
  34. abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
  35. abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
  36. abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
  37. abstract_utilities/file_utils (2)/__init__.py +2 -0
  38. abstract_utilities/file_utils (2)/imports/__init__.py +2 -0
  39. abstract_utilities/file_utils (2)/imports/constants.py +118 -0
  40. abstract_utilities/file_utils (2)/imports/imports/__init__.py +3 -0
  41. abstract_utilities/file_utils (2)/imports/imports/constants.py +119 -0
  42. abstract_utilities/file_utils (2)/imports/imports/imports.py +46 -0
  43. abstract_utilities/file_utils (2)/imports/imports/module_imports.py +8 -0
  44. abstract_utilities/file_utils (2)/imports/utils/__init__.py +3 -0
  45. abstract_utilities/file_utils (2)/imports/utils/classes.py +379 -0
  46. abstract_utilities/file_utils (2)/imports/utils/clean_imps.py +155 -0
  47. abstract_utilities/file_utils (2)/imports/utils/filter_utils.py +341 -0
  48. abstract_utilities/file_utils (2)/src/__init__.py +8 -0
  49. abstract_utilities/file_utils (2)/src/file_filters.py +155 -0
  50. abstract_utilities/file_utils (2)/src/file_reader.py +604 -0
  51. abstract_utilities/file_utils (2)/src/find_collect.py +258 -0
  52. abstract_utilities/file_utils (2)/src/initFunctionsGen.py +286 -0
  53. abstract_utilities/file_utils (2)/src/map_utils.py +28 -0
  54. abstract_utilities/file_utils (2)/src/pdf_utils.py +300 -0
  55. abstract_utilities/import_utils/circular_import_finder.py +222 -0
  56. abstract_utilities/import_utils/circular_import_finder2.py +118 -0
  57. abstract_utilities/import_utils/imports/module_imports.py +3 -1
  58. abstract_utilities/import_utils/src/clean_imports.py +156 -25
  59. abstract_utilities/import_utils/src/dot_utils.py +11 -0
  60. abstract_utilities/import_utils/src/extract_utils.py +4 -0
  61. abstract_utilities/import_utils/src/import_functions.py +66 -2
  62. abstract_utilities/import_utils/src/pkg_utils.py +58 -4
  63. abstract_utilities/import_utils/src/sysroot_utils.py +56 -1
  64. abstract_utilities/log_utils/log_file.py +73 -24
  65. abstract_utilities/parse_utils/parse_utils.py +23 -0
  66. abstract_utilities/path_utils/path_utils.py +25 -23
  67. abstract_utilities/read_write_utils/imports/imports.py +1 -1
  68. abstract_utilities/read_write_utils/read_write_utils.py +99 -31
  69. abstract_utilities/safe_utils/safe_utils.py +30 -0
  70. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.627.dist-info}/METADATA +1 -1
  71. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.627.dist-info}/RECORD +73 -32
  72. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.627.dist-info}/WHEEL +0 -0
  73. {abstract_utilities-0.2.2.513.dist-info → abstract_utilities-0.2.2.627.dist-info}/top_level.txt +0 -0
@@ -1,79 +1,15 @@
1
1
  from ..imports import *
2
- from .filter_params import *
3
- from .file_filters import enumerate_source_files
2
+ from .file_filters import *
4
3
  from pathlib import Path
5
4
  from typing import Optional, List, Set
6
5
 
7
- def check_path_type(
8
- path: str,
9
- user: Optional[str] = None,
10
- host: Optional[str] = None,
11
- user_as_host: Optional[str] = None,
12
- use_shell: bool = False
13
- ) -> Literal["file", "directory", "missing", "unknown"]:
14
- """
15
- Determine whether a given path is a file, directory, or missing.
16
- Works locally or remotely (via SSH).
17
6
 
18
- Args:
19
- path: The path to check.
20
- user, host, user_as_host: SSH parameters if remote.
21
- use_shell: Force shell test instead of Python os.path.
22
- Returns:
23
- One of: 'file', 'directory', 'missing', or 'unknown'
24
- """
25
-
26
- # --- remote check if user/host is given ---
27
- if user_as_host or (user and host):
28
- remote_target = user_as_host or f"{user}@{host}"
29
- cmd = f"if [ -f '{path}' ]; then echo file; elif [ -d '{path}' ]; then echo directory; else echo missing; fi"
30
- try:
31
- result = subprocess.check_output(
32
- ["ssh", remote_target, cmd],
33
- stderr=subprocess.DEVNULL,
34
- text=True,
35
- timeout=5
36
- ).strip()
37
- return result if result in ("file", "directory", "missing") else "unknown"
38
- except Exception:
39
- return "unknown"
40
-
41
- # --- local check ---
42
- if not use_shell:
43
- if os.path.isfile(path):
44
- return "file"
45
- elif os.path.isdir(path):
46
- return "directory"
47
- elif not os.path.exists(path):
48
- return "missing"
49
- return "unknown"
50
- else:
51
- # fallback using shell tests (useful for sandboxed contexts)
52
- cmd = f"if [ -f '{path}' ]; then echo file; elif [ -d '{path}' ]; then echo directory; else echo missing; fi"
53
- try:
54
- output = subprocess.check_output(
55
- cmd, shell=True, stderr=subprocess.DEVNULL, text=True
56
- ).strip()
57
- return output if output in ("file", "directory", "missing") else "unknown"
58
- except Exception:
59
- return "unknown"
60
7
 
61
8
 
62
9
 
63
10
 
64
11
  def get_find_cmd(
65
- directory: str,
66
- *,
67
- cfg: Optional["ScanConfig"] = None,
68
- *,
69
- allowed_exts: Optional[Set[str]] = False,
70
- unallowed_exts: Optional[Set[str]] = False,
71
- allowed_types: Optional[Set[str]] = False,
72
- exclude_types: Optional[Set[str]] = False,
73
- allowed_dirs: Optional[List[str]] = False,
74
- exclude_dirs: Optional[List[str]] = False,
75
- allowed_patterns: Optional[List[str]] = False,
76
- exclude_patterns: Optional[List[str]] = False,
12
+ *args,
77
13
  mindepth: Optional[int] = None,
78
14
  maxdepth: Optional[int] = None,
79
15
  depth: Optional[int] = None,
@@ -86,14 +22,23 @@ def get_find_cmd(
86
22
  **kwargs
87
23
  ) -> str:
88
24
  """
89
- Construct a Unix `find` command string from cfg and explicit keyword args.
90
-
91
- - Honors allowed/excluded patterns, dirs, and extensions from ScanConfig.
92
- - Automatically applies mindepth/maxdepth/depth/file_type filters.
25
+ Construct a Unix `find` command string that supports multiple directories.
26
+ Accepts filtering via ScanConfig-compatible kwargs.
93
27
  """
94
- cmd = [f"find {shlex.quote(directory)}"]
28
+ # Normalize inputs into canonical form
29
+ kwargs = get_safe_canonical_kwargs(*args, **kwargs)
30
+ cfg = kwargs.get('cfg') or define_defaults(**kwargs)
95
31
 
96
- # --- depth ---
32
+ # Get directory list (may come from args or kwargs)
33
+ kwargs["directories"] = ensure_directories(*args, **kwargs)
34
+ if not kwargs["directories"]:
35
+ return []
36
+
37
+ # Build base command for all directories
38
+ dir_expr = " ".join(shlex.quote(d) for d in kwargs["directories"])
39
+ cmd = [f"find {dir_expr}"]
40
+
41
+ # --- depth filters ---
97
42
  if depth is not None:
98
43
  cmd += [f"-mindepth {depth}", f"-maxdepth {depth}"]
99
44
  else:
@@ -106,7 +51,7 @@ def get_find_cmd(
106
51
  if file_type in ("f", "d"):
107
52
  cmd.append(f"-type {file_type}")
108
53
 
109
- # --- base attributes ---
54
+ # --- basic attributes ---
110
55
  if name:
111
56
  cmd.append(f"-name {shlex.quote(name)}")
112
57
  if size:
@@ -117,63 +62,53 @@ def get_find_cmd(
117
62
  cmd.append(f"-perm {shlex.quote(perm)}")
118
63
  if user:
119
64
  cmd.append(f"-user {shlex.quote(user)}")
120
- cfg = cfg or define_defaults(
121
- allowed_exts = allowed_exts,
122
- unallowed_exts = unallowed_exts,
123
- allowed_types = allowed_types,
124
- exclude_types = exclude_types,
125
- allowed_dirs = allowed_dirs,
126
- exclude_dirs = exclude_dirs,
127
- allowed_patterns = allowed_patterns,
128
- exclude_patterns = exclude_patterns,
129
- add = add
130
- )
65
+
131
66
  # --- cfg-based filters ---
132
67
  if cfg:
133
- # allowed extensions
68
+ # Allowed extensions
134
69
  if cfg.allowed_exts and cfg.allowed_exts != {"*"}:
135
70
  ext_expr = " -o ".join(
136
71
  [f"-name '*{e}'" for e in cfg.allowed_exts if e]
137
72
  )
138
73
  cmd.append(f"\\( {ext_expr} \\)")
139
74
 
140
- # disallowed extensions
141
- if cfg.unallowed_exts:
142
- for e in cfg.unallowed_exts:
75
+ # Excluded extensions
76
+ if cfg.exclude_exts:
77
+ for e in cfg.exclude_exts:
143
78
  cmd.append(f"! -name '*{e}'")
144
79
 
145
- # allowed directories (match any path)
80
+ # Allowed directories
146
81
  if cfg.allowed_dirs and cfg.allowed_dirs != ["*"]:
147
82
  dir_expr = " -o ".join(
148
83
  [f"-path '*{d}*'" for d in cfg.allowed_dirs if d]
149
84
  )
150
85
  cmd.append(f"\\( {dir_expr} \\)")
151
86
 
152
- # exclude directories
87
+ # Excluded directories
153
88
  if cfg.exclude_dirs:
154
89
  for d in cfg.exclude_dirs:
155
90
  cmd.append(f"! -path '*{d}*'")
156
91
 
157
- # allowed patterns
92
+ # Allowed patterns
158
93
  if cfg.allowed_patterns and cfg.allowed_patterns != ["*"]:
159
94
  pat_expr = " -o ".join(
160
95
  [f"-name '{p}'" for p in cfg.allowed_patterns if p]
161
96
  )
162
97
  cmd.append(f"\\( {pat_expr} \\)")
163
98
 
164
- # exclude patterns
99
+ # Excluded patterns
165
100
  if cfg.exclude_patterns:
166
101
  for p in cfg.exclude_patterns:
167
102
  cmd.append(f"! -name '{p}'")
168
103
 
169
- # allowed types
104
+ # Allowed types (semantic, not `-type`)
170
105
  if cfg.allowed_types and cfg.allowed_types != {"*"}:
171
106
  type_expr = " -o ".join(
172
107
  [f"-path '*{t}*'" for t in cfg.allowed_types if t]
173
108
  )
174
109
  cmd.append(f"\\( {type_expr} \\)")
175
110
 
176
- # excluded types
111
+ # Excluded types
177
112
  if cfg.exclude_types:
178
113
  for t in cfg.exclude_types:
179
114
  cmd.append(f"! -path '*{t}*'")
@@ -183,24 +118,12 @@ def get_find_cmd(
183
118
 
184
119
 
185
120
  def collect_globs(
186
- directory: str,
187
- cfg: Optional["ScanConfig"] = None,
188
- *,
189
- allowed_exts: Optional[Set[str]] = False,
190
- unallowed_exts: Optional[Set[str]] = False,
191
- allowed_types: Optional[Set[str]] = False,
192
- exclude_types: Optional[Set[str]] = False,
193
- allowed_dirs: Optional[List[str]] = False,
194
- exclude_dirs: Optional[List[str]] = False,
195
- allowed_patterns: Optional[List[str]] = False,
196
- exclude_patterns: Optional[List[str]] = False,
197
- patterns: Optional[List[str]] = None,
121
+ *args,
198
122
  mindepth: Optional[int] = None,
199
123
  maxdepth: Optional[int] = None,
200
124
  depth: Optional[int] = None,
201
125
  file_type: Optional[str] = None, # "f", "d", or None
202
- user_at_host: Optional[str] = None,
203
- add: bool = False,
126
+ allowed: Optional[Callable[[str], bool]] = None,
204
127
  **kwargs
205
128
  ) -> List[str] | dict:
206
129
  """
@@ -210,61 +133,58 @@ def collect_globs(
210
133
  - If file_type is "f" or "d" → returns a list of that type
211
134
  - Supports SSH mode via `user_at_host`
212
135
  """
213
- cfg = cfg or define_defaults(
214
- allowed_exts = allowed_exts,
215
- unallowed_exts = unallowed_exts,
216
- allowed_types = allowed_types,
217
- exclude_types = exclude_types,
218
- allowed_dirs = allowed_dirs,
219
- exclude_dirs = exclude_dirs,
220
- allowed_patterns = allowed_patterns,
221
- exclude_patterns = exclude_patterns,
222
- add = add
223
- )
224
- allowed = allowed or make_allowed_predicate(cfg)
225
- directory = str(directory)
226
-
227
- # Remote path (SSH)
228
- if user_at_host:
136
+ user_pass_host_key = get_user_pass_host_key(**kwargs)
137
+ kwargs["directories"] = ensure_directories(*args, **kwargs)
138
+ kwargs= get_safe_canonical_kwargs(**kwargs)
139
+ kwargs["cfg"] = kwargs.get('cfg') or define_defaults(**kwargs)
140
+
141
+ type_strs = {"f":"files","d":"dirs"}
142
+ file_type = get_proper_type_str(file_type)
143
+ file_types = make_list(file_type)
144
+ if file_type == None:
145
+ file_types = ["f","d"]
146
+ return_results = {}
147
+ return_result=[]
148
+ for file_type in file_types:
149
+ type_str = type_strs.get(file_type)
150
+ # Remote path (SSH)
229
151
  find_cmd = get_find_cmd(
230
- directory,
231
- cfg=cfg,
232
- mindepth=mindepth,
233
- maxdepth=maxdepth,
234
- depth=depth,
235
- file_type=file_type,
236
- **{k: v for k, v in kwargs.items() if v},
237
- )
238
- return run_cmd(find_cmd, user_at_host=user_at_host)
239
-
240
- # Local path (Python-native walk)
241
- root = Path(directory)
242
- results_js = {"f": [], "d": []}
243
-
244
- for p in root.rglob("*"):
245
- if p.is_file():
246
- kind = "f"
247
- elif p.is_dir():
248
- kind = "d"
249
- else:
250
- continue
251
-
252
- # If file_type is specified, skip the other kind
253
- if file_type and kind != file_type:
254
- continue
255
-
256
- if exts and kind == "f" and p.suffix.lower() not in exts:
257
- continue
258
-
259
- if patterns and not any(p.match(pat) for pat in patterns):
260
- continue
261
-
262
- results_js[kind].append(str(p))
263
-
264
- # Return based on selection
265
- if file_type is None:
266
- return results_js
267
- else:
268
- return results_js[file_type]
269
-
270
-
152
+ directories=kwargs.get("directories"),
153
+ cfg=kwargs.get('cfg'),
154
+ mindepth=mindepth,
155
+ maxdepth=maxdepth,
156
+ depth=depth,
157
+ file_type=file_type,
158
+ **user_pass_host_key,
159
+ )
160
+ result = run_pruned_func(run_cmd,find_cmd,
161
+ **kwargs
162
+
163
+ )
164
+ return_result = [res for res in result.split('\n') if res]
165
+ return_results[type_str]=return_result
166
+ if len(file_types) == 1:
167
+ return return_result
168
+ return return_results
169
+ def get_files_and_dirs(
170
+ *args,
171
+ recursive: bool = True,
172
+ include_files: bool = True,
173
+ **kwargs
174
+ ):
175
+ if recursive == False:
176
+ kwargs['maxdepth']=1
177
+ if include_files == False:
178
+ kwargs['file_type']='d'
179
+ result = collect_globs(*args,**kwargs)
180
+ if include_files == False:
181
+ return result,[]
182
+ dirs = result.get("dirs")
183
+ files = result.get("files")
184
+ return dirs,files
185
+ def collect_filepaths(
186
+ *args,
187
+ **kwargs
188
+ ) -> List[str]:
189
+ kwargs['file_type']='f'
190
+ return collect_globs(*args,**kwargs)
@@ -0,0 +1,210 @@
1
+ from .file_filters import *
2
+ from .reader_utils import *
3
+ from .find_collect import *
4
+ STOP_SEARCH = False
5
+
6
+ def request_find_console_stop():
7
+ global STOP_SEARCH
8
+ STOP_SEARCH = True
9
+
10
+ def reset_find_console_stop():
11
+ global STOP_SEARCH
12
+ STOP_SEARCH = False
13
+
14
+ def get_contents(
15
+ full_path=None,
16
+ parse_lines=False,
17
+ content=None
18
+ ):
19
+ if full_path:
20
+ content = content or read_any_file(full_path)
21
+ if content:
22
+ if parse_lines:
23
+ content = str(content).split('\n')
24
+ return make_list(content)
25
+ return []
26
+
27
+ def _normalize(s: str, strip_comments=True, collapse_ws=True, lower=True):
28
+ if s is None:
29
+ return ""
30
+ if strip_comments:
31
+ s = s.split('//', 1)[0]
32
+ if collapse_ws:
33
+ s = re.sub(r'\s+', ' ', s)
34
+ if lower:
35
+ s = s.lower()
36
+ return s.strip()
37
+
38
+ def stringInContent(content, strings, total_strings=False, normalize=False):
39
+ if not content:
40
+ return False
41
+ if normalize:
42
+ c = _normalize(str(content))
43
+
44
+ found = [s for s in strings if _normalize(s) and _normalize(s) in c]
45
+ else:
46
+ c = str(content)
47
+ found = [s for s in strings if s and s in c]
48
+ if not found:
49
+ return False
50
+ return len(found) == len(strings) if total_strings else True
51
+ def find_file(content, spec_line, strings, total_strings=False):
52
+ lines = content.split('\n')
53
+ if 1 <= spec_line <= len(lines):
54
+ return stringInContent(lines[spec_line - 1], strings, total_strings=total_strings)
55
+ return False
56
+ def find_lines(content, strings, total_strings=False, normalize=True, any_per_line=True):
57
+ lines = content.split('\n')
58
+ hits = []
59
+ for i, line in enumerate(lines):
60
+ # match one line either if ANY string matches or if ALL match (configurable)
61
+ if any_per_line:
62
+ match = stringInContent(line, strings, total_strings=False, normalize=normalize)
63
+ else:
64
+ match = stringInContent(line, strings, total_strings=True, normalize=normalize)
65
+ if match:
66
+ hits.append({"line": i+1, "content": line})
67
+ return hits
68
+ def getPaths(files, strings):
69
+ tot_strings = strings
70
+ nu_files, found_paths = [], []
71
+ if isinstance(strings,list):
72
+ if len(strings) >1:
73
+ tot_strings = '\n'.join(strings)
74
+ else:
75
+ if len(strings) == 0:
76
+ return nu_files, found_paths
77
+ tot_strings = strings[0]
78
+
79
+
80
+ for file_path in files:
81
+ try:
82
+ og_content = read_any_file(file_path)
83
+ if tot_strings not in og_content:
84
+ continue
85
+ if file_path not in nu_files:
86
+ nu_files.append(file_path)
87
+ ogLines = og_content.split('\n')
88
+ # find all occurrences of the block
89
+ for m in re.finditer(re.escape(tot_strings), og_content):
90
+ start_line = og_content[:m.start()].count('\n') + 1 # 1-based
91
+ curr = {'file_path': file_path, 'lines': []}
92
+ for j in range(len(strings)):
93
+ ln = start_line + j
94
+ curr['lines'].append({'line': ln, 'content': ogLines[ln - 1]})
95
+ found_paths.append(curr)
96
+ except Exception as e:
97
+ print(f"{e}")
98
+ return nu_files, found_paths
99
+
100
+ def findContent(
101
+ *args,
102
+ strings: list=[],
103
+ total_strings=True,
104
+ parse_lines=False,
105
+ spec_line=False,
106
+ get_lines=True,
107
+ diffs=False,
108
+ **kwargs
109
+ ):
110
+ global STOP_SEARCH
111
+ kwargs["directories"] = ensure_directories(*args,**kwargs)
112
+
113
+ found_paths = []
114
+
115
+ dirs, files = get_files_and_dirs(
116
+ **kwargs
117
+ )
118
+ nu_files, found_paths = getPaths(files, strings)
119
+
120
+ if diffs and found_paths:
121
+ return found_paths
122
+
123
+ for file_path in nu_files:
124
+ if STOP_SEARCH:
125
+ return found_paths # early exit
126
+
127
+ if file_path:
128
+ og_content = read_any_file(file_path)
129
+ contents = get_contents(
130
+ file_path,
131
+ parse_lines=parse_lines,
132
+ content=og_content
133
+ )
134
+ found = False
135
+ for content in contents:
136
+ if STOP_SEARCH:
137
+ return found_paths # bail out cleanly
138
+
139
+ if stringInContent(content, strings, total_strings=True, normalize=True):
140
+ found = True
141
+ if spec_line:
142
+ found = find_file(og_content, spec_line, strings, total_strings=True)
143
+ if found:
144
+ if get_lines:
145
+ lines = find_lines(
146
+ og_content,
147
+ strings=strings,
148
+ total_strings=False,
149
+ normalize=True,
150
+ any_per_line=True
151
+ )
152
+ if lines:
153
+ file_path = {"file_path": file_path, "lines": lines}
154
+ found_paths.append(file_path)
155
+ break
156
+ return found_paths
157
+ def return_function(start_dir=None,preferred_dir=None,basenames=None,functionName=None):
158
+ if basenames:
159
+ basenames = make_list(basenames)
160
+ abstract_file_finder = AbstractFileFinderImporter(start_dir=start_dir,preferred_dir=preferred_dir)
161
+ paths = abstract_file_finder.find_paths(basenames)
162
+ func = abstract_file_finder.import_function_from_path(paths[0], functionName)
163
+ return func
164
+ def getLineNums(file_path):
165
+ lines=[]
166
+ if file_path and isinstance(file_path,dict):
167
+ lines = file_path.get('lines')
168
+ file_path = file_path.get('file_path')
169
+ return file_path,lines
170
+ def get_line_content(obj):
171
+ line,content=None,None
172
+ if obj and isinstance(obj,dict):
173
+ line=obj.get('line')
174
+ content = obj.get('content')
175
+ #print(f"line: {line}\ncontent: {content}")
176
+ return line,content
177
+ def get_edit(file_path):
178
+ if file_path and os.path.isfile(file_path):
179
+ os.system(f"code {file_path}")
180
+ input()
181
+ def editLines(file_paths):
182
+ for file_path in file_paths:
183
+ file_path,lines = getLineNums(file_path)
184
+ for obj in lines:
185
+ line,content = get_line_content(obj)
186
+ get_edit(file_path)
187
+ def findContentAndEdit(*args,
188
+ strings: list=[],
189
+ total_strings=True,
190
+ parse_lines=False,
191
+ spec_line=False,
192
+ get_lines=True,
193
+ edit_lines=False,
194
+ diffs=False,
195
+ **kwargs
196
+ ):
197
+ file_paths = findContent(
198
+ *args,
199
+ strings=strings,
200
+ total_strings=total_strings,
201
+ parse_lines=parse_lines,
202
+ spec_line=spec_line,
203
+ get_lines=get_lines,
204
+ diffs=diffs,
205
+ **kwargs
206
+ )
207
+ if edit_lines:
208
+ editLines(file_paths)
209
+ return file_paths
210
+
@@ -1,10 +1,11 @@
1
1
  # attach_functions.py — single helper you can import anywhere
2
2
  # attach_dynamic.py
3
3
  from __future__ import annotations
4
- from .file_utils import define_defaults,get_files_and_dirs
4
+ from .find_collect import get_files_and_dirs
5
5
  from ..imports import *
6
6
  ABSPATH = os.path.abspath(__file__)
7
7
  ABSROOT = os.path.dirname(ABSPATH)
8
+
8
9
  def caller_path():
9
10
  frame = inspect.stack()[1]
10
11
  return os.path.abspath(frame.filename)
@@ -210,33 +211,37 @@ def get_for_all_tabs(root = None):
210
211
  root = root or caller_path()
211
212
  if os.path.isfile(root):
212
213
  root = os.path.dirname(root)
213
- all_tabs = get_dirs(root = root)
214
+ all_tabs = get_files_and_dirs(root,allowed_patterns='*Tab')[0]
215
+
214
216
  for ROOT in all_tabs:
215
- FUNCS_DIR = ifFunctionsInFile(ROOT)
216
- if FUNCS_DIR == None:
217
- for ROOT in get_dirs(root = ROOT):
218
- apply_inits(ROOT)
219
- else:
220
- apply_inits(ROOT)
217
+ if os.path.isdir(ROOT):
218
+ [apply_inits(os.path.join(ROOT,func)) for func in os.listdir(ROOT) if 'functions' == os.path.splitext(func)[0]]
219
+
220
+
221
221
 
222
222
 
223
223
  def apply_inits(ROOT):
224
- FUNCS_DIR = ifFunctionsInFile(ROOT)
225
-
226
-
227
- if_fun_dir = isDir(FUNCS_DIR)
228
- if if_fun_dir != None:
229
-
230
- if if_fun_dir:
231
- CFG = define_defaults(allowed_exts='.py',
232
- unallowed_exts = True,
233
- exclude_types = True,
234
- exclude_dirs = True,
235
- exclude_patterns = True)
236
- _,filepaths = get_files_and_dirs(FUNCS_DIR,cfg=CFG)
224
+ filepaths=[ROOT]
225
+ TAB_DIR = os.path.dirname(ROOT)
226
+ INIT_FUNCS_PAPTH = os.path.join(TAB_DIR, "initFuncs.py")
227
+ if_fun_dir=False
228
+ ## if os.path.isfile(ROOT):
229
+ ## dirname= os.path.dirname(ROOT)
230
+ ## basename= os.path.basename(ROOT)
231
+ ## functions_dir = os.path.join(dirname,'functions')
232
+ ## functions_path = os.path.join(functions_dir,basename)
233
+ ## input(get_clean_imports(ROOT))
234
+ ##
235
+ ## os.makedirs(functions_dir,exist_ok=True)
236
+ ## shutil.move(ROOT,functions_path)
237
+ ## ROOT=functions_dir
238
+ if os.path.isdir(ROOT):
239
+ INIT_PATH = os.path.join(ROOT, "__init__.py")
237
240
 
238
- else:
239
- filepaths = [FUNCS_DIR]
241
+ filepaths = get_files_and_dirs(directory=ROOT,allowed_exts='py',add=True)[-1]
242
+ if_fun_dir=True
243
+
244
+
240
245
 
241
246
  # Parse top-level def names
242
247
  def extract_funcs(path: str):
@@ -246,7 +251,7 @@ def apply_inits(ROOT):
246
251
  if m:
247
252
  funcs.append(m.group(1))
248
253
  return funcs
249
-
254
+
250
255
  # Build functions/__init__.py that re-exports all discovered functions
251
256
  import_lines = []
252
257
  all_funcs = []
@@ -258,7 +263,7 @@ def apply_inits(ROOT):
258
263
  all_funcs.extend(funcs)
259
264
  if if_fun_dir:
260
265
  functions_init = "\n".join(import_lines) + ("\n" if import_lines else "")
261
- write_to_file(contents=functions_init, file_path=os.path.join(FUNCS_DIR, "__init__.py"))
266
+ write_to_file(contents=functions_init, file_path=INIT_PATH)
262
267
 
263
268
  # Prepare the tuple literal of function names for import + loop
264
269
  uniq_funcs = sorted(set(all_funcs))
@@ -267,9 +272,10 @@ def apply_inits(ROOT):
267
272
  # Generate apiConsole/initFuncs.py using the safer setattr-loop
268
273
  init_funcs_src = textwrap.dedent(f"""\
269
274
 
270
-
275
+
276
+ from abstract_utilities import get_logFile
271
277
  from .functions import ({func_tuple})
272
-
278
+ logger=get_logFile(__name__)
273
279
  def initFuncs(self):
274
280
  try:
275
281
  for f in ({func_tuple}):
@@ -279,8 +285,9 @@ def apply_inits(ROOT):
279
285
  return self
280
286
  """)
281
287
 
282
- write_to_file(contents=init_funcs_src, file_path=os.path.join(ROOT, "initFuncs.py"))
288
+ write_to_file(contents=init_funcs_src, file_path=INIT_FUNCS_PAPTH)
283
289
 
284
290
  def call_for_all_tabs():
285
291
  root = get_caller_dir(2)
292
+
286
293
  get_for_all_tabs(root)