abstract-utilities 0.2.2.493__py3-none-any.whl → 0.2.2.495__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.
- abstract_utilities/__init__.py +0 -1
- abstract_utilities/file_utils/__init__.py +1 -2
- abstract_utilities/file_utils/imports/constants.py +6 -0
- abstract_utilities/file_utils/imports/imports.py +1 -1
- abstract_utilities/file_utils/imports/module_imports.py +1 -2
- abstract_utilities/file_utils/module_imports.py +12 -0
- abstract_utilities/file_utils/src/__init__.py +10 -0
- abstract_utilities/file_utils/src/file_filters.py +110 -0
- abstract_utilities/file_utils/src/file_reader.py +607 -0
- abstract_utilities/file_utils/src/file_utils.py +279 -0
- abstract_utilities/file_utils/src/filter_params.py +155 -0
- abstract_utilities/file_utils/src/find_collect.py +154 -0
- abstract_utilities/file_utils/src/initFunctionsGen.py +286 -0
- abstract_utilities/file_utils/src/map_utils.py +29 -0
- abstract_utilities/file_utils/src/pdf_utils.py +300 -0
- abstract_utilities/file_utils/src/type_checks.py +92 -0
- abstract_utilities/import_utils/__init__.py +2 -0
- abstract_utilities/import_utils/imports/__init__.py +4 -0
- abstract_utilities/import_utils/imports/constants.py +2 -0
- abstract_utilities/import_utils/imports/imports.py +4 -0
- abstract_utilities/import_utils/imports/module_imports.py +6 -0
- abstract_utilities/import_utils/imports/utils.py +30 -0
- abstract_utilities/import_utils/src/__init__.py +7 -0
- abstract_utilities/import_utils/src/clean_imports.py +122 -0
- abstract_utilities/import_utils/src/dot_utils.py +60 -0
- abstract_utilities/import_utils/src/extract_utils.py +42 -0
- abstract_utilities/import_utils/src/import_functions.py +46 -0
- abstract_utilities/import_utils/src/import_utils.py +299 -0
- abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
- abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
- abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
- abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
- abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
- abstract_utilities/import_utils/src/package_utils.py +140 -0
- abstract_utilities/import_utils/src/sysroot_utils.py +57 -0
- abstract_utilities/path_utils.py +1 -12
- abstract_utilities/read_write_utils.py +31 -14
- {abstract_utilities-0.2.2.493.dist-info → abstract_utilities-0.2.2.495.dist-info}/METADATA +1 -1
- {abstract_utilities-0.2.2.493.dist-info → abstract_utilities-0.2.2.495.dist-info}/RECORD +42 -11
- {abstract_utilities-0.2.2.493.dist-info → abstract_utilities-0.2.2.495.dist-info}/top_level.txt +1 -0
- imports/__init__.py +36 -0
- {abstract_utilities-0.2.2.493.dist-info → abstract_utilities-0.2.2.495.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from importlib.util import find_spec
|
|
4
|
+
from typing import Dict, Set
|
|
5
|
+
import ast, sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from importlib.util import find_spec
|
|
8
|
+
from typing import Dict, Set
|
|
9
|
+
from src.abstract_utilities.import_utils import *
|
|
10
|
+
STDLIB_NAMES = set(sys.builtin_module_names)
|
|
11
|
+
def parse_imports(file_path: Path):
|
|
12
|
+
"""Return list of (module, level) for every import/from-import."""
|
|
13
|
+
try:
|
|
14
|
+
src = file_path.read_text(errors="ignore")
|
|
15
|
+
tree = ast.parse(src, filename=str(file_path))
|
|
16
|
+
except Exception:
|
|
17
|
+
return []
|
|
18
|
+
imports = []
|
|
19
|
+
for node in ast.walk(tree):
|
|
20
|
+
if isinstance(node, ast.Import):
|
|
21
|
+
for alias in node.names:
|
|
22
|
+
imports.append((alias.name, 0))
|
|
23
|
+
elif isinstance(node, ast.ImportFrom):
|
|
24
|
+
imports.append((node.module, node.level))
|
|
25
|
+
return imports
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def resolve_relative_import(base_file: Path, module: str | None, level: int) -> Path | None:
|
|
29
|
+
"""Follow a relative import path to its real file if it exists."""
|
|
30
|
+
base = base_file.parent
|
|
31
|
+
for _ in range(level - 1):
|
|
32
|
+
base = base.parent
|
|
33
|
+
if not module:
|
|
34
|
+
target = base
|
|
35
|
+
else:
|
|
36
|
+
target = base / module.replace(".", "/")
|
|
37
|
+
if (target / "__init__.py").exists():
|
|
38
|
+
return target / "__init__.py"
|
|
39
|
+
if target.with_suffix(".py").exists():
|
|
40
|
+
return target.with_suffix(".py")
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def classify_import(mod_name: str, root_pkg: str) -> str:
|
|
47
|
+
"""Return 'local', 'internal', or 'external'."""
|
|
48
|
+
if not mod_name:
|
|
49
|
+
return "unknown"
|
|
50
|
+
if mod_name.startswith("."):
|
|
51
|
+
return "local"
|
|
52
|
+
if mod_name.split(".")[0] == root_pkg:
|
|
53
|
+
return "internal"
|
|
54
|
+
if mod_name.split(".")[0] in STDLIB_NAMES:
|
|
55
|
+
return "stdlib"
|
|
56
|
+
return "external"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def follow_imports(entry: Path, root_pkg: str,
|
|
60
|
+
visited: Dict[Path, Dict[str, Set[str]]] | None = None):
|
|
61
|
+
"""
|
|
62
|
+
Recursively follow only internal/local imports.
|
|
63
|
+
Returns {file_path: {'internal': set(), 'external': set()}}
|
|
64
|
+
"""
|
|
65
|
+
visited = visited or {}
|
|
66
|
+
if entry in visited:
|
|
67
|
+
return visited
|
|
68
|
+
|
|
69
|
+
visited[entry] = {"internal": set(), "external": set()}
|
|
70
|
+
|
|
71
|
+
for mod, level in parse_imports(entry):
|
|
72
|
+
if level > 0:
|
|
73
|
+
target = resolve_relative_import(entry, mod, level)
|
|
74
|
+
if target:
|
|
75
|
+
visited[entry]["internal"].add(str(target))
|
|
76
|
+
follow_imports(target, root_pkg, visited)
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
category = classify_import(mod, root_pkg)
|
|
80
|
+
if category == "internal":
|
|
81
|
+
spec = find_spec(mod)
|
|
82
|
+
if spec and spec.origin and spec.origin.endswith(".py"):
|
|
83
|
+
visited[entry]["internal"].add(spec.origin)
|
|
84
|
+
follow_imports(Path(spec.origin), root_pkg, visited)
|
|
85
|
+
elif category == "external":
|
|
86
|
+
visited[entry]["external"].add(mod)
|
|
87
|
+
elif category == "stdlib":
|
|
88
|
+
# stdlib gets treated like external but labeled
|
|
89
|
+
visited[entry]["external"].add(mod + " # stdlib")
|
|
90
|
+
|
|
91
|
+
return visited
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def build_master_imports(entry: Path, root_pkg: str, output: Path):
|
|
96
|
+
trace = follow_imports(entry, root_pkg)
|
|
97
|
+
lines = ["# Auto-generated master imports for abstract_utilities\n"]
|
|
98
|
+
all_modules = set()
|
|
99
|
+
external_modules = set()
|
|
100
|
+
imports = get_all_imports(path)
|
|
101
|
+
for _, data in trace.items():
|
|
102
|
+
for dep in data["internal"]:
|
|
103
|
+
path = Path(dep)
|
|
104
|
+
if path.suffix != ".py":
|
|
105
|
+
continue
|
|
106
|
+
try:
|
|
107
|
+
rel_parts = path.with_suffix("").parts
|
|
108
|
+
idx = rel_parts.index(root_pkg)
|
|
109
|
+
dotted = ".".join(rel_parts[idx:])
|
|
110
|
+
all_modules.add(dotted)
|
|
111
|
+
except ValueError:
|
|
112
|
+
continue
|
|
113
|
+
external_modules.update(data["external"])
|
|
114
|
+
|
|
115
|
+
for mod in sorted(all_modules):
|
|
116
|
+
short = mod.split(".", 1)[-1]
|
|
117
|
+
lines.append(f"from .{short} import *")
|
|
118
|
+
|
|
119
|
+
if external_modules:
|
|
120
|
+
lines.append("\n# External / stdlib imports (not traced, for reference)")
|
|
121
|
+
for ext in sorted(external_modules):
|
|
122
|
+
lines.append(f"# {ext}")
|
|
123
|
+
|
|
124
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
125
|
+
output.write_text("\n".join(lines+str(imports)))
|
|
126
|
+
print(f"✅ wrote master imports hub → {output}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
entry = Path(
|
|
132
|
+
"/home/flerb/Documents/pythonTools/modules/src/modules/abstract_utilities/src/"
|
|
133
|
+
"abstract_utilities/import_utils/src/import_functions.py"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
pkg = "abstract_utilities"
|
|
138
|
+
out = entry.parents[4] / "imports" / "__init__.py"
|
|
139
|
+
build_master_imports(entry, pkg, out)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import sys, os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from .path_utils import find_top_package_dir, derive_package_for_file
|
|
4
|
+
|
|
5
|
+
def ensure_package_context(file: str):
|
|
6
|
+
"""Ensure that running this file directly gives correct package context."""
|
|
7
|
+
file = file or os.getcwd()
|
|
8
|
+
here = Path(file).resolve()
|
|
9
|
+
top_pkg_dir = find_top_package_dir(here)
|
|
10
|
+
if not top_pkg_dir:
|
|
11
|
+
raise RuntimeError(f"No package context above {here}. Add __init__.py files up the tree.")
|
|
12
|
+
|
|
13
|
+
sysroot = top_pkg_dir.parent
|
|
14
|
+
if str(sysroot) not in sys.path:
|
|
15
|
+
sys.path.insert(0, str(sysroot))
|
|
16
|
+
|
|
17
|
+
parts = here.with_suffix("").relative_to(sysroot).parts
|
|
18
|
+
pkg_name = ".".join(parts[:-1])
|
|
19
|
+
if (__name__ == "__main__") and not globals().get("__package__"):
|
|
20
|
+
globals()["__package__"] = pkg_name
|
|
21
|
+
|
|
22
|
+
def ensure_caller_package(caller_file: str, caller_globals: dict | None = None) -> str:
|
|
23
|
+
"""Ensure sysroot is on sys.path and return caller's dotted package name."""
|
|
24
|
+
pkg, _ = derive_package_for_file(caller_file)
|
|
25
|
+
if caller_globals and caller_globals.get("__name__") == "__main__" and not caller_globals.get("__package__"):
|
|
26
|
+
caller_globals["__package__"] = pkg
|
|
27
|
+
return pkg
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
from .import_functions import *
|
|
3
|
+
|
|
4
|
+
def ensure_import_pkg_js(import_pkg_js=None, file_path=None):
|
|
5
|
+
import_pkg_js = import_pkg_js or {"context": {}}
|
|
6
|
+
if "context" not in import_pkg_js:
|
|
7
|
+
import_pkg_js["context"] = {}
|
|
8
|
+
for key in ["nulines", "file_path", "all_data"]:
|
|
9
|
+
import_pkg_js["context"].setdefault(key, [] if key != "file_path" else None)
|
|
10
|
+
|
|
11
|
+
if file_path and file_path != import_pkg_js["context"].get("file_path"):
|
|
12
|
+
found = False
|
|
13
|
+
nu_data = {
|
|
14
|
+
"file_path": import_pkg_js["context"]["file_path"],
|
|
15
|
+
"nulines": import_pkg_js["context"]["nulines"]
|
|
16
|
+
}
|
|
17
|
+
for i, data in enumerate(import_pkg_js["context"]["all_data"]):
|
|
18
|
+
if data.get("file_path") == import_pkg_js["context"]["file_path"]:
|
|
19
|
+
import_pkg_js["context"]["all_data"][i] = nu_data
|
|
20
|
+
found = True
|
|
21
|
+
break
|
|
22
|
+
if not found:
|
|
23
|
+
import_pkg_js["context"]["all_data"].append(nu_data)
|
|
24
|
+
import_pkg_js["context"]["nulines"] = []
|
|
25
|
+
import_pkg_js["context"]["file_path"] = file_path
|
|
26
|
+
return import_pkg_js
|
|
27
|
+
|
|
28
|
+
def add_imports_to_import_pkg_js(import_pkg, imports, import_pkg_js=None):
|
|
29
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
30
|
+
imports = clean_imports(imports)
|
|
31
|
+
if import_pkg not in import_pkg_js:
|
|
32
|
+
i = len(import_pkg_js["context"]["nulines"])
|
|
33
|
+
file_path = import_pkg_js["context"]["file_path"]
|
|
34
|
+
file_parts = get_file_parts(file_path)
|
|
35
|
+
dirname = file_parts["dirname"]
|
|
36
|
+
import_pkg_js[import_pkg] = {"imports": imports, "line": i}
|
|
37
|
+
import_pkg_js["context"]["nulines"].append(f"from {import_pkg} import ")
|
|
38
|
+
else:
|
|
39
|
+
import_pkg_js[import_pkg]["imports"] += imports
|
|
40
|
+
return import_pkg_js
|
|
41
|
+
|
|
42
|
+
def update_import_pkg_js(line, import_pkg_js=None):
|
|
43
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
44
|
+
if is_line_group_import(line):
|
|
45
|
+
import_pkg = get_import_pkg(line)
|
|
46
|
+
imports = get_imports_from_import_pkg(line)
|
|
47
|
+
import_pkg_js = add_imports_to_import_pkg_js(import_pkg, imports, import_pkg_js=import_pkg_js)
|
|
48
|
+
else:
|
|
49
|
+
if import_pkg_js["context"]["nulines"] and line == "" and is_line_import(import_pkg_js["context"]["nulines"][-1]):
|
|
50
|
+
pass
|
|
51
|
+
else:
|
|
52
|
+
import_pkg_js["context"]["nulines"].append(line)
|
|
53
|
+
return import_pkg_js
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os, sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
def find_top_package_dir(p: Path) -> Path | None:
|
|
5
|
+
"""Walk upward until the topmost __init__.py-containing directory."""
|
|
6
|
+
p = p.resolve()
|
|
7
|
+
if p.is_file():
|
|
8
|
+
p = p.parent
|
|
9
|
+
top = None
|
|
10
|
+
while (p / "__init__.py").exists():
|
|
11
|
+
top = p
|
|
12
|
+
if p.parent == p:
|
|
13
|
+
break
|
|
14
|
+
p = p.parent
|
|
15
|
+
return top
|
|
16
|
+
|
|
17
|
+
def derive_package_for_file(file: str) -> tuple[str, Path]:
|
|
18
|
+
"""Return (pkg_name, sysroot) for the module file."""
|
|
19
|
+
here = Path(file).resolve()
|
|
20
|
+
top_pkg_dir = find_top_package_dir(here)
|
|
21
|
+
if not top_pkg_dir:
|
|
22
|
+
raise RuntimeError(f"No package context above {here}. Add __init__.py up the tree.")
|
|
23
|
+
sysroot = top_pkg_dir.parent
|
|
24
|
+
if str(sysroot) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(sysroot))
|
|
26
|
+
parts = here.with_suffix("").relative_to(sysroot).parts
|
|
27
|
+
pkg_name = ".".join(parts[:-1])
|
|
28
|
+
return pkg_name, sysroot
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import inspect, importlib
|
|
2
|
+
from .context_utils import ensure_caller_package
|
|
3
|
+
|
|
4
|
+
def safe_import(
|
|
5
|
+
name: str,
|
|
6
|
+
*,
|
|
7
|
+
member: str | None = None,
|
|
8
|
+
package: str | None = None,
|
|
9
|
+
file: str | None = None,
|
|
10
|
+
caller_globals: dict | None = None,
|
|
11
|
+
):
|
|
12
|
+
"""
|
|
13
|
+
Safe dynamic import that resolves relative imports when run as a script.
|
|
14
|
+
"""
|
|
15
|
+
if file is None:
|
|
16
|
+
frame = inspect.currentframe()
|
|
17
|
+
assert frame is not None
|
|
18
|
+
outer = frame.f_back
|
|
19
|
+
caller_file = (outer.f_globals.get("__file__") if outer else None) or __file__
|
|
20
|
+
else:
|
|
21
|
+
caller_file = file
|
|
22
|
+
|
|
23
|
+
if name.startswith(".") and not package:
|
|
24
|
+
package = ensure_caller_package(caller_file, caller_globals=caller_globals)
|
|
25
|
+
|
|
26
|
+
mod = importlib.import_module(name, package=package)
|
|
27
|
+
return getattr(mod, member) if member else mod
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# safe_import_utils.py
|
|
2
|
+
from ..imports import *
|
|
3
|
+
from .import_functions import *
|
|
4
|
+
|
|
5
|
+
def ensure_import_pkg_js(import_pkg_js,file_path=None):
|
|
6
|
+
import_pkg_js = import_pkg_js or {"context":{}}
|
|
7
|
+
if "context" not in import_pkg_js:
|
|
8
|
+
import_pkg_js["context"]={}
|
|
9
|
+
for key in ["nulines","file_path","all_data"]:
|
|
10
|
+
if key not in import_pkg_js["context"]:
|
|
11
|
+
import_pkg_js["context"][key]=[]
|
|
12
|
+
if file_path and file_path != import_pkg_js["context"]["file_path"]:
|
|
13
|
+
found=False
|
|
14
|
+
nu_data = {"file_path":import_pkg_js["context"]["file_path"],"nulines":import_pkg_js["context"]["nulines"]}
|
|
15
|
+
for i,data in enumerate(import_pkg_js["context"]["all_data"]):
|
|
16
|
+
if data.get('file_path') == import_pkg_js["context"]["file_path"]:
|
|
17
|
+
import_pkg_js["context"]["all_data"][i] = nu_data
|
|
18
|
+
found = True
|
|
19
|
+
break
|
|
20
|
+
if found == False:
|
|
21
|
+
import_pkg_js["context"]["all_data"].append(nu_data)
|
|
22
|
+
import_pkg_js["context"]["nulines"]=[]
|
|
23
|
+
import_pkg_js["context"]["file_path"]=file_path
|
|
24
|
+
return import_pkg_js
|
|
25
|
+
def ensure_package_context(file: str):
|
|
26
|
+
"""
|
|
27
|
+
Ensure that running this file directly still gives it the correct package.
|
|
28
|
+
Sets sys.path and __package__ based on the __init__.py chain.
|
|
29
|
+
"""
|
|
30
|
+
file = file or os.getcwd()
|
|
31
|
+
here = Path(file).resolve()
|
|
32
|
+
top_pkg_dir = find_top_pkg_dir(here)
|
|
33
|
+
if not top_pkg_dir:
|
|
34
|
+
raise RuntimeError(f"No package context above {here}. Add __init__.py files up the tree.")
|
|
35
|
+
|
|
36
|
+
sysroot = top_pkg_dir.parent # dir ABOVE the top package (e.g., .../src)
|
|
37
|
+
if str(sysroot) not in sys.path:
|
|
38
|
+
sys.path.insert(0, str(sysroot))
|
|
39
|
+
|
|
40
|
+
# Compute this module's package (exclude the filename)
|
|
41
|
+
parts = here.with_suffix("").relative_to(sysroot).parts
|
|
42
|
+
pkg_name = ".".join(parts[:-1]) # e.g. abstract_ide.consoles.launcherWindowTab
|
|
43
|
+
|
|
44
|
+
# When run as a script, __package__ is empty -> set it
|
|
45
|
+
if (__name__ == "__main__") and (not globals().get("__package__")):
|
|
46
|
+
globals()["__package__"] = pkg_name
|
|
47
|
+
# --- tiny utils ---
|
|
48
|
+
def find_top_package_dir(p: Path) -> Path | None:
|
|
49
|
+
p = p.resolve()
|
|
50
|
+
if p.is_file():
|
|
51
|
+
p = p.parent
|
|
52
|
+
top = None
|
|
53
|
+
while (p / "__init__.py").exists():
|
|
54
|
+
top = p
|
|
55
|
+
if p.parent == p:
|
|
56
|
+
break
|
|
57
|
+
p = p.parent
|
|
58
|
+
return top
|
|
59
|
+
|
|
60
|
+
def derive_package_for_file(file: str) -> tuple[str, Path]:
|
|
61
|
+
"""Return (pkg_name, sysroot) for the module file."""
|
|
62
|
+
here = Path(file).resolve()
|
|
63
|
+
top_pkg_dir = find_top_pkg_dir(here)
|
|
64
|
+
if not top_pkg_dir:
|
|
65
|
+
raise RuntimeError(f"No package context above {here}. Add __init__.py up the tree.")
|
|
66
|
+
sysroot = top_pkg_dir.parent
|
|
67
|
+
if str(sysroot) not in sys.path:
|
|
68
|
+
sys.path.insert(0, str(sysroot))
|
|
69
|
+
parts = here.with_suffix("").relative_to(sysroot).parts
|
|
70
|
+
pkg_name = ".".join(parts[:-1]) # package of the module (drop the filename)
|
|
71
|
+
return pkg_name, sysroot
|
|
72
|
+
|
|
73
|
+
def ensure_caller_package(caller_file: str, caller_globals: dict | None = None) -> str:
|
|
74
|
+
"""
|
|
75
|
+
Ensure sysroot is on sys.path and return the caller's dotted package.
|
|
76
|
+
Optionally set caller_globals['__package__'] when running as a script.
|
|
77
|
+
"""
|
|
78
|
+
pkg, _ = derive_package_for_file(caller_file)
|
|
79
|
+
if caller_globals and caller_globals.get("__name__") == "__main__" and not caller_globals.get("__package__"):
|
|
80
|
+
caller_globals["__package__"] = pkg
|
|
81
|
+
return pkg
|
|
82
|
+
def get_import_pkg(line):
|
|
83
|
+
if is_line_group_import(line):
|
|
84
|
+
return clean_line(line.split(FROM_TAG)[1].split(IMPORT_TAG)[0])
|
|
85
|
+
def get_imports_from_import_pkg(line):
|
|
86
|
+
if is_line_group_import(line):
|
|
87
|
+
return get_cleaned_import_list(line,commaClean=True)
|
|
88
|
+
def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None):
|
|
89
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
90
|
+
imports = clean_imports(imports)
|
|
91
|
+
if import_pkg not in import_pkg_js:
|
|
92
|
+
i = len(import_pkg_js["context"]["nulines"])
|
|
93
|
+
import_pkg_js[import_pkg]={"imports":imports,"line":i}
|
|
94
|
+
import_line = f"from {import_pkg} import "
|
|
95
|
+
if import_pkg == "import":
|
|
96
|
+
import_line = IMPORT_TAG
|
|
97
|
+
import_pkg_js["context"]["nulines"].append(import_line)
|
|
98
|
+
else:
|
|
99
|
+
import_pkg_js[import_pkg]["imports"]+=imports
|
|
100
|
+
return import_pkg_js
|
|
101
|
+
def update_import_pkg_js(line,import_pkg_js=None):
|
|
102
|
+
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
103
|
+
if is_line_group_import(line):
|
|
104
|
+
import_pkg = get_import_pkg(line)
|
|
105
|
+
imports = get_imports_from_import_pkg(line)
|
|
106
|
+
import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=import_pkg_js)
|
|
107
|
+
else:
|
|
108
|
+
if len(import_pkg_js["context"]["nulines"]) >0 and line == '' and is_line_import(import_pkg_js["context"]["nulines"][-1]):
|
|
109
|
+
pass
|
|
110
|
+
else:
|
|
111
|
+
import_pkg_js["context"]["nulines"].append(line)
|
|
112
|
+
return import_pkg_js
|
|
113
|
+
# --- public API ---
|
|
114
|
+
def safe_import(
|
|
115
|
+
name: str,
|
|
116
|
+
*,
|
|
117
|
+
member: str | None = None,
|
|
118
|
+
package: str | None = None,
|
|
119
|
+
file: str | None = None,
|
|
120
|
+
caller_globals: dict | None = None,
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Import `name` (relative or absolute).
|
|
124
|
+
- If `name` is relative and `package` is missing, derive it from `file` (or caller).
|
|
125
|
+
- If running the caller as a script, we can set its __package__ when caller_globals is provided.
|
|
126
|
+
"""
|
|
127
|
+
if file is None:
|
|
128
|
+
# best-effort: use the immediate caller's file
|
|
129
|
+
frame = inspect.currentframe()
|
|
130
|
+
assert frame is not None
|
|
131
|
+
outer = frame.f_back
|
|
132
|
+
caller_file = (outer.f_globals.get("__file__") if outer else None) or __file__
|
|
133
|
+
else:
|
|
134
|
+
caller_file = file
|
|
135
|
+
|
|
136
|
+
if name.startswith(".") and not package:
|
|
137
|
+
package = ensure_caller_package(caller_file, caller_globals=caller_globals)
|
|
138
|
+
|
|
139
|
+
mod = importlib.import_module(name, package=package)
|
|
140
|
+
return getattr(mod, member) if member else mod
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
from .dot_utils import *
|
|
3
|
+
|
|
4
|
+
def ensure_on_path(p: Path):
|
|
5
|
+
s = str(p)
|
|
6
|
+
if s not in sys.path:
|
|
7
|
+
sys.path.insert(0, s)
|
|
8
|
+
def get_sysroot(filepath,i):
|
|
9
|
+
for j in range(i):
|
|
10
|
+
filepath = os.path.dirname(filepath)
|
|
11
|
+
return filepath
|
|
12
|
+
|
|
13
|
+
def get_dot_range_sysroot(filepath):
|
|
14
|
+
sysroot = filepath
|
|
15
|
+
while True:
|
|
16
|
+
dot_range = get_dot_range(is_import_or_init(sysroot))
|
|
17
|
+
if dot_range == 0:
|
|
18
|
+
break
|
|
19
|
+
sysroot = get_sysroot(sysroot,dot_range)
|
|
20
|
+
|
|
21
|
+
return sysroot
|
|
22
|
+
|
|
23
|
+
def is_import_or_init(sysroot,likely=None):
|
|
24
|
+
file_data = get_file_parts(sysroot)
|
|
25
|
+
nuroot = sysroot
|
|
26
|
+
dirname = file_data.get('dirname')
|
|
27
|
+
if os.path.isdir(sysroot):
|
|
28
|
+
dirname = sysroot
|
|
29
|
+
ext = file_data.get('ext')
|
|
30
|
+
filename = file_data.get('filename')
|
|
31
|
+
|
|
32
|
+
candidates = []
|
|
33
|
+
if likely:
|
|
34
|
+
candidates += [os.path.join(dirname,f"{likely}.py"),os.path.join(dirname,likely)]
|
|
35
|
+
candidates += [os.path.join(dirname,f"{filename}.py"),os.path.join(dirname,filename)]
|
|
36
|
+
files: List[Path] = []
|
|
37
|
+
for item in candidates:
|
|
38
|
+
|
|
39
|
+
if os.path.exists(item):
|
|
40
|
+
if os.path.isdir(item):
|
|
41
|
+
|
|
42
|
+
nuroot=None
|
|
43
|
+
init_name = '__init__.py'
|
|
44
|
+
rootList = os.listdir(item)
|
|
45
|
+
for basename in rootList:
|
|
46
|
+
if get_file_parts(basename,'filename') == filename:
|
|
47
|
+
nuroot = os.path.join(item,basename)
|
|
48
|
+
break
|
|
49
|
+
if init_name in rootList:
|
|
50
|
+
nuroot = os.path.join(item,init_name)
|
|
51
|
+
break
|
|
52
|
+
|
|
53
|
+
else:
|
|
54
|
+
nuroot=sysroot
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
return nuroot
|
abstract_utilities/path_utils.py
CHANGED
|
@@ -23,7 +23,6 @@ Date: 05/31/2023
|
|
|
23
23
|
Version: 0.1.2
|
|
24
24
|
"""
|
|
25
25
|
import os
|
|
26
|
-
from .read_write_utils import read_from_file,write_to_file
|
|
27
26
|
from .string_clean import eatAll
|
|
28
27
|
from .list_utils import make_list
|
|
29
28
|
from .type_utils import get_media_exts, is_media_type,MIME_TYPES
|
|
@@ -540,8 +539,6 @@ def get_all_items(directory):
|
|
|
540
539
|
file_list = [item for item in dir_list if is_path(directory,item)]
|
|
541
540
|
return file_list
|
|
542
541
|
|
|
543
|
-
def collate_text_docs(directory=None):
|
|
544
|
-
return [read_from_file(item) for item in get_all_files(directory=directory)]
|
|
545
542
|
|
|
546
543
|
def get_dirlist(directory):
|
|
547
544
|
path = get_directory(directory)
|
|
@@ -553,15 +550,7 @@ def get_dirlist(directory):
|
|
|
553
550
|
elif is_file(path):
|
|
554
551
|
dir_list = [os.path.basename(path)]
|
|
555
552
|
return dir_list
|
|
556
|
-
|
|
557
|
-
item_path = os.path.join(*paths)
|
|
558
|
-
if os.path.isfile(item_path):
|
|
559
|
-
try:
|
|
560
|
-
content = read_from_file(item_path)
|
|
561
|
-
return content
|
|
562
|
-
except:
|
|
563
|
-
pass
|
|
564
|
-
return None
|
|
553
|
+
|
|
565
554
|
|
|
566
555
|
def is_directory_in_paths(path,directory):
|
|
567
556
|
return directory in path
|
|
@@ -16,10 +16,10 @@ import os
|
|
|
16
16
|
import shlex
|
|
17
17
|
from .string_clean import *
|
|
18
18
|
from .ssh_utils.utils import run_cmd,get_print_sudo_cmd,run_local_cmd,run_remote_cmd
|
|
19
|
-
from .file_utils
|
|
19
|
+
from .file_utils import is_file,is_dir,get_user_pass_host_key,is_exists
|
|
20
20
|
from .abstract_classes import run_pruned_func
|
|
21
21
|
from .string_utils import get_from_kwargs
|
|
22
|
-
|
|
22
|
+
from .path_utils import get_all_files
|
|
23
23
|
_FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
|
|
24
24
|
_CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
|
|
25
25
|
|
|
@@ -34,12 +34,12 @@ def string_in_keys(strings, kwargs):
|
|
|
34
34
|
return None
|
|
35
35
|
def make_dirs(path, exist_ok=True, **kwargs):
|
|
36
36
|
remote = get_user_pass_host_key(**kwargs)
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
if remote:
|
|
39
39
|
kwargs['cmd'] = f"mkdir -p {path}"
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
resp = run_pruned_func(run_cmd, **kwargs)
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
else:
|
|
44
44
|
os.makedirs(path, exist_ok=exist_ok)
|
|
45
45
|
return path
|
|
@@ -53,16 +53,15 @@ def make_path(path, home_dir=None, file=None, **kwargs):
|
|
|
53
53
|
# Detect whether this is a file or a folder
|
|
54
54
|
is_file = file if file is not None else ('.' in basename)
|
|
55
55
|
pieces = parts[:-1] if is_file else parts
|
|
56
|
-
|
|
56
|
+
|
|
57
57
|
full_dir = home_dir or '/'
|
|
58
58
|
for piece in pieces:
|
|
59
59
|
full_dir = os.path.join(full_dir, piece)
|
|
60
60
|
make_dirs(full_dir, exist_ok=True, **kwargs)
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
if is_file:
|
|
63
63
|
full_dir = os.path.join(full_dir, basename)
|
|
64
64
|
|
|
65
|
-
print(f"✅ full_dir == {full_dir}")
|
|
66
65
|
return full_dir
|
|
67
66
|
def get_rel_path(src,src_rel,dst,**kwargs):
|
|
68
67
|
if src.startswith(src_rel):
|
|
@@ -72,12 +71,12 @@ def get_rel_path(src,src_rel,dst,**kwargs):
|
|
|
72
71
|
rel_path = os.path.join(dst,nu_src)
|
|
73
72
|
return rel_path
|
|
74
73
|
def make_relative_path(src,src_rel,dst,**kwargs):
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
if src.startswith(src_rel):
|
|
77
76
|
rel_path = get_rel_path(src,src_rel,dst)
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
path = make_path(rel_path,**kwargs)
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
return path
|
|
82
81
|
|
|
83
82
|
def path_join(*args):
|
|
@@ -157,7 +156,7 @@ def write_to_path(
|
|
|
157
156
|
# shell command that fully overwrites
|
|
158
157
|
# (no append, replaces contents entirely)
|
|
159
158
|
base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
|
|
160
|
-
|
|
159
|
+
|
|
161
160
|
# optional sudo password injection
|
|
162
161
|
full_cmd = get_print_sudo_cmd(
|
|
163
162
|
cmd=base_cmd,
|
|
@@ -259,7 +258,7 @@ def copy_dirs(dirs, dst_root, src_rel=None, **kwargs):
|
|
|
259
258
|
# build destination path preserving relative structure
|
|
260
259
|
dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else dst_root
|
|
261
260
|
make_path(dst_path, **kwargs) # ensures directory exists
|
|
262
|
-
|
|
261
|
+
|
|
263
262
|
|
|
264
263
|
|
|
265
264
|
def copy_file(src, dst_root, src_rel=None, **kwargs):
|
|
@@ -278,7 +277,7 @@ def copy_file(src, dst_root, src_rel=None, **kwargs):
|
|
|
278
277
|
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
|
279
278
|
shutil.copy2(src, dst_path)
|
|
280
279
|
|
|
281
|
-
|
|
280
|
+
|
|
282
281
|
return dst_path
|
|
283
282
|
|
|
284
283
|
|
|
@@ -326,3 +325,21 @@ def get_content_lines(*args, **kwargs):
|
|
|
326
325
|
elif isinstance(contents, list):
|
|
327
326
|
return contents
|
|
328
327
|
return []
|
|
328
|
+
def collate_text_docs(directory=None):
|
|
329
|
+
return [read_from_file(item) for item in get_all_files(directory=directory)]
|
|
330
|
+
def get_content(*paths):
|
|
331
|
+
item_path = os.path.join(*paths)
|
|
332
|
+
if os.path.isfile(item_path):
|
|
333
|
+
try:
|
|
334
|
+
content = read_from_file(item_path)
|
|
335
|
+
return content
|
|
336
|
+
except:
|
|
337
|
+
pass
|
|
338
|
+
return None
|
|
339
|
+
def get_text_or_read(text=None,file_path=None):
|
|
340
|
+
text = text or ''
|
|
341
|
+
imports_js = {}
|
|
342
|
+
if not text and file_path and os.path.isfile(file_path):
|
|
343
|
+
text=read_from_file(file_path)
|
|
344
|
+
return text
|
|
345
|
+
##
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstract_utilities
|
|
3
|
-
Version: 0.2.2.
|
|
3
|
+
Version: 0.2.2.495
|
|
4
4
|
Summary: abstract_utilities is a collection of utility modules providing a variety of functions to aid in tasks such as data comparison, list manipulation, JSON handling, string manipulation, mathematical computations, and time operations.
|
|
5
5
|
Home-page: https://github.com/AbstractEndeavors/abstract_utilities
|
|
6
6
|
Author: putkoff
|