abstract-utilities 0.2.2.387__py3-none-any.whl → 0.2.2.480__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.

Files changed (63) hide show
  1. abstract_utilities/__init__.py +14 -43
  2. abstract_utilities/abstract_classes.py +49 -0
  3. abstract_utilities/class_utils.py +38 -3
  4. abstract_utilities/cmd_utils/imports/__init__.py +1 -0
  5. abstract_utilities/cmd_utils/imports/imports.py +10 -0
  6. abstract_utilities/cmd_utils/pexpect_utils.py +310 -0
  7. abstract_utilities/cmd_utils/user_utils.py +1 -1
  8. abstract_utilities/dynimport.py +7 -15
  9. abstract_utilities/env_utils/__init__.py +3 -0
  10. abstract_utilities/env_utils/abstractEnv.py +129 -0
  11. abstract_utilities/env_utils/envy_it.py +33 -0
  12. abstract_utilities/env_utils/imports/__init__.py +2 -0
  13. abstract_utilities/env_utils/imports/imports.py +8 -0
  14. abstract_utilities/env_utils/imports/utils.py +122 -0
  15. abstract_utilities/file_utils/__init__.py +3 -0
  16. abstract_utilities/file_utils/file_utils/__init__.py +8 -0
  17. abstract_utilities/file_utils/file_utils/file_filters.py +104 -0
  18. abstract_utilities/{robust_reader → file_utils/file_utils}/file_reader.py +5 -19
  19. abstract_utilities/{robust_readers/file_filters.py → file_utils/file_utils/file_utils.py} +5 -4
  20. abstract_utilities/{robust_readers → file_utils/file_utils}/filter_params.py +1 -38
  21. abstract_utilities/file_utils/file_utils/find_collect.py +154 -0
  22. abstract_utilities/file_utils/file_utils/imports/__init__.py +3 -0
  23. abstract_utilities/file_utils/file_utils/imports/constants.py +39 -0
  24. abstract_utilities/file_utils/file_utils/imports/file_functions.py +10 -0
  25. abstract_utilities/file_utils/file_utils/imports/imports.py +39 -0
  26. abstract_utilities/file_utils/file_utils/imports/module_imports.py +14 -0
  27. abstract_utilities/file_utils/file_utils/imports.py +10 -0
  28. abstract_utilities/file_utils/file_utils/map_utils.py +29 -0
  29. abstract_utilities/{robust_reader → file_utils/file_utils}/pdf_utils.py +1 -9
  30. abstract_utilities/file_utils/file_utils/type_checks.py +91 -0
  31. abstract_utilities/file_utils/imports/__init__.py +4 -0
  32. abstract_utilities/file_utils/imports/classes.py +381 -0
  33. abstract_utilities/file_utils/imports/clean_imps.py +158 -0
  34. abstract_utilities/file_utils/imports/constants.py +39 -0
  35. abstract_utilities/file_utils/imports/file_functions.py +10 -0
  36. abstract_utilities/file_utils/imports/imports.py +65 -0
  37. abstract_utilities/file_utils/imports/module_imports.py +13 -0
  38. abstract_utilities/file_utils/req.py +329 -0
  39. abstract_utilities/log_utils.py +1 -1
  40. abstract_utilities/path_utils.py +90 -6
  41. abstract_utilities/read_write_utils.py +250 -157
  42. abstract_utilities/robust_reader/__init__.py +1 -1
  43. abstract_utilities/robust_reader/imports/__init__.py +1 -0
  44. abstract_utilities/robust_reader/imports/imports.py +3 -0
  45. abstract_utilities/robust_readers/__init__.py +0 -1
  46. abstract_utilities/robust_readers/import_utils/__init__.py +1 -0
  47. abstract_utilities/robust_readers/import_utils/clean_imports.py +175 -0
  48. abstract_utilities/robust_readers/imports.py +8 -0
  49. abstract_utilities/robust_readers/initFuncGen.py +92 -76
  50. abstract_utilities/safe_utils.py +133 -0
  51. abstract_utilities/ssh_utils/__init__.py +3 -0
  52. abstract_utilities/ssh_utils/classes.py +127 -0
  53. abstract_utilities/ssh_utils/imports.py +10 -0
  54. abstract_utilities/ssh_utils/pexpect_utils.py +315 -0
  55. abstract_utilities/ssh_utils/utils.py +188 -0
  56. abstract_utilities/string_clean.py +40 -1
  57. abstract_utilities/string_utils.py +51 -0
  58. abstract_utilities/type_utils.py +25 -2
  59. {abstract_utilities-0.2.2.387.dist-info → abstract_utilities-0.2.2.480.dist-info}/METADATA +1 -1
  60. abstract_utilities-0.2.2.480.dist-info/RECORD +92 -0
  61. abstract_utilities-0.2.2.387.dist-info/RECORD +0 -52
  62. {abstract_utilities-0.2.2.387.dist-info → abstract_utilities-0.2.2.480.dist-info}/WHEEL +0 -0
  63. {abstract_utilities-0.2.2.387.dist-info → abstract_utilities-0.2.2.480.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,39 @@
1
+ from .imports import *
2
+ from .module_imports import *
3
+ @dataclass
4
+ class ScanConfig:
5
+ allowed_exts: Set[str]
6
+ unallowed_exts: Set[str]
7
+ exclude_types: Set[str]
8
+ exclude_dirs: List[str] = field(default_factory=list)
9
+ exclude_patterns: List[str] = field(default_factory=list)
10
+ DEFAULT_ALLOWED_EXTS: Set[str] = {
11
+ ".py", ".pyw", # python
12
+ ".js", ".jsx", ".ts", ".tsx", ".mjs", # JS/TS
13
+ ".html", ".htm", ".xml", # markup
14
+ ".css", ".scss", ".sass", ".less", # styles
15
+ ".json", ".yaml", ".yml", ".toml", ".ini", # configs
16
+ ".cfg", ".md", ".markdown", ".rst", # docs
17
+ ".sh", ".bash", ".env", # scripts/env
18
+ ".txt" # plain text
19
+ }
20
+
21
+ DEFAULT_EXCLUDE_TYPES: Set[str] = {
22
+ "image", "video", "audio", "presentation",
23
+ "spreadsheet", "archive", "executable"
24
+ }
25
+
26
+ # never want these—even if they sneak into ALLOWED
27
+ _unallowed = set(get_media_exts(DEFAULT_EXCLUDE_TYPES)) | {'.bak', '.shp', '.cpg', '.dbf', '.shx','.geojson',".pyc",'.shx','.geojson','.prj','.sbn','.sbx'}
28
+ DEFAULT_UNALLOWED_EXTS = {e for e in _unallowed if e not in DEFAULT_ALLOWED_EXTS}
29
+
30
+ DEFAULT_EXCLUDE_DIRS: Set[str] = {
31
+ "node_modules", "old","__pycache__", "backups", "backup", "backs", "trash", "depriciated", "old", "__init__"
32
+ }
33
+
34
+ DEFAULT_EXCLUDE_PATTERNS: Set[str] = {
35
+ "__init__*", "*.tmp", "*.log", "*.lock", "*.zip","*~"
36
+ }
37
+ REMOTE_RE = re.compile(r"^(?P<host>[^:\s]+@[^:\s]+):(?P<path>/.*)$")
38
+ AllowedPredicate = Optional[Callable[[str], bool]]
39
+ DEFAULT_EXCLUDE_FILE_PATTERNS=DEFAULT_EXCLUDE_PATTERNS
@@ -0,0 +1,10 @@
1
+ from .imports import *
2
+ def get_caller_path(i=None):
3
+ i = i or 1
4
+ frame = inspect.stack()[i]
5
+ return os.path.abspath(frame.filename)
6
+ def get_caller_dir(i=None):
7
+ i = i or 1
8
+ frame = inspect.stack()[i]
9
+ abspath = os.path.abspath(frame.filename)
10
+ return os.path.dirname(abspath)
@@ -0,0 +1,65 @@
1
+ # ============================================================
2
+ # abstract_utilities/imports/imports.py
3
+ # Global imports hub — everything imported here will be
4
+ # automatically available to any module that does:
5
+ # from ..imports import *
6
+ # ============================================================
7
+
8
+
9
+ import os
10
+ import sys, importlib,os
11
+ import sys, importlib, os, inspect
12
+ from pathlib import Path
13
+ import os,sys
14
+
15
+
16
+
17
+ from typing import *
18
+ import re
19
+
20
+ from typing import *
21
+ from types import MethodType
22
+ import os,re, sys, importlib, inspect, os, importlib.util, hashlib
23
+ import os,tempfile,shutil,logging,ezodf,fnmatch,pytesseract,pdfplumber
24
+ import pandas as pd
25
+ import geopandas as gpd
26
+ from datetime import datetime
27
+
28
+ from typing import *
29
+ from werkzeug.utils import secure_filename
30
+ from werkzeug.datastructures import FileStorage
31
+ from pdf2image import convert_from_path # only used for OCR fallback
32
+ # ---- Core standard library modules -------------------------
33
+ import os, sys, re, shlex, glob, platform, textwrap, subprocess, inspect, json, time
34
+ import tempfile, shutil, logging, pathlib, fnmatch, importlib, importlib.util, types
35
+
36
+ from datetime import datetime
37
+ from types import ModuleType
38
+
39
+ # ---- Dataclasses and typing --------------------------------
40
+ from dataclasses import dataclass, field
41
+ from typing import (
42
+ Any, Optional, List, Dict, Set, Tuple,
43
+ Iterable, Callable, Literal, Union, TypeVar
44
+ )
45
+
46
+ # ---- Common 3rd-party dependencies --------------------------
47
+ import pandas as pd
48
+ import geopandas as gpd
49
+ import pytesseract
50
+ import pdfplumber
51
+ import PyPDF2
52
+ import ezodf
53
+ from pdf2image import convert_from_path
54
+ from werkzeug.utils import secure_filename
55
+ from werkzeug.datastructures import FileStorage
56
+
57
+ # ---- Helpers ------------------------------------------------
58
+ import textwrap as tw
59
+ from pprint import pprint
60
+
61
+ # ============================================================
62
+ # AUTO-EXPORT ALL NON-PRIVATE NAMES
63
+ # ============================================================
64
+ __all__ = [name for name in globals() if not name.startswith("_")]
65
+
@@ -0,0 +1,13 @@
1
+ from .imports import *
2
+ from ...string_clean import eatAll
3
+ from ...list_utils import make_list
4
+ from ...type_utils import get_media_exts, is_media_type, MIME_TYPES, is_str
5
+ from ...ssh_utils import *
6
+ from ...env_utils import *
7
+ from ...read_write_utils import *
8
+ from ...abstract_classes import SingletonMeta
9
+ from ...log_utils import get_logFile
10
+ from ...class_utils import get_caller, get_caller_path, get_caller_dir
11
+ from ...ssh_utils import run_cmd
12
+
13
+ __all__ = [name for name in globals() if not name.startswith("_")]
@@ -0,0 +1,329 @@
1
+ # attach_functions.py — single helper you can import anywhere
2
+ # attach_dynamic.py
3
+ from __future__ import annotations
4
+ from .file_utils import define_defaults,get_files_and_dirs
5
+ from .imports import *
6
+ ABSPATH = os.path.abspath(__file__)
7
+ ABSROOT = os.path.dirname(ABSPATH)
8
+ def caller_path():
9
+ frame = inspect.stack()[1]
10
+ return os.path.abspath(frame.filename)
11
+ def _is_defined_here(mod: types.ModuleType, obj: object) -> bool:
12
+ try:
13
+ return inspect.getmodule(obj) is mod
14
+ except Exception:
15
+ return False
16
+
17
+ def _collect_callables(mod: types.ModuleType) -> Dict[str, Callable]:
18
+ out: Dict[str, Callable] = {}
19
+ names = getattr(mod, "__all__", None)
20
+ if names:
21
+ # trust the author's export list
22
+ for n in names:
23
+ fn = getattr(mod, n, None)
24
+ if callable(fn):
25
+ out[n] = fn
26
+ return out
27
+ # otherwise, discover top-level callables defined in this module
28
+ for n in dir(mod):
29
+ if n.startswith("_"):
30
+ continue
31
+ obj = getattr(mod, n, None)
32
+ if callable(obj) and _is_defined_here(mod, obj):
33
+ out[n] = obj
34
+ return out
35
+
36
+ def _import_module_by_name(name: str) -> Optional[types.ModuleType]:
37
+ try:
38
+ return importlib.import_module(name)
39
+ except Exception:
40
+ return None
41
+
42
+ def _import_module_by_path(pkg_name: str, base_dir: str, filename: str) -> Optional[types.ModuleType]:
43
+ mod_name = f"{pkg_name}.functions"
44
+ path = os.path.join(base_dir, filename)
45
+ spec = importlib.util.spec_from_file_location(mod_name, path)
46
+ if not spec or not spec.loader:
47
+ return None
48
+ mod = importlib.util.module_from_spec(spec)
49
+ sys.modules[mod_name] = mod
50
+ spec.loader.exec_module(mod)
51
+ return mod
52
+
53
+ def _walk_functions_package(pkg_name: str, pkg_mod: types.ModuleType) -> List[types.ModuleType]:
54
+ """Import all immediate submodules in the functions/ package."""
55
+ mods: List[types.ModuleType] = [pkg_mod]
56
+ pkg_dir = os.path.dirname(pkg_mod.__file__ or "")
57
+ for info in pkgutil.iter_modules([pkg_dir]):
58
+ # only import direct children (no recursion here; easy to add if you need)
59
+ child_name = f"{pkg_mod.__name__}.{info.name}"
60
+ m = _import_module_by_name(child_name)
61
+ if m:
62
+ mods.append(m)
63
+ return mods
64
+
65
+ def _discover_functions(base_pkg: str, *, hot_reload: bool) -> List[Tuple[str, Callable, str]]:
66
+ """
67
+ Returns a list of (export_name, callable, module_basename).
68
+ Works if you have base_pkg.functions.py or base_pkg/functions/ package.
69
+ """
70
+ # Prefer normal import of '<base_pkg>.functions'
71
+ fqn = f"{base_pkg}.functions"
72
+ mod = _import_module_by_name(fqn)
73
+
74
+ if mod is None:
75
+ # fallback: sibling functions.py, even without being a package
76
+ base = _import_module_by_name(base_pkg)
77
+ if not base or not getattr(base, "__file__", None):
78
+ return []
79
+ base_dir = os.path.dirname(base.__file__)
80
+ if os.path.isfile(os.path.join(base_dir, "functions.py")):
81
+ mod = _import_module_by_path(base_pkg, base_dir, "functions.py")
82
+ else:
83
+ return []
84
+
85
+ if hot_reload:
86
+ try:
87
+ mod = importlib.reload(mod) # type: ignore[arg-type]
88
+ except Exception:
89
+ pass
90
+
91
+ results: List[Tuple[str, Callable, str]] = []
92
+ modules: List[types.ModuleType]
93
+
94
+ if hasattr(mod, "__path__"): # it's a package: import children
95
+ modules = _walk_functions_package(base_pkg, mod)
96
+ else:
97
+ modules = [mod]
98
+
99
+ for m in modules:
100
+ exported = _collect_callables(m)
101
+ module_basename = m.__name__.split(".")[-1]
102
+ for name, fn in exported.items():
103
+ results.append((name, fn, module_basename))
104
+ return results
105
+
106
+ def attach_functionss(
107
+ self,
108
+ *,
109
+ base_pkg: Optional[str] = None,
110
+ hot_reload: bool = False,
111
+ prefix_with_module: bool = False,
112
+ on_collision: str = "last_wins", # or "error" or "skip"
113
+ ):
114
+ """
115
+ Attach discovered functions from '<base_pkg>.functions' onto `self`.
116
+
117
+ - base_pkg: package containing either functions.py or functions/ (defaults to the class' package)
118
+ - hot_reload: reload modules each call (handy during development)
119
+ - prefix_with_module: if True, attach as '<module>_<funcname>' to avoid name clashes
120
+ - on_collision: how to handle duplicate names: 'last_wins' | 'error' | 'skip'
121
+ """
122
+ if base_pkg is None:
123
+ # Infer from the class' module: e.g., "myapp.tabs.users.widgets" -> "myapp.tabs.users"
124
+ cls_mod = self.__class__.__module__
125
+ base_pkg = cls_mod.rsplit(".", 1)[0] if "." in cls_mod else cls_mod
126
+
127
+ discovered = _discover_functions(base_pkg, hot_reload=hot_reload)
128
+ seen: Dict[str, str] = {}
129
+
130
+ for name, fn, mod_base in discovered:
131
+ attr_name = f"{mod_base}_{name}" if prefix_with_module else name
132
+
133
+ if hasattr(self, attr_name):
134
+ if on_collision == "skip":
135
+ continue
136
+ if on_collision == "error":
137
+ raise RuntimeError(f"attach_functions collision on '{attr_name}' from module '{mod_base}'")
138
+ # last_wins: fall through
139
+
140
+ setattr(self, attr_name, fn)
141
+ seen[attr_name] = mod_base
142
+
143
+ # breadcrumb for debugging
144
+ setattr(self, "_attached_functions", sorted(seen.keys()))
145
+ return self
146
+
147
+ def attach_functions(
148
+ obj_or_cls,
149
+ base_pkg: str | None = None,
150
+ hot_reload: bool = True,
151
+ prefix_with_module: bool = False,
152
+ include_private: bool = True,
153
+ only_defined_here: bool = True, # don't attach stuff imported from elsewhere
154
+ ) -> list[str]:
155
+ """
156
+ Attach all free functions found in <base_pkg>.functions (module or package)
157
+ to the *class* of obj_or_cls. Returns the list of attached attribute names.
158
+ """
159
+ cls = obj_or_cls if inspect.isclass(obj_or_cls) else obj_or_cls.__class__
160
+ # Derive "<package>.functions" from the class's module unless you pass base_pkg
161
+ caller_mod = cls.__module__
162
+ pkg_root = (base_pkg or caller_mod.rsplit(".", 1)[0]).rstrip(".")
163
+ funcs_pkg_name = f"{pkg_root}.functions"
164
+
165
+ def _import(name: str) -> ModuleType | None:
166
+ try:
167
+ if hot_reload and name in sys.modules:
168
+ return importlib.reload(sys.modules[name])
169
+ return importlib.import_module(name)
170
+ except Exception:
171
+ return None
172
+
173
+ def _is_pkg(m: ModuleType) -> bool:
174
+ return hasattr(m, "__path__")
175
+
176
+ mod = _import(funcs_pkg_name)
177
+ if mod is None:
178
+ # Nothing to attach (no functions.py or functions/ next to your class)
179
+ setattr(cls, "_attached_functions", tuple())
180
+ return []
181
+
182
+ modules: list[ModuleType] = [mod]
183
+ if _is_pkg(mod):
184
+ # attach from every submodule under functions/
185
+ for it in pkgutil.iter_modules(mod.__path__):
186
+ sub = _import(f"{funcs_pkg_name}.{it.name}")
187
+ if sub is not None:
188
+ modules.append(sub)
189
+
190
+ attached: list[str] = []
191
+ for m in modules:
192
+ for name, obj in vars(m).items():
193
+ # only callables (skip classes), and keep them sane
194
+ if not callable(obj) or isinstance(obj, type):
195
+ continue
196
+ if only_defined_here and getattr(obj, "__module__", None) != m.__name__:
197
+ continue
198
+ if not include_private and name.startswith("_"):
199
+ continue
200
+ if name.startswith("__") and name.endswith("__"):
201
+ continue
202
+ attr = f"{m.__name__.rsplit('.', 1)[-1]}__{name}" if prefix_with_module else name
203
+ try:
204
+ setattr(cls, attr, obj) # set on CLASS → becomes bound method on instances
205
+ attached.append(attr)
206
+ except Exception:
207
+ # don't explode if one name collides; keep going
208
+ continue
209
+
210
+ # handy for debugging
211
+ try:
212
+ setattr(cls, "_attached_functions", tuple(attached))
213
+ except Exception:
214
+ pass
215
+ return attached
216
+
217
+
218
+
219
+ def clean_imports():
220
+ alls = str(list(set("""os,re,subprocess,sys,re,traceback,pydot, enum, inspect, sys, traceback, threading,json,traceback,logging,requests""".replace('\n','').replace(' ','').replace('\t','').split(','))))[1:-1].replace('"','').replace("'",'')
221
+ input(alls)
222
+ def isTab(item):
223
+ item_lower = item.lower()
224
+ for key in ['console','tab']:
225
+ if item_lower.endswith(key):
226
+ return True
227
+ return False
228
+ def get_dir(root,item):
229
+ if None in [root]:
230
+ return None
231
+ path = root
232
+ if item != None:
233
+ path = os.path.join(path,item)
234
+ return path
235
+ def isDir(root,item=None):
236
+ path = get_dir(root,item)
237
+ if path:
238
+ return os.path.isdir(path)
239
+ def check_dir_item(root,item=None):
240
+ return (item and isTab(item) and isDir(root,item))
241
+ def get_dirs(root = None):
242
+ root = root or ABSROOT
243
+ dirpaths = [get_dir(root,item) for item in os.listdir(root) if check_dir_item(root,item)]
244
+ return dirpaths
245
+ def ifFunctionsInFile(root):
246
+ items = [os.path.join(root, "functions"),os.path.join(root, "functions.py")]
247
+ for item in items:
248
+ if os.path.exists(item):
249
+ return item
250
+
251
+
252
+ def get_for_all_tabs(root = None):
253
+ root = root or caller_path()
254
+ if os.path.isfile(root):
255
+ root = os.path.dirname(root)
256
+ all_tabs = get_dirs(root = root)
257
+ for ROOT in all_tabs:
258
+ FUNCS_DIR = ifFunctionsInFile(ROOT)
259
+ if FUNCS_DIR == None:
260
+ for ROOT in get_dirs(root = ROOT):
261
+ apply_inits(ROOT)
262
+ else:
263
+ apply_inits(ROOT)
264
+
265
+
266
+ def apply_inits(ROOT):
267
+ FUNCS_DIR = ifFunctionsInFile(ROOT)
268
+
269
+
270
+ if_fun_dir = isDir(FUNCS_DIR)
271
+ if if_fun_dir != None:
272
+
273
+ if if_fun_dir:
274
+ CFG = define_defaults(allowed_exts='.py',
275
+ unallowed_exts = True,
276
+ exclude_types = True,
277
+ exclude_dirs = True,
278
+ exclude_patterns = True)
279
+ _,filepaths = get_files_and_dirs(FUNCS_DIR,cfg=CFG)
280
+
281
+ else:
282
+ filepaths = [FUNCS_DIR]
283
+
284
+ # Parse top-level def names
285
+ def extract_funcs(path: str):
286
+ funcs = []
287
+ for line in read_from_file(path).splitlines():
288
+ m = re.match(r"^def\s+([A-Za-z_]\w*)\s*\(self", line)
289
+ if m:
290
+ funcs.append(m.group(1))
291
+ return funcs
292
+
293
+ # Build functions/__init__.py that re-exports all discovered functions
294
+ import_lines = []
295
+ all_funcs = []
296
+ for fp in filepaths:
297
+ module = os.path.splitext(os.path.basename(fp))[0]
298
+ funcs = extract_funcs(fp)
299
+ if funcs:
300
+ import_lines.append(f"from .{module} import ({', '.join(funcs)})")
301
+ all_funcs.extend(funcs)
302
+ if if_fun_dir:
303
+ functions_init = "\n".join(import_lines) + ("\n" if import_lines else "")
304
+ write_to_file(contents=functions_init, file_path=os.path.join(FUNCS_DIR, "__init__.py"))
305
+
306
+ # Prepare the tuple literal of function names for import + loop
307
+ uniq_funcs = sorted(set(all_funcs))
308
+ func_tuple = ", ".join(uniq_funcs) + ("," if len(uniq_funcs) == 1 else "")
309
+
310
+ # Generate apiConsole/initFuncs.py using the safer setattr-loop
311
+ init_funcs_src = textwrap.dedent(f"""\
312
+
313
+
314
+ from .functions import ({func_tuple})
315
+
316
+ def initFuncs(self):
317
+ try:
318
+ for f in ({func_tuple}):
319
+ setattr(self, f.__name__, f)
320
+ except Exception as e:
321
+ logger.info(f"{{e}}")
322
+ return self
323
+ """)
324
+
325
+ write_to_file(contents=init_funcs_src, file_path=os.path.join(ROOT, "initFuncs.py"))
326
+
327
+ def call_for_all_tabs():
328
+ root = get_caller_dir(2)
329
+ get_for_all_tabs(root)
@@ -229,7 +229,7 @@ def initialize_call_log(value=None,
229
229
 
230
230
  print_or_log(full_message,level=log_level)
231
231
 
232
- def get_json_call_response(value, status_code, data=None, logMsg=None, callLog=False):
232
+ def get_json_call_response(value=None, status_code=None, data=None, logMsg=None, callLog=False):
233
233
  response_body = {}
234
234
  if status_code == 200:
235
235
  response_body["success"] = True
@@ -23,8 +23,13 @@ Date: 05/31/2023
23
23
  Version: 0.1.2
24
24
  """
25
25
  import os
26
- import platform
27
- from .read_write_utils import read_from_file
26
+ from .read_write_utils import read_from_file,write_to_file
27
+ from .string_clean import eatAll
28
+ from .list_utils import make_list
29
+ from .type_utils import get_media_exts, is_media_type,MIME_TYPES
30
+ from .safe_utils import safe_join
31
+ from .class_utils import get_caller_path,get_caller_dir
32
+
28
33
  def get_os_info():
29
34
  """
30
35
  Get Operating System Information
@@ -572,8 +577,87 @@ def remove_path(path=None):
572
577
  remove_directory(path)
573
578
  else:
574
579
  os.remove(path)
580
+ def get_safe_dirname(path=None):
581
+ if path:
582
+ path_str = str(path)
583
+ return os.path.dirname(path_str)
584
+ def get_safe_basename(path=None):
585
+ if path:
586
+ path_str = str(path)
587
+ return os.path.basename(path_str)
588
+ def get_safe_splitext(path=None,basename=None):
589
+ basename = basename or get_safe_basename(path=path)
590
+ if basename:
591
+ basename_str = str(basename)
592
+ filename,ext = os.path.splitext(basename_str)
593
+ return filename,ext
594
+ def get_safe_filename(path=None,basename=None):
595
+ filename,_ = get_safe_splitext(path=path,basename=basename)
596
+ return filename
597
+ def get_safe_ext(path=None,basename=None):
598
+ _,ext = get_safe_splitext(path=path,basename=basename)
599
+ return ext
600
+ def raw_create_dirs(*paths):
601
+ """Recursively create all directories along the given path."""
602
+ full_path = os.path.abspath(safe_join(*paths))
603
+ sub_parts = [p for p in full_path.split(os.sep) if p]
604
+
605
+ current_path = "/" if full_path.startswith(os.sep) else ""
606
+ for part in sub_parts:
607
+ current_path = safe_join(current_path, part)
608
+ os.makedirs(current_path, exist_ok=True)
609
+ return full_path
610
+
611
+
612
+ def create_dirs(directory, child=None):
613
+ """Create directory and optional child path safely."""
614
+ full_path = os.path.abspath(safe_join(directory, child))
615
+ if not os.path.exists(full_path):
616
+ raw_create_dirs(full_path)
617
+ return full_path
618
+
619
+
620
+ def get_base_dir(directory=None):
621
+ """Return given directory or _BASE_DIR fallback."""
622
+ return directory or _BASE_DIR
623
+
624
+
625
+ def create_base_path(directory=None, child=None):
626
+ """Join base dir with child."""
627
+ directory = get_base_dir(directory)
628
+ return safe_join(directory, child)
629
+
630
+
631
+ def create_base_dir(directory=None, child=None):
632
+ """Ensure existence of base directory path."""
633
+ full_path = create_base_path(directory, child)
634
+ if not os.path.exists(full_path):
635
+ raw_create_dirs(full_path)
636
+ return full_path
637
+
638
+
639
+
575
640
  def get_file_parts(path):
576
- dirName = os.path.dirname(path)
577
- baseName = os.path.basename(path)
578
- fileName, ext = os.path.splitext(baseName)
579
- return {"dirName": dirName, "baseName": baseName, "fileName": fileName, "ext": ext}
641
+
642
+ basename = get_safe_basename(path)
643
+ filename, ext = get_safe_splitext(basename=basename)
644
+
645
+ dirname = get_safe_dirname(path)
646
+ dirbase = get_safe_basename(dirname)
647
+
648
+ parent_dirname = get_safe_dirname(dirname)
649
+ parent_dirbase = get_safe_basename(parent_dirname)
650
+
651
+ super_dirname = get_safe_dirname(parent_dirname)
652
+ super_dirbase = get_safe_basename(super_dirname)
653
+
654
+ return {"dirname": dirname,
655
+ "basename": basename,
656
+ "filename": filename,
657
+ "ext": ext,
658
+ "dirbase":dirbase,
659
+ "parent_dirname":parent_dirname,
660
+ "parent_dirbase":parent_dirbase,
661
+ "super_dirname":super_dirname,
662
+ "super_dirbase":super_dirbase
663
+ }