abstract-utilities 0.2.2.492__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.
Files changed (42) hide show
  1. abstract_utilities/__init__.py +0 -1
  2. abstract_utilities/file_utils/__init__.py +1 -2
  3. abstract_utilities/file_utils/imports/constants.py +6 -0
  4. abstract_utilities/file_utils/imports/imports.py +1 -1
  5. abstract_utilities/file_utils/imports/module_imports.py +1 -2
  6. abstract_utilities/file_utils/module_imports.py +12 -0
  7. abstract_utilities/file_utils/src/__init__.py +10 -0
  8. abstract_utilities/file_utils/src/file_filters.py +110 -0
  9. abstract_utilities/file_utils/src/file_reader.py +607 -0
  10. abstract_utilities/file_utils/src/file_utils.py +279 -0
  11. abstract_utilities/file_utils/src/filter_params.py +155 -0
  12. abstract_utilities/file_utils/src/find_collect.py +154 -0
  13. abstract_utilities/file_utils/src/initFunctionsGen.py +286 -0
  14. abstract_utilities/file_utils/src/map_utils.py +29 -0
  15. abstract_utilities/file_utils/src/pdf_utils.py +300 -0
  16. abstract_utilities/file_utils/src/type_checks.py +92 -0
  17. abstract_utilities/import_utils/__init__.py +2 -0
  18. abstract_utilities/import_utils/imports/__init__.py +4 -0
  19. abstract_utilities/import_utils/imports/constants.py +2 -0
  20. abstract_utilities/import_utils/imports/imports.py +4 -0
  21. abstract_utilities/import_utils/imports/module_imports.py +6 -0
  22. abstract_utilities/import_utils/imports/utils.py +30 -0
  23. abstract_utilities/import_utils/src/__init__.py +7 -0
  24. abstract_utilities/import_utils/src/clean_imports.py +122 -0
  25. abstract_utilities/import_utils/src/dot_utils.py +60 -0
  26. abstract_utilities/import_utils/src/extract_utils.py +42 -0
  27. abstract_utilities/import_utils/src/import_functions.py +46 -0
  28. abstract_utilities/import_utils/src/import_utils.py +299 -0
  29. abstract_utilities/import_utils/src/package_utils/__init__.py +139 -0
  30. abstract_utilities/import_utils/src/package_utils/context_utils.py +27 -0
  31. abstract_utilities/import_utils/src/package_utils/import_collectors.py +53 -0
  32. abstract_utilities/import_utils/src/package_utils/path_utils.py +28 -0
  33. abstract_utilities/import_utils/src/package_utils/safe_import.py +27 -0
  34. abstract_utilities/import_utils/src/package_utils.py +140 -0
  35. abstract_utilities/import_utils/src/sysroot_utils.py +57 -0
  36. abstract_utilities/path_utils.py +1 -12
  37. abstract_utilities/read_write_utils.py +66 -32
  38. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.495.dist-info}/METADATA +1 -1
  39. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.495.dist-info}/RECORD +42 -11
  40. {abstract_utilities-0.2.2.492.dist-info → abstract_utilities-0.2.2.495.dist-info}/top_level.txt +1 -0
  41. imports/__init__.py +36 -0
  42. {abstract_utilities-0.2.2.492.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
@@ -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
- def get_content(*paths):
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.file_utils.type_checks import is_file,is_dir,get_user_pass_host_key,is_exists
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
- print(remote)
37
+
38
38
  if remote:
39
39
  kwargs['cmd'] = f"mkdir -p {path}"
40
- print(kwargs)
40
+
41
41
  resp = run_pruned_func(run_cmd, **kwargs)
42
- print(resp)
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
- print(pieces)
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
- print(f"✅ full_dir == {full_dir}")
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
- print(f"src == {src}\nsrc_rel == {src_rel}\dst == {dst}")
74
+
76
75
  if src.startswith(src_rel):
77
76
  rel_path = get_rel_path(src,src_rel,dst)
78
- print(rel_path)
77
+
79
78
  path = make_path(rel_path,**kwargs)
80
- print(f"path == {path}")
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
- input(base_cmd)
159
+
161
160
  # optional sudo password injection
162
161
  full_cmd = get_print_sudo_cmd(
163
162
  cmd=base_cmd,
@@ -250,27 +249,44 @@ def read_from_file(file_path,**kwargs):
250
249
  with open(file_path, "r", encoding="utf-8") as f:
251
250
  return f.read()
252
251
 
253
- def copy_dirs(dirs,dst,src_rel=None,**kwargs):
252
+
253
+ def copy_dirs(dirs, dst_root, src_rel=None, **kwargs):
254
+ """
255
+ Recursively copy directory structures (without files) from dirs → dst_root.
256
+ """
254
257
  for src in dirs:
255
- if rel_path:
256
- dst = make_relative_path(src,src_rel,dst,**kwargs)
257
- make_path(dst,**kwargs)
258
-
259
- def copy_file(src,dst,rel_path=None,**kwargs):
260
-
261
- if rel_path:
262
- dst = make_relative_path(src,rel_path,dst,**kwargs)
263
- print(dst)
264
- if get_user_pass_host_key(**kwargs):
265
- contents=read_from_file(src,**kwargs)
266
- write_to_file(contents=contents,file_path=dst,**kwargs)
267
- else:
268
- shutil.copy(src,dst)
269
- print(dst)
270
- return dst
271
- def copy_files(files,dst,rel_path=None,**kwargs):
272
- for file in files:
273
- copy_file(src=file,dst=dst,rel_path=rel_path,**kwargs)
258
+ # build destination path preserving relative structure
259
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else dst_root
260
+ make_path(dst_path, **kwargs) # ensures directory exists
261
+
262
+
263
+
264
+ def copy_file(src, dst_root, src_rel=None, **kwargs):
265
+ """
266
+ Copy a single file to dst_root, preserving relative structure if src_rel provided.
267
+ Supports remote copy via read/write.
268
+ """
269
+ # derive destination file path
270
+ dst_path = make_relative_path(src, src_rel, dst_root, **kwargs) if src_rel else os.path.join(dst_root, os.path.basename(src))
271
+ make_path(dst_path, **kwargs)
272
+
273
+ if get_user_pass_host_key(**kwargs): # remote mode
274
+ contents = read_from_file(src, **kwargs)
275
+ write_to_file(contents=contents, file_path=dst_path, **kwargs)
276
+ else: # local
277
+ os.makedirs(os.path.dirname(dst_path), exist_ok=True)
278
+ shutil.copy2(src, dst_path)
279
+
280
+
281
+ return dst_path
282
+
283
+
284
+ def copy_files(files, dst_root, src_rel=None, **kwargs):
285
+ """
286
+ Copy a list of files to dst_root.
287
+ """
288
+ for src in files:
289
+ copy_file(src=src, dst_root=dst_root, src_rel=src_rel, **kwargs)
274
290
 
275
291
  def create_and_read_file(*args, **kwargs):
276
292
  """
@@ -309,3 +325,21 @@ def get_content_lines(*args, **kwargs):
309
325
  elif isinstance(contents, list):
310
326
  return contents
311
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.492
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