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.
- abstract_utilities/__init__.py +14 -43
- abstract_utilities/abstract_classes.py +49 -0
- abstract_utilities/class_utils.py +38 -3
- abstract_utilities/cmd_utils/imports/__init__.py +1 -0
- abstract_utilities/cmd_utils/imports/imports.py +10 -0
- abstract_utilities/cmd_utils/pexpect_utils.py +310 -0
- abstract_utilities/cmd_utils/user_utils.py +1 -1
- abstract_utilities/dynimport.py +7 -15
- abstract_utilities/env_utils/__init__.py +3 -0
- abstract_utilities/env_utils/abstractEnv.py +129 -0
- abstract_utilities/env_utils/envy_it.py +33 -0
- abstract_utilities/env_utils/imports/__init__.py +2 -0
- abstract_utilities/env_utils/imports/imports.py +8 -0
- abstract_utilities/env_utils/imports/utils.py +122 -0
- abstract_utilities/file_utils/__init__.py +3 -0
- abstract_utilities/file_utils/file_utils/__init__.py +8 -0
- abstract_utilities/file_utils/file_utils/file_filters.py +104 -0
- abstract_utilities/{robust_reader → file_utils/file_utils}/file_reader.py +5 -19
- abstract_utilities/{robust_readers/file_filters.py → file_utils/file_utils/file_utils.py} +5 -4
- abstract_utilities/{robust_readers → file_utils/file_utils}/filter_params.py +1 -38
- abstract_utilities/file_utils/file_utils/find_collect.py +154 -0
- abstract_utilities/file_utils/file_utils/imports/__init__.py +3 -0
- abstract_utilities/file_utils/file_utils/imports/constants.py +39 -0
- abstract_utilities/file_utils/file_utils/imports/file_functions.py +10 -0
- abstract_utilities/file_utils/file_utils/imports/imports.py +39 -0
- abstract_utilities/file_utils/file_utils/imports/module_imports.py +14 -0
- abstract_utilities/file_utils/file_utils/imports.py +10 -0
- abstract_utilities/file_utils/file_utils/map_utils.py +29 -0
- abstract_utilities/{robust_reader → file_utils/file_utils}/pdf_utils.py +1 -9
- abstract_utilities/file_utils/file_utils/type_checks.py +91 -0
- abstract_utilities/file_utils/imports/__init__.py +4 -0
- abstract_utilities/file_utils/imports/classes.py +381 -0
- abstract_utilities/file_utils/imports/clean_imps.py +158 -0
- abstract_utilities/file_utils/imports/constants.py +39 -0
- abstract_utilities/file_utils/imports/file_functions.py +10 -0
- abstract_utilities/file_utils/imports/imports.py +65 -0
- abstract_utilities/file_utils/imports/module_imports.py +13 -0
- abstract_utilities/file_utils/req.py +329 -0
- abstract_utilities/log_utils.py +1 -1
- abstract_utilities/path_utils.py +90 -6
- abstract_utilities/read_write_utils.py +250 -157
- abstract_utilities/robust_reader/__init__.py +1 -1
- abstract_utilities/robust_reader/imports/__init__.py +1 -0
- abstract_utilities/robust_reader/imports/imports.py +3 -0
- abstract_utilities/robust_readers/__init__.py +0 -1
- abstract_utilities/robust_readers/import_utils/__init__.py +1 -0
- abstract_utilities/robust_readers/import_utils/clean_imports.py +175 -0
- abstract_utilities/robust_readers/imports.py +8 -0
- abstract_utilities/robust_readers/initFuncGen.py +92 -76
- abstract_utilities/safe_utils.py +133 -0
- abstract_utilities/ssh_utils/__init__.py +3 -0
- abstract_utilities/ssh_utils/classes.py +127 -0
- abstract_utilities/ssh_utils/imports.py +10 -0
- abstract_utilities/ssh_utils/pexpect_utils.py +315 -0
- abstract_utilities/ssh_utils/utils.py +188 -0
- abstract_utilities/string_clean.py +40 -1
- abstract_utilities/string_utils.py +51 -0
- abstract_utilities/type_utils.py +25 -2
- {abstract_utilities-0.2.2.387.dist-info → abstract_utilities-0.2.2.480.dist-info}/METADATA +1 -1
- abstract_utilities-0.2.2.480.dist-info/RECORD +92 -0
- abstract_utilities-0.2.2.387.dist-info/RECORD +0 -52
- {abstract_utilities-0.2.2.387.dist-info → abstract_utilities-0.2.2.480.dist-info}/WHEEL +0 -0
- {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)
|
abstract_utilities/log_utils.py
CHANGED
|
@@ -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
|
abstract_utilities/path_utils.py
CHANGED
|
@@ -23,8 +23,13 @@ Date: 05/31/2023
|
|
|
23
23
|
Version: 0.1.2
|
|
24
24
|
"""
|
|
25
25
|
import os
|
|
26
|
-
import
|
|
27
|
-
from .
|
|
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
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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
|
+
}
|