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,118 @@
1
+ from abstract_utilities import *
2
+ import os
3
+ from collections import defaultdict
4
+
5
+ def get_path_or_init(pkg_info):
6
+ root_dirname = pkg_info.get("root_dirname")
7
+ pkg = pkg_info.get("pkg")
8
+ rel_path = pkg.replace('.', '/')
9
+ dirname = os.path.dirname(root_dirname)
10
+ pkg_path = os.path.join(dirname, rel_path)
11
+ pkg_py_path = f"{pkg_path}.py"
12
+ if os.path.isfile(pkg_py_path):
13
+ return pkg_py_path
14
+ pkg_init_path = os.path.join(pkg_path, '__init__.py')
15
+ if os.path.isdir(pkg_path) and os.path.isfile(pkg_init_path):
16
+ return pkg_init_path
17
+ # optional: silence instead of blocking input()
18
+ print(f"⚠️ not found == {pkg_info}")
19
+ return None
20
+
21
+
22
+ def get_dot_fro_line(line, dirname=None, file_path=None, get_info=False):
23
+ info_js = {"nuline": line, "og_line": line, "pkg": line, "dirname": dirname,
24
+ "file_path": file_path, "root_dirname": None, "local": False}
25
+ if dirname and is_file(dirname):
26
+ file_path = dirname
27
+ dirname = os.path.dirname(dirname)
28
+ info_js["file_path"] = file_path
29
+ info_js["dirname"] = dirname
30
+
31
+ from_line = line.split(FROM_TAG)[-1]
32
+ dot_fro = ""
33
+ for char in from_line:
34
+ if char != '.':
35
+ pkg = f"{dot_fro}{eatAll(from_line, '.')}"
36
+ nuline = f"from {pkg}"
37
+ info_js["nuline"] = nuline
38
+ info_js["pkg"] = pkg
39
+ break
40
+ if dirname:
41
+ info_js["root_dirname"] = dirname
42
+ dirbase = os.path.basename(dirname)
43
+ dirname = os.path.dirname(dirname)
44
+ dot_fro = f"{dirbase}.{dot_fro}"
45
+
46
+ if get_info:
47
+ if dot_fro and os.path.isdir(info_js.get("root_dirname") or ""):
48
+ info_js["local"] = True
49
+ info_js["pkg_path"] = get_path_or_init(info_js)
50
+ return info_js
51
+ return line
52
+
53
+
54
+ def return_local_imps(file_path):
55
+ local_imps = []
56
+ dirname = os.path.dirname(file_path)
57
+ imports_js = get_all_imports(file_path)
58
+ for pkg, imps in imports_js.items():
59
+ if pkg not in ['context', 'nulines']:
60
+ full_imp_info = get_dot_fro_line(pkg, dirname, file_path=file_path, get_info=True)
61
+ if full_imp_info.get("local"):
62
+ local_imps.append(full_imp_info)
63
+ return local_imps
64
+
65
+
66
+ def get_all_pkg_paths(file_path):
67
+ pkg_paths = []
68
+ local_imps = return_local_imps(file_path)
69
+ for local_imp in local_imps:
70
+ pkg_path = local_imp.get('pkg_path')
71
+ if pkg_path:
72
+ pkg_paths.append(pkg_path)
73
+ return pkg_paths
74
+
75
+
76
+ # --- NEW: Build dependency graph and detect circular imports ---
77
+
78
+ def build_graph(main_directory):
79
+ dirs, all_local_scripts = get_files_and_dirs(main_directory, allowd_exts='.py', files_only=True)
80
+ graph = defaultdict(set)
81
+ for file_path in all_local_scripts:
82
+ deps = get_all_pkg_paths(file_path)
83
+ for dep in deps:
84
+ if dep: # only valid files
85
+ graph[file_path].add(dep)
86
+ return graph
87
+
88
+
89
+ def find_cycles(graph):
90
+ visited, stack, cycles = set(), [], []
91
+
92
+ def dfs(node, path):
93
+ visited.add(node)
94
+ path.append(node)
95
+ for dep in graph.get(node, []):
96
+ if dep not in visited:
97
+ dfs(dep, path.copy())
98
+ elif dep in path:
99
+ cycle_start = path.index(dep)
100
+ cycles.append(path[cycle_start:] + [dep])
101
+
102
+ for node in graph:
103
+ if node not in visited:
104
+ dfs(node, [])
105
+ return cycles
106
+
107
+
108
+ if __name__ == "__main__":
109
+ main_directory = "/home/flerb/Documents/pythonTools/modules/src/modules/abstract_utilities/src/abstract_utilities"
110
+ graph = build_graph(main_directory)
111
+ cycles = find_cycles(graph)
112
+
113
+ if not cycles:
114
+ print("✅ No circular imports found.")
115
+ else:
116
+ print("❌ Circular imports detected:")
117
+ for cycle in cycles:
118
+ print(" → ".join(cycle))
@@ -0,0 +1,4 @@
1
+ from .imports import *
2
+ from .module_imports import *
3
+ from .constants import *
4
+ from .utils import *
@@ -0,0 +1,2 @@
1
+ IMPORT_TAG = 'import '
2
+ FROM_TAG = 'from '
@@ -0,0 +1,4 @@
1
+ from pathlib import Path
2
+ from typing import *
3
+ from types import MethodType
4
+ from ...imports import os, sys, importlib, os, inspect, re, hashlib
@@ -0,0 +1,8 @@
1
+ from ...read_write_utils import read_from_file,write_to_file,get_text_or_read
2
+ from ...string_utils import eatAll,eatInner,eatElse,clean_line
3
+ from ...class_utils import get_caller_path,get_caller_dir,if_none_default,get_initial_caller_dir
4
+ from ...list_utils import make_list
5
+ from ...path_utils import get_file_parts
6
+ from ...type_utils import is_number,make_list
7
+ from ...file_utils import collect_filepaths,collect_globs
8
+ from ...directory_utils import get_shortest_path,get_common_root
@@ -0,0 +1,30 @@
1
+ import os
2
+ from .constants import *
3
+
4
+ def is_line_import(line):
5
+ if line and (line.startswith(FROM_TAG) or line.startswith(IMPORT_TAG)):
6
+ return True
7
+ return False
8
+ def is_line_group_import(line):
9
+ if line and (line.startswith(FROM_TAG) and IMPORT_TAG in line):
10
+ return True
11
+ return False
12
+
13
+ def is_from_line_group(line):
14
+ if line and line.startswith(FROM_TAG) and IMPORT_TAG in line and '(' in line:
15
+ import_spl = line.split(IMPORT_TAG)[-1]
16
+ import_spl_clean = clean_line(line)
17
+ if not import_spl_clean.endswith(')'):
18
+ return True
19
+ return False
20
+ def get_unique_name(string,list_obj):
21
+ if isinstance(list_obj,dict):
22
+ list_obj = list(list_obj.keys())
23
+ if string in list_obj:
24
+ nustring = f"{string}"
25
+ for i in range(len(list_obj)):
26
+ nustring = f"{string}_{i}"
27
+ if nustring not in list_obj:
28
+ break
29
+ string = nustring
30
+ return string
@@ -0,0 +1,7 @@
1
+ from .clean_imports import *
2
+ from .dot_utils import *
3
+ from .extract_utils import *
4
+ from .import_utils import *
5
+ from .import_functions import *
6
+ from .pkg_utils import *
7
+ from .sysroot_utils import *
@@ -0,0 +1,278 @@
1
+ from ..imports import *
2
+ from .pkg_utils import *
3
+ from ...safe_utils import *
4
+ def is_local_import(line):
5
+ print(line)
6
+ imports_from_import_pkg = clean_imports(line)
7
+ input(imports_from_import_pkg)
8
+ def try_is_file(file_path):
9
+ try:
10
+ return os.path.isfile(file_path)
11
+ except:
12
+ return False
13
+ def try_is_dir(file_path):
14
+ try:
15
+ return os.path.isdir(file_path)
16
+ except:
17
+ return False
18
+ def try_join(*args):
19
+ try:
20
+ return safe_join(*args)
21
+ except:
22
+ return False
23
+ def get_pkg_or_init(pkg_path):
24
+ if pkg_path:
25
+ if try_is_file(pkg_path):
26
+ return pkg_path
27
+ pkg_py_path = f"{pkg_path}.py"
28
+ if try_is_file(pkg_py_path):
29
+ return pkg_py_path
30
+ pkg_init_path = try_join(pkg_path,'__init__.py')
31
+ if try_is_dir(pkg_path):
32
+ if os.path.isfile(pkg_init_path):
33
+ return pkg_init_path
34
+ def get_text_and_file_and_js(text=None,file_path=None,import_pkg_js=None):
35
+ inputs = {"text":text,"file_path":file_path,"import_pkg_js":import_pkg_js}
36
+ for key,value in inputs.items():
37
+ if value:
38
+ if isinstance(value,str):
39
+ _file_path = get_pkg_or_init(file_path)
40
+ if _file_path:
41
+ file_path=_file_path
42
+ if key == "text" or text == None:
43
+ text=read_from_file(file_path)
44
+ if isinstance(value,dict):
45
+ if key in ["text","file_path"]:
46
+ if key == "text":
47
+ text = None
48
+ if key == "file_path":
49
+ file_path = None
50
+ import_pkg_js=value
51
+ import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
52
+ return text,file_path,import_pkg_js
53
+ def get_text_or_read(text=None,file_path=None):
54
+ file_path = get_pkg_or_init(file_path)
55
+ if not text and file_path:
56
+ text=read_from_file(file_path)
57
+ if text and not file_path:
58
+ file_path=get_pkg_or_init(text)
59
+ if file_path:
60
+ text = None
61
+ return text,file_path
62
+ def is_line_import(line):
63
+ if line and (line.startswith(FROM_TAG) or line.startswith(IMPORT_TAG)):
64
+ return True
65
+ return False
66
+ def is_line_group_import(line):
67
+ if line and (line.startswith(FROM_TAG) and IMPORT_TAG in line):
68
+ return True
69
+ return False
70
+
71
+ def is_from_line_group(line):
72
+ if line and line.startswith(FROM_TAG) and IMPORT_TAG in line and '(' in line:
73
+ import_spl = line.split(IMPORT_TAG)[-1]
74
+ import_spl_clean = clean_line(line)
75
+ if not import_spl_clean.endswith(')'):
76
+ return True
77
+ return False
78
+
79
+ def get_all_imports(text=None,file_path=None,import_pkg_js=None):
80
+ text,file_path = get_text_or_read(text=text,file_path=file_path)
81
+ lines = text.split('\n')
82
+ cleaned_import_list=[]
83
+ nu_lines = []
84
+ is_from_group = False
85
+ import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
86
+ for line in lines:
87
+
88
+ if line.startswith(IMPORT_TAG) and ' from ' not in line:
89
+
90
+ cleaned_import_list = get_cleaned_import_list(line)
91
+ import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js,file_path=file_path)
92
+ else:
93
+ if is_from_group:
94
+ import_pkg=is_from_group
95
+ line = clean_line(line)
96
+ if line.endswith(')'):
97
+ is_from_group=False
98
+ line=line[:-1]
99
+ imports_from_import_pkg = clean_imports(line)
100
+ import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports_from_import_pkg,import_pkg_js=import_pkg_js,file_path=file_path)
101
+
102
+ else:
103
+ import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js,file_path=file_path)
104
+ if is_from_line_group(line) and is_from_group == False:
105
+ is_from_group=get_import_pkg(line)
106
+ return import_pkg_js
107
+
108
+ def get_clean_imports(text=None,file_path=None,import_pkg_js=None,fill_nulines=False):
109
+ text,file_path,_ = get_text_and_file_and_js(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
110
+ if not import_pkg_js:
111
+ import_pkg_js = get_all_imports(text=text,file_path=file_path)
112
+ import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
113
+ nu_lines = import_pkg_js["context"]["nulines"]
114
+ for pkg,values in import_pkg_js.items():
115
+ comments = []
116
+ if pkg not in ["context"]:
117
+
118
+ imports = values.get('imports')
119
+ for i,imp in enumerate(imports):
120
+ if '#' in imp:
121
+ imp_spl = imp.split('#')
122
+ comments.append(imp_spl[-1])
123
+ imports[i] = clean_line(imp_spl[0])
124
+ imports = list(set(imports))
125
+ if '*' in imports:
126
+ imports="*"
127
+ else:
128
+ imports=','.join(imports)
129
+ if comments:
130
+ comments=','.join(comments)
131
+ imports+=f" #{comments}"
132
+ import_pkg_js[pkg]["imports"]=imports
133
+ if fill_nulines:
134
+ line = values.get('line')
135
+ if len(nu_lines) >= line:
136
+ nu_lines[line] += imports
137
+ return import_pkg_js
138
+ def clean_all_imports(text=None,file_path=None,import_pkg_js=None,fill_nulines=False):
139
+ import_pkg_js = get_clean_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js,fill_nulines=import_pkg_js)
140
+ import_pkg_js["context"]["nulines"]=import_pkg_js["context"]["nulines"]
141
+ return import_pkg_js
142
+ def get_clean_import_string(import_pkg_js,fill_nulines=False,get_locals=False):
143
+ import_pkg_js = get_clean_imports(import_pkg_js=import_pkg_js,fill_nulines=fill_nulines)
144
+ import_ls = []
145
+ for key,values in import_pkg_js.items():
146
+ if key not in ['context','nulines']:
147
+ imports = None
148
+ imp_values= values.get('imports')
149
+ if key == 'import':
150
+ imports = f'import {imp_values}'
151
+ elif get_locals or not key.startswith('.'):
152
+ imports = f'from {key} import {imp_values}'
153
+ if imports:
154
+ import_ls.append(imports)
155
+ return '\n'.join(import_ls)
156
+ def get_clean_imports_from_files(files):
157
+ import_pkg_js={}
158
+ for file in files:
159
+ import_pkg_js = get_all_imports(file,import_pkg_js=import_pkg_js)
160
+ return get_clean_import_string(import_pkg_js)
161
+ def get_dot_fro_line(line,dirname):
162
+ from_line = line.split(FROM_TAG)[-1]
163
+ dot_fro = ""
164
+ for char in from_line:
165
+ if char != '.':
166
+ line = f"from {dot_fro}{eatAll(from_line,'.')}"
167
+ break
168
+ dirname = os.path.dirname(dirname)
169
+ dirbase = os.path.basename(dirname)
170
+ dot_fro = f"{dirbase}.{dot_fro}"
171
+ return line
172
+ def get_dot_fro_lines(lines,file_path,all_imps):
173
+ for line in lines:
174
+ if line.startswith(FROM_TAG):
175
+ line = get_dot_fro_line(line,file_path)
176
+ if line in all_imps:
177
+ line = ""
178
+ if line:
179
+ all_imps.append(line)
180
+ return all_imps
181
+ def get_all_real_imps(text=None,file_path=None,all_imps=None):
182
+
183
+ all_imps = all_imps or []
184
+ text,file_path = get_text_or_read(text=text,file_path=file_path)
185
+ lines = text.split('\n')
186
+ all_imps = get_dot_fro_lines(lines,file_path,all_imps)
187
+ return '\n'.join(all_imps)
188
+ def save_cleaned_imports(text=None,file_path=None,write=False,import_pkg_js=None):
189
+ text,file_path,import_pkg_js = get_text_and_file_and_js(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
190
+ import_pkg_js = clean_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
191
+ contents = '\n'.join(import_pkg_js["context"]["nulines"])
192
+ if file_path and write:
193
+ write_to_file(contents=contents,file_path=file_path)
194
+ return contents
195
+ def convert_to_sysroot_relative(import_pkg, file_path, sysroot):
196
+ """
197
+ Convert an absolute package import into a dotted relative import based on
198
+ the file's depth inside sysroot.
199
+ """
200
+
201
+ if not sysroot:
202
+ return import_pkg # no conversion
203
+
204
+ file_path = os.path.abspath(file_path)
205
+ sysroot = os.path.abspath(sysroot)
206
+
207
+ # Ignore imports outside sysroot
208
+ file_dir = os.path.dirname(file_path)
209
+ if not file_dir.startswith(sysroot):
210
+ return import_pkg
211
+
212
+ # Compute how many directories deep the file is
213
+ rel = os.path.relpath(file_dir, sysroot)
214
+ depth = 0 if rel == "." else len(rel.split(os.sep))
215
+
216
+ # Depth N means N dots (i.e. N relative levels)
217
+ dots = "." * depth
218
+
219
+ return f"{dots}{import_pkg}"
220
+
221
+ import os
222
+
223
+ def rewrite_import_with_sysroot(line, file_path, sysroot):
224
+ """
225
+ Rewrite imports like:
226
+ from imports.constants import *
227
+ into:
228
+ from <relative_path>.imports.constants import *
229
+ Where <relative_path> is computed relative to sysroot.
230
+ """
231
+
232
+ line = line.rstrip()
233
+ if not line.startswith("from "):
234
+ return line
235
+
236
+ # Split import structure
237
+ try:
238
+ after_from = line[len("from "):]
239
+ pkg, after_import = after_from.split(" import ", 1)
240
+ except ValueError:
241
+ return line # Not a normal from X import Y
242
+
243
+ # Absolute paths
244
+ file_dir = os.path.dirname(os.path.abspath(file_path))
245
+ sysroot = os.path.abspath(sysroot)
246
+
247
+ # Compute relative path
248
+ relpath = os.path.relpath(file_dir, sysroot)
249
+
250
+ # Turn filesystem path into dotted python path
251
+ if relpath == ".":
252
+ dotted = ""
253
+ else:
254
+ dotted = ".".join(part for part in relpath.split(os.sep) if part)
255
+
256
+ # Import path you want to append the old import to
257
+ new_pkg = f"{dotted}.{pkg}".lstrip('.')
258
+
259
+ # Build final rewritten import
260
+ return f"from {new_pkg} import {after_import}"
261
+
262
+ def trace_all_imports(file_path, sysroot=None):
263
+ import_pkg_js = {}
264
+ files = collect_filepaths(file_path, allowed_exts='.py', add=True)
265
+
266
+ for file in files:
267
+ text = get_all_real_imps(file_path=file)
268
+ lines = text.split("\n")
269
+
270
+ if sysroot:
271
+ new_lines = []
272
+ for line in lines:
273
+ new_lines.append(rewrite_import_with_sysroot(line, file, sysroot))
274
+ text = "\n".join(new_lines)
275
+
276
+ import_pkg_js = get_all_imports(text=text, file_path=file, import_pkg_js=import_pkg_js)
277
+
278
+ return get_clean_import_string(import_pkg_js)
@@ -0,0 +1,80 @@
1
+ from ..imports import *
2
+ def find_top_package_dir(p: Path) -> Path | None:
3
+ p = p.resolve()
4
+ if p.is_file():
5
+ p = p.parent
6
+ top = None
7
+ while (p / "__init__.py").exists():
8
+ top = p
9
+ if p.parent == p:
10
+ break
11
+ p = p.parent
12
+ return top
13
+ def get_Path(path):
14
+ if isinstance(path,str):
15
+ path = Path(str(path))
16
+ return path
17
+ def get_dot_range(filepath=None,list_obj=None):
18
+ imports = make_list(list_obj) or extract_imports(filepath)
19
+ highest=0
20
+ dots = [get_imp(fro) for fro in imports if fro]
21
+
22
+ if dots:
23
+ dots.sort()
24
+ highest = dots[0]
25
+ return highest
26
+ def dotted_from(file: Path, sysroot: Path) -> str:
27
+ """
28
+ Build dotted name from sysroot (directory *above* top package)
29
+ e.g. /repo/abstract_ide/consoles/launcherWindowTab/functions/core_utils.py
30
+ sysroot=/repo -> abstract_ide.consoles.launcherWindowTab.functions.core_utils
31
+ """
32
+ file = get_Path(file)
33
+ sysroot = get_Path(sysroot)
34
+ file = file.resolve()
35
+ stem = file.with_suffix("") # drop .py
36
+ return ".".join(stem.relative_to(sysroot).parts)
37
+ def to_dotted_name(file_path: Path, top_package: str) -> str:
38
+ """
39
+ Convert .../abstract_ide/consoles/launcherWindowTab/functions/core_utils.py
40
+ -> abstract_ide.consoles.launcherWindowTab.functions.core_utils
41
+ """
42
+ # find the index of the top_package in the path parts
43
+ file_path = get_Path(file_path)
44
+ top_package = get_Path(top_package)
45
+ parts = file_path.resolve().parts
46
+ i = None
47
+ if is_number(top_package):
48
+ i= int(top_package)
49
+ if i is None:
50
+ try:
51
+ i = parts.index(top_package)
52
+ except ValueError:
53
+ raise RuntimeError(f"Cannot locate package '{top_package}' in {file_path}")
54
+ rel_parts = parts[i:] # from top_package onward
55
+ if rel_parts[-1].endswith(".py"):
56
+ rel_parts = list(rel_parts)
57
+ rel_parts[-1] = rel_parts[-1][:-3] # strip .py
58
+ return ".".join(rel_parts)
59
+ def compute_dotted_and_sysroot(file_path: Path) -> Tuple[str, Path]:
60
+ """
61
+ If inside packages, build dotted name from the top package down.
62
+ sysroot will be the directory *above* the top package.
63
+ If not a package, we fall back to a repo-ish root guess (2 parents up).
64
+ """
65
+ file_path = get_Path(file_path)
66
+ file_path = file_path.resolve()
67
+ stem = file_path.with_suffix("") # drop .py
68
+
69
+ top_pkg_dir = find_top_package_dir(file_path)
70
+ if top_pkg_dir:
71
+ sysroot = top_pkg_dir.parent
72
+ dotted = ".".join(stem.relative_to(sysroot).parts)
73
+ return dotted, sysroot
74
+
75
+ # Fallback: not in a package tree — guess a root a couple levels up
76
+ sysroot = file_path.parents[2]
77
+ dotted = ".".join(stem.relative_to(sysroot).parts)
78
+ return dotted, sysroot
79
+
80
+
@@ -0,0 +1,46 @@
1
+ from ..imports import *
2
+ def get_imp(line):
3
+ lis = [li for li in line.split(' ') if li and li.startswith('.')]
4
+ if lis and len(lis) >0:
5
+ lis = lis[0]
6
+ lis = len(lis) - len(eatInner(lis,['.']))
7
+ return lis
8
+ return 0
9
+ def extract_imports(path,strings=None):
10
+ strings = make_list(strings or ['from','import'])
11
+ funcs = []
12
+ lines = read_from_file(path).splitlines()
13
+ return [line for line in lines if [string for string in strings if string and eatAll(line,[' ','\n','\t']) and eatAll(line,[' ','\n','\t']).startswith(string)]]
14
+
15
+ def extract_froms(path: str):
16
+ funcs = []
17
+ for line in read_from_file(path).splitlines():
18
+ m = re.match(r"^from\s+([A-Za-z_]\w*)\s*", line)
19
+ if m:
20
+ funcs.append(m.group(1))
21
+ return funcs
22
+ def extract_selfs(path: str):
23
+ funcs = []
24
+ for line in read_from_file(path).splitlines():
25
+ m = re.match(r"^def\s+([A-Za-z_]\w*)\s*\(self", line)
26
+ if m:
27
+ funcs.append(m.group(1))
28
+ return funcs
29
+ def extract_funcs(path: str):
30
+ funcs = []
31
+ for line in read_from_file(path).splitlines():
32
+ m = re.match(r"^def\s+([A-Za-z_]\w*)\s*\(", line)
33
+ if m:
34
+ funcs.append(m.group(1))
35
+ return funcs
36
+ def extract_class(path: str):
37
+ funcs = []
38
+ for line in read_from_file(path).splitlines():
39
+ m = re.match(r"^class\s+([A-Za-z_]\w*)\s*\(", line) or re.match(r"^class\s+([A-Za-z_]\w*)\s*\:", line)
40
+ if m:
41
+ funcs.append(m.group(1))
42
+ return funcs
43
+ def get_all_py_file_paths(*args,**kwargs):
44
+ globs = collect_globs(*args,allowed_exts='.py',**kwargs)
45
+ globs = [glo for glo in globs.get('files') if glo]
46
+ return globs
@@ -0,0 +1,91 @@
1
+ # --- auto-package bootstrap (run-safe) ---------------------------------
2
+ from ..imports import *
3
+ from .dot_utils import get_dot_range
4
+ from .sysroot_utils import get_sysroot,get_import_with_sysroot,get_py_files,get_all_py_sysroots
5
+ from .extract_utils import get_all_py_file_paths
6
+ def clean_imports(imports,commaClean=True):
7
+ chars=["*"]
8
+ if not commaClean:
9
+ chars.append(',')
10
+ if isinstance(imports,str):
11
+ imports = imports.split(',')
12
+ return [eatElse(imp,chars=chars) for imp in imports if imp]
13
+ def get_dot_range(import_pkg):
14
+ count = 0
15
+ for char in import_pkg:
16
+ if char != '.':
17
+ break
18
+ count+=1
19
+ return count
20
+ def get_cleaned_import_list(line,commaClean=True):
21
+ cleaned_import_list=[]
22
+ if IMPORT_TAG in line:
23
+ imports = line.split(IMPORT_TAG)[1]
24
+ cleaned_import_list+=clean_imports(imports,commaClean=commaClean)
25
+ return cleaned_import_list
26
+ def get_module_from_import(imp,path=None):
27
+ path = path or os.getcwd()
28
+ i = get_dot_range(imp)
29
+ imp = eatAll(imp,'.')
30
+ sysroot = get_sysroot(path,i)
31
+ return os.path.join(sysroot, imp)
32
+
33
+ def safe_import(name: str, *, package: str | None = None, member: str | None = None, file: str | None = None):
34
+ """
35
+ Wrapper over importlib.import_module that:
36
+ - if `name` is relative (starts with '.'), ensures `package` is set.
37
+ - if `package` is missing, derives it from `file` (defaults to __file__).
38
+ """
39
+ file = file or __file__
40
+ ensure_package_context(file)
41
+ if name.startswith(".") and not package:
42
+
43
+
44
+ pkg_name = get_module_from_import(name,path=None)
45
+ # also set __package__ if we are running as a script
46
+ if __name__ == "__main__" and (not globals().get("__package__")):
47
+ globals()["__package__"] = pkg_name
48
+ package = pkg_name
49
+
50
+ mod = importlib.import_module(name, package=package)
51
+ return getattr(mod, member) if member else mod
52
+
53
+ def dynamic_import(module_path: str, namespace: dict, all_imports = None):
54
+ """
55
+ Emulates:
56
+ from module_path import *
57
+ but includes private (_xxx) names too.
58
+ """
59
+ all_imports = if_none_default(all_imports,True,typ=bool)
60
+ if module_path:
61
+ module = importlib.import_module(module_path)
62
+
63
+ # Import literally everything except dunders, unless you want them too.
64
+ names = [n for n in dir(module) if n and ((not all_imports and not n.startswith("_")) or all_imports)]
65
+
66
+
67
+ for name in names:
68
+ namespace[name] = getattr(module, name)
69
+
70
+ return module
71
+
72
+
73
+ def get_monorepo_root(directory=None,files=None):
74
+ directory = directory or get_initial_caller_dir()
75
+ py_files = get_all_py_file_paths(directory,add=True)
76
+ sysroots = get_all_py_sysroots(directory=directory,files=py_files)
77
+ monorepo_root = get_common_root(sysroots)
78
+ return monorepo_root
79
+ def switch_to_monorepo_root(directory=None,files=None):
80
+ monorepo_root = get_monorepo_root(directory=directory,files=files)
81
+ if str(monorepo_root) not in sys.path:
82
+ sys.path.insert(0, str(monorepo_root))
83
+ def get_all_imports(directory=None,sysroot=None):
84
+ sysroot = sysroot or get_initial_caller_dir()
85
+ directory = directory or sysroot
86
+ files = get_py_files(directory=directory)
87
+ switch_to_monorepo_root(directory=directory,files=files)
88
+ for glo in [glo for glo in globs.get('files') if glo]:
89
+ imp = get_import_with_sysroot(glo, sysroot)
90
+ dynamic_import(imp, globals())
91
+