abstract-utilities 0.2.2.540__py3-none-any.whl → 0.2.2.667__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.
- abstract_utilities/__init__.py +13 -4
- abstract_utilities/class_utils/abstract_classes.py +104 -34
- abstract_utilities/class_utils/caller_utils.py +57 -0
- abstract_utilities/class_utils/global_utils.py +35 -20
- abstract_utilities/class_utils/imports/imports.py +1 -1
- abstract_utilities/directory_utils/src/directory_utils.py +19 -1
- abstract_utilities/file_utils/imports/classes.py +59 -55
- abstract_utilities/file_utils/imports/imports.py +0 -4
- abstract_utilities/file_utils/imports/module_imports.py +1 -1
- abstract_utilities/file_utils/src/__init__.py +2 -3
- abstract_utilities/file_utils/src/file_filters/__init__.py +1 -0
- abstract_utilities/file_utils/src/file_filters/ensure_utils.py +490 -0
- abstract_utilities/file_utils/src/file_filters/filter_params.py +150 -0
- abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
- abstract_utilities/file_utils/src/file_filters/predicate_utils.py +44 -0
- abstract_utilities/file_utils/src/file_reader.py +0 -1
- abstract_utilities/file_utils/src/find_collect.py +10 -86
- abstract_utilities/file_utils/src/find_content.py +210 -0
- abstract_utilities/file_utils/src/initFunctionsGen.py +36 -23
- abstract_utilities/file_utils/src/initFunctionsGens.py +280 -0
- abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
- abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
- abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
- abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
- abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
- abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
- abstract_utilities/import_utils/circular_import_finder.py +222 -0
- abstract_utilities/import_utils/circular_import_finder2.py +118 -0
- abstract_utilities/import_utils/imports/__init__.py +1 -1
- abstract_utilities/import_utils/imports/init_imports.py +3 -0
- abstract_utilities/import_utils/imports/module_imports.py +4 -1
- abstract_utilities/import_utils/imports/utils.py +1 -1
- abstract_utilities/import_utils/src/__init__.py +1 -0
- abstract_utilities/import_utils/src/clean_imports.py +156 -25
- abstract_utilities/import_utils/src/dot_utils.py +11 -0
- abstract_utilities/import_utils/src/extract_utils.py +4 -0
- abstract_utilities/import_utils/src/import_functions.py +66 -2
- abstract_utilities/import_utils/src/import_utils.py +39 -0
- abstract_utilities/import_utils/src/layze_import_utils/__init__.py +2 -0
- abstract_utilities/import_utils/src/layze_import_utils/lazy_utils.py +41 -0
- abstract_utilities/import_utils/src/layze_import_utils/nullProxy.py +32 -0
- abstract_utilities/import_utils/src/nullProxy.py +30 -0
- abstract_utilities/import_utils/src/pkg_utils.py +58 -4
- abstract_utilities/import_utils/src/sysroot_utils.py +56 -1
- abstract_utilities/imports.py +3 -2
- abstract_utilities/json_utils/json_utils.py +11 -3
- abstract_utilities/log_utils/log_file.py +73 -24
- abstract_utilities/parse_utils/parse_utils.py +23 -0
- abstract_utilities/path_utils/imports/module_imports.py +1 -1
- abstract_utilities/path_utils/path_utils.py +32 -35
- abstract_utilities/read_write_utils/imports/imports.py +1 -1
- abstract_utilities/read_write_utils/read_write_utils.py +102 -32
- abstract_utilities/safe_utils/safe_utils.py +30 -0
- abstract_utilities/type_utils/__init__.py +5 -1
- abstract_utilities/type_utils/get_type.py +116 -0
- abstract_utilities/type_utils/imports/__init__.py +1 -0
- abstract_utilities/type_utils/imports/constants.py +134 -0
- abstract_utilities/type_utils/imports/module_imports.py +25 -1
- abstract_utilities/type_utils/is_type.py +455 -0
- abstract_utilities/type_utils/make_type.py +126 -0
- abstract_utilities/type_utils/mime_types.py +68 -0
- abstract_utilities/type_utils/type_utils.py +0 -877
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/METADATA +1 -1
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/RECORD +66 -41
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/WHEEL +0 -0
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
from abstract_utilities import *
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
def clean_line(line):
|
|
4
|
+
return eatAll(line,[' ','','\t','\n'])
|
|
5
|
+
def is_from_line_group(line):
|
|
6
|
+
if line and line.startswith(FROM_TAG) and IMPORT_TAG in line and '(' in line:
|
|
7
|
+
import_spl = line.split(IMPORT_TAG)[-1]
|
|
8
|
+
import_spl_clean = clean_line(line)
|
|
9
|
+
if not import_spl_clean.endswith(')'):
|
|
10
|
+
return True
|
|
11
|
+
return False
|
|
12
|
+
def clean_imports(text=None,file_path=None,import_pkg_js=None,fill_nulines=False):
|
|
13
|
+
if text and os.path.isfile(text):
|
|
14
|
+
file_path = text
|
|
15
|
+
input(file_path)
|
|
16
|
+
text = read_from_file(file_path)
|
|
17
|
+
if not import_pkg_js:
|
|
18
|
+
import_pkg_js = get_all_imports(text=text,file_path=file_path)
|
|
19
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
|
|
20
|
+
nu_lines = import_pkg_js["context"]["nulines"]
|
|
21
|
+
for pkg,values in import_pkg_js.items():
|
|
22
|
+
comments = []
|
|
23
|
+
if pkg not in ["context"]:
|
|
24
|
+
|
|
25
|
+
imports = values.get('imports')
|
|
26
|
+
for i,imp in enumerate(imports):
|
|
27
|
+
if '#' in imp:
|
|
28
|
+
imp_spl = imp.split('#')
|
|
29
|
+
comments.append(imp_spl[-1])
|
|
30
|
+
imports[i] = clean_line(imp_spl[0])
|
|
31
|
+
imports = list(set(imports))
|
|
32
|
+
if '*' in imports:
|
|
33
|
+
imports="*"
|
|
34
|
+
else:
|
|
35
|
+
imports=','.join(imports)
|
|
36
|
+
if comments:
|
|
37
|
+
comments=','.join(comments)
|
|
38
|
+
imports+=f" #{comments}"
|
|
39
|
+
import_pkg_js[pkg]["imports"]=imports
|
|
40
|
+
if fill_nulines:
|
|
41
|
+
line = values.get('line')
|
|
42
|
+
if len(nu_lines) >= line:
|
|
43
|
+
nu_lines[line] += imports
|
|
44
|
+
return import_pkg_js
|
|
45
|
+
def get_all_imports(text=None,file_path=None,import_pkg_js=None):
|
|
46
|
+
if text and os.path.isfile(text):
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
text = read_from_file(text)
|
|
50
|
+
except:
|
|
51
|
+
pass
|
|
52
|
+
file_path = text
|
|
53
|
+
text = get_text_or_read(text=text,file_path=file_path)
|
|
54
|
+
lines = text.split('\n')
|
|
55
|
+
cleaned_import_list=[]
|
|
56
|
+
nu_lines = []
|
|
57
|
+
is_from_group = False
|
|
58
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
|
|
59
|
+
for line in lines:
|
|
60
|
+
if line.startswith(IMPORT_TAG) and ' from ' not in line:
|
|
61
|
+
cleaned_import_list = get_cleaned_import_list(line)
|
|
62
|
+
import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js)
|
|
63
|
+
else:
|
|
64
|
+
if is_from_group:
|
|
65
|
+
import_pkg=is_from_group
|
|
66
|
+
line = clean_line(line)
|
|
67
|
+
if line.endswith(')'):
|
|
68
|
+
is_from_group=False
|
|
69
|
+
line=line[:-1]
|
|
70
|
+
imports_from_import_pkg = clean_imports(line)
|
|
71
|
+
import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports_from_import_pkg,import_pkg_js=import_pkg_js)
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js)
|
|
75
|
+
if is_from_line_group(line) and is_from_group == False:
|
|
76
|
+
is_from_group=get_import_pkg(line)
|
|
77
|
+
return import_pkg_js
|
|
78
|
+
def get_path_or_init(pkg_info):
|
|
79
|
+
root_dirname = pkg_info.get("root_dirname")
|
|
80
|
+
pkg = pkg_info.get("pkg")
|
|
81
|
+
rel_path = pkg.replace('.','/')
|
|
82
|
+
dirname = os.path.dirname(root_dirname)
|
|
83
|
+
pkg_path = os.path.join(dirname,rel_path)
|
|
84
|
+
pkg_py_path = f"{pkg_path}.py"
|
|
85
|
+
if os.path.isfile(pkg_py_path):
|
|
86
|
+
return pkg_py_path
|
|
87
|
+
pkg_init_path = os.path.join(pkg_path,'__init__.py')
|
|
88
|
+
if os.path.isdir(pkg_path):
|
|
89
|
+
if os.path.isfile(pkg_init_path):
|
|
90
|
+
return pkg_init_path
|
|
91
|
+
#input(f"nnot found == {pkg_info}")
|
|
92
|
+
def get_dot_fro_line(line,dirname=None,file_path=None,get_info=False):
|
|
93
|
+
info_js = {"nuline":line,"og_line":line,"pkg":line,"dirname":dirname,"file_path":file_path,"root_dirname":None,"local":False}
|
|
94
|
+
if dirname and is_file(dirname):
|
|
95
|
+
file_path=dirname
|
|
96
|
+
dirname = os.path.dirname(dirname)
|
|
97
|
+
info_js["file_path"]=file_path
|
|
98
|
+
info_js["dirname"]=dirname
|
|
99
|
+
from_line = line.split(FROM_TAG)[-1]
|
|
100
|
+
dot_fro = ""
|
|
101
|
+
for char in from_line:
|
|
102
|
+
if char != '.':
|
|
103
|
+
pkg = f"{dot_fro}{eatAll(from_line,'.')}"
|
|
104
|
+
nuline=f"from {pkg}"
|
|
105
|
+
info_js["nuline"]=nuline
|
|
106
|
+
info_js["pkg"]=pkg
|
|
107
|
+
break
|
|
108
|
+
if dirname:
|
|
109
|
+
info_js["root_dirname"]=dirname
|
|
110
|
+
dirbase = os.path.basename(dirname)
|
|
111
|
+
dirname = os.path.dirname(dirname)
|
|
112
|
+
|
|
113
|
+
dot_fro = f"{dirbase}.{dot_fro}"
|
|
114
|
+
if get_info:
|
|
115
|
+
if dot_fro and os.path.isdir(info_js["root_dirname"]):
|
|
116
|
+
info_js["local"]=True
|
|
117
|
+
info_js["pkg_path"]=get_path_or_init(info_js)
|
|
118
|
+
return info_js
|
|
119
|
+
return line
|
|
120
|
+
def get_top_level_imp(line,dirname=None):
|
|
121
|
+
imp = get_dot_fro_line(line,dirname)
|
|
122
|
+
return imp.split('.')[0]
|
|
123
|
+
def return_local_imps(file_path):
|
|
124
|
+
local_imps = []
|
|
125
|
+
dirname = os.path.dirname(file_path)
|
|
126
|
+
imports_js = get_all_imports(file_path)
|
|
127
|
+
for pkg,imps in imports_js.items():
|
|
128
|
+
if pkg not in ['context','nulines']:
|
|
129
|
+
full_imp_info = get_dot_fro_line(pkg,dirname,file_path=file_path,get_info=True)
|
|
130
|
+
if full_imp_info.get("local") == True:
|
|
131
|
+
local_imps.append(full_imp_info)
|
|
132
|
+
return local_imps
|
|
133
|
+
def get_all_pkg_paths(file_path):
|
|
134
|
+
pkg_paths = []
|
|
135
|
+
local_imps = return_local_imps(file_path)
|
|
136
|
+
for local_imp in local_imps:
|
|
137
|
+
curr_file_path = local_imp.get('file_path')
|
|
138
|
+
pkg_path = local_imp.get('pkg_path')
|
|
139
|
+
if pkg_path != None:
|
|
140
|
+
pkg_paths.append(pkg_path)
|
|
141
|
+
return pkg_paths
|
|
142
|
+
def get_cir_dir(pkg_path):
|
|
143
|
+
dirname = os.path.dirname(pkg_path)
|
|
144
|
+
dirbase = os.path.basename(dirname)
|
|
145
|
+
while True:
|
|
146
|
+
if dirname == "/home/flerb/Documents/pythonTools/modules/src/modules/abstract_utilities/src/abstract_utilities":
|
|
147
|
+
break
|
|
148
|
+
dirbase = os.path.basename(dirname)
|
|
149
|
+
dirname = os.path.dirname(dirname)
|
|
150
|
+
#input(f"{dirbase} is circular")
|
|
151
|
+
return dirbase
|
|
152
|
+
def is_circular(pkg_path):
|
|
153
|
+
pkg_paths = get_all_pkg_paths(pkg_path)
|
|
154
|
+
if pkg_path in pkg_paths:
|
|
155
|
+
return pkg_path
|
|
156
|
+
def are_circular(pkg_path,cir_dirs = None):
|
|
157
|
+
cir_dirs = cir_dirs or []
|
|
158
|
+
pkg_path = is_circular(pkg_path)
|
|
159
|
+
if pkg_path:
|
|
160
|
+
if pkg_path not in cir_dirs:
|
|
161
|
+
cir_dirs.append(pkg_path)
|
|
162
|
+
return cir_dirs
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def build_dependency_graph(main_directory):
|
|
166
|
+
"""Map each file to all local imports (by resolved pkg_path)."""
|
|
167
|
+
graph = defaultdict(list)
|
|
168
|
+
dirs, all_local_scripts = get_files_and_dirs(
|
|
169
|
+
main_directory,
|
|
170
|
+
allowed_exts='.py',
|
|
171
|
+
exclude_dirs=['depriciate', 'junk'],
|
|
172
|
+
files_only=True
|
|
173
|
+
)
|
|
174
|
+
for file_path in all_local_scripts:
|
|
175
|
+
deps = get_all_pkg_paths(file_path)
|
|
176
|
+
for dep in deps:
|
|
177
|
+
if dep and os.path.isfile(dep):
|
|
178
|
+
graph[file_path].append(dep)
|
|
179
|
+
return graph
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def find_circular_chains(graph):
|
|
183
|
+
"""Detect circular imports and return their full dependency paths."""
|
|
184
|
+
visited, cycles = set(), []
|
|
185
|
+
|
|
186
|
+
def dfs(node, path):
|
|
187
|
+
visited.add(node)
|
|
188
|
+
path.append(node)
|
|
189
|
+
for dep in graph.get(node, []):
|
|
190
|
+
if dep not in path:
|
|
191
|
+
dfs(dep, path.copy())
|
|
192
|
+
else:
|
|
193
|
+
# Found a circular import
|
|
194
|
+
cycle_start = path.index(dep)
|
|
195
|
+
cycle = path[cycle_start:] + [dep]
|
|
196
|
+
if cycle not in cycles:
|
|
197
|
+
cycles.append(cycle)
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
for start in graph:
|
|
201
|
+
dfs(start, [])
|
|
202
|
+
return cycles
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def explain_circular_imports(cycles):
|
|
206
|
+
"""Pretty-print circular import chains with file names and import lines."""
|
|
207
|
+
for i, cycle in enumerate(cycles, 1):
|
|
208
|
+
print(f"\n🔁 Circular import {i}:")
|
|
209
|
+
for j in range(len(cycle) - 1):
|
|
210
|
+
src, dst = cycle[j], cycle[j + 1]
|
|
211
|
+
print(f" {os.path.basename(src)} → {os.path.basename(dst)}")
|
|
212
|
+
print(f" ^ back to {os.path.basename(cycle[0])}")
|
|
213
|
+
main_directory = "/home/flerb/Documents/pythonTools/modules/src/modules/abstract_utilities/src/abstract_utilities"
|
|
214
|
+
|
|
215
|
+
graph = build_dependency_graph(main_directory)
|
|
216
|
+
cycles = find_circular_chains(graph)
|
|
217
|
+
|
|
218
|
+
if not cycles:
|
|
219
|
+
print("✅ No circular imports found.")
|
|
220
|
+
else:
|
|
221
|
+
print(f"❌ Found {len(cycles)} circular import(s).")
|
|
222
|
+
explain_circular_imports(cycles)
|
|
@@ -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))
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from ...read_write_utils import read_from_file,write_to_file,get_text_or_read
|
|
2
2
|
from ...string_utils import eatAll,eatInner,eatElse,clean_line
|
|
3
|
-
from ...class_utils import get_caller_path
|
|
3
|
+
from ...class_utils import if_none_change,if_none_default,get_true_globals,get_initial_caller_dir,get_caller_path,get_caller_dir,if_none_default
|
|
4
4
|
from ...list_utils import make_list
|
|
5
5
|
from ...path_utils import get_file_parts
|
|
6
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
|
|
9
|
+
from ...log_utils import get_logFile
|
|
@@ -1,12 +1,64 @@
|
|
|
1
1
|
from ..imports import *
|
|
2
2
|
from .pkg_utils import *
|
|
3
|
-
|
|
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
|
|
4
53
|
def get_text_or_read(text=None,file_path=None):
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if not text and file_path and os.path.isfile(file_path):
|
|
54
|
+
file_path = get_pkg_or_init(file_path)
|
|
55
|
+
if not text and file_path:
|
|
8
56
|
text=read_from_file(file_path)
|
|
9
|
-
|
|
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
|
|
10
62
|
def is_line_import(line):
|
|
11
63
|
if line and (line.startswith(FROM_TAG) or line.startswith(IMPORT_TAG)):
|
|
12
64
|
return True
|
|
@@ -25,19 +77,18 @@ def is_from_line_group(line):
|
|
|
25
77
|
return False
|
|
26
78
|
|
|
27
79
|
def get_all_imports(text=None,file_path=None,import_pkg_js=None):
|
|
28
|
-
|
|
29
|
-
file_path = text
|
|
30
|
-
text = read_from_file(text)
|
|
31
|
-
text = get_text_or_read(text=text,file_path=file_path)
|
|
80
|
+
text,file_path = get_text_or_read(text=text,file_path=file_path)
|
|
32
81
|
lines = text.split('\n')
|
|
33
82
|
cleaned_import_list=[]
|
|
34
83
|
nu_lines = []
|
|
35
84
|
is_from_group = False
|
|
36
85
|
import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
|
|
37
86
|
for line in lines:
|
|
87
|
+
|
|
38
88
|
if line.startswith(IMPORT_TAG) and ' from ' not in line:
|
|
89
|
+
|
|
39
90
|
cleaned_import_list = get_cleaned_import_list(line)
|
|
40
|
-
import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js)
|
|
91
|
+
import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js,file_path=file_path)
|
|
41
92
|
else:
|
|
42
93
|
if is_from_group:
|
|
43
94
|
import_pkg=is_from_group
|
|
@@ -46,18 +97,16 @@ def get_all_imports(text=None,file_path=None,import_pkg_js=None):
|
|
|
46
97
|
is_from_group=False
|
|
47
98
|
line=line[:-1]
|
|
48
99
|
imports_from_import_pkg = clean_imports(line)
|
|
49
|
-
import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports_from_import_pkg,import_pkg_js=import_pkg_js)
|
|
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)
|
|
50
101
|
|
|
51
102
|
else:
|
|
52
|
-
import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js)
|
|
103
|
+
import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js,file_path=file_path)
|
|
53
104
|
if is_from_line_group(line) and is_from_group == False:
|
|
54
105
|
is_from_group=get_import_pkg(line)
|
|
55
106
|
return import_pkg_js
|
|
56
107
|
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
file_path = text
|
|
60
|
-
text = read_from_file(text)
|
|
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)
|
|
61
110
|
if not import_pkg_js:
|
|
62
111
|
import_pkg_js = get_all_imports(text=text,file_path=file_path)
|
|
63
112
|
import_pkg_js = ensure_import_pkg_js(import_pkg_js,file_path=file_path)
|
|
@@ -87,11 +136,11 @@ def clean_imports(text=None,file_path=None,import_pkg_js=None,fill_nulines=False
|
|
|
87
136
|
nu_lines[line] += imports
|
|
88
137
|
return import_pkg_js
|
|
89
138
|
def clean_all_imports(text=None,file_path=None,import_pkg_js=None,fill_nulines=False):
|
|
90
|
-
|
|
91
|
-
import_pkg_js["context"]["nulines"]=
|
|
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"]
|
|
92
141
|
return import_pkg_js
|
|
93
142
|
def get_clean_import_string(import_pkg_js,fill_nulines=False,get_locals=False):
|
|
94
|
-
import_pkg_js =
|
|
143
|
+
import_pkg_js = get_clean_imports(import_pkg_js=import_pkg_js,fill_nulines=fill_nulines)
|
|
95
144
|
import_ls = []
|
|
96
145
|
for key,values in import_pkg_js.items():
|
|
97
146
|
if key not in ['context','nulines']:
|
|
@@ -130,18 +179,100 @@ def get_dot_fro_lines(lines,file_path,all_imps):
|
|
|
130
179
|
all_imps.append(line)
|
|
131
180
|
return all_imps
|
|
132
181
|
def get_all_real_imps(text=None,file_path=None,all_imps=None):
|
|
133
|
-
|
|
134
|
-
file_path = text
|
|
135
|
-
text = read_from_file(text)
|
|
182
|
+
|
|
136
183
|
all_imps = all_imps or []
|
|
137
|
-
|
|
138
|
-
lines =
|
|
184
|
+
text,file_path = get_text_or_read(text=text,file_path=file_path)
|
|
185
|
+
lines = text.split('\n')
|
|
139
186
|
all_imps = get_dot_fro_lines(lines,file_path,all_imps)
|
|
140
187
|
return '\n'.join(all_imps)
|
|
141
188
|
def save_cleaned_imports(text=None,file_path=None,write=False,import_pkg_js=None):
|
|
142
|
-
import_pkg_js=
|
|
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)
|
|
143
190
|
import_pkg_js = clean_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
|
|
144
191
|
contents = '\n'.join(import_pkg_js["context"]["nulines"])
|
|
145
192
|
if file_path and write:
|
|
146
193
|
write_to_file(contents=contents,file_path=file_path)
|
|
147
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)
|
|
@@ -1,4 +1,15 @@
|
|
|
1
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
|
|
2
13
|
def get_Path(path):
|
|
3
14
|
if isinstance(path,str):
|
|
4
15
|
path = Path(str(path))
|
|
@@ -40,3 +40,7 @@ def extract_class(path: str):
|
|
|
40
40
|
if m:
|
|
41
41
|
funcs.append(m.group(1))
|
|
42
42
|
return funcs
|
|
43
|
+
def get_all_py_file_paths(directory,*args,**kwargs):
|
|
44
|
+
globs = collect_globs(directory,*args,allowed_exts='.py',**kwargs)
|
|
45
|
+
globs = [glo for glo in globs.get('files') if glo]
|
|
46
|
+
return globs
|