abstract-utilities 0.2.2.540__py3-none-any.whl → 0.2.2.667__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of abstract-utilities might be problematic. Click here for more details.
- abstract_utilities/__init__.py +13 -4
- abstract_utilities/class_utils/abstract_classes.py +104 -34
- abstract_utilities/class_utils/caller_utils.py +57 -0
- abstract_utilities/class_utils/global_utils.py +35 -20
- abstract_utilities/class_utils/imports/imports.py +1 -1
- abstract_utilities/directory_utils/src/directory_utils.py +19 -1
- abstract_utilities/file_utils/imports/classes.py +59 -55
- abstract_utilities/file_utils/imports/imports.py +0 -4
- abstract_utilities/file_utils/imports/module_imports.py +1 -1
- abstract_utilities/file_utils/src/__init__.py +2 -3
- abstract_utilities/file_utils/src/file_filters/__init__.py +1 -0
- abstract_utilities/file_utils/src/file_filters/ensure_utils.py +490 -0
- abstract_utilities/file_utils/src/file_filters/filter_params.py +150 -0
- abstract_utilities/file_utils/src/file_filters/filter_utils.py +78 -0
- abstract_utilities/file_utils/src/file_filters/predicate_utils.py +44 -0
- abstract_utilities/file_utils/src/file_reader.py +0 -1
- abstract_utilities/file_utils/src/find_collect.py +10 -86
- abstract_utilities/file_utils/src/find_content.py +210 -0
- abstract_utilities/file_utils/src/initFunctionsGen.py +36 -23
- abstract_utilities/file_utils/src/initFunctionsGens.py +280 -0
- abstract_utilities/file_utils/src/reader_utils/__init__.py +4 -0
- abstract_utilities/file_utils/src/reader_utils/directory_reader.py +53 -0
- abstract_utilities/file_utils/src/reader_utils/file_reader.py +543 -0
- abstract_utilities/file_utils/src/reader_utils/file_readers.py +376 -0
- abstract_utilities/file_utils/src/reader_utils/imports.py +18 -0
- abstract_utilities/file_utils/src/reader_utils/pdf_utils.py +300 -0
- abstract_utilities/import_utils/circular_import_finder.py +222 -0
- abstract_utilities/import_utils/circular_import_finder2.py +118 -0
- abstract_utilities/import_utils/imports/__init__.py +1 -1
- abstract_utilities/import_utils/imports/init_imports.py +3 -0
- abstract_utilities/import_utils/imports/module_imports.py +4 -1
- abstract_utilities/import_utils/imports/utils.py +1 -1
- abstract_utilities/import_utils/src/__init__.py +1 -0
- abstract_utilities/import_utils/src/clean_imports.py +156 -25
- abstract_utilities/import_utils/src/dot_utils.py +11 -0
- abstract_utilities/import_utils/src/extract_utils.py +4 -0
- abstract_utilities/import_utils/src/import_functions.py +66 -2
- abstract_utilities/import_utils/src/import_utils.py +39 -0
- abstract_utilities/import_utils/src/layze_import_utils/__init__.py +2 -0
- abstract_utilities/import_utils/src/layze_import_utils/lazy_utils.py +41 -0
- abstract_utilities/import_utils/src/layze_import_utils/nullProxy.py +32 -0
- abstract_utilities/import_utils/src/nullProxy.py +30 -0
- abstract_utilities/import_utils/src/pkg_utils.py +58 -4
- abstract_utilities/import_utils/src/sysroot_utils.py +56 -1
- abstract_utilities/imports.py +3 -2
- abstract_utilities/json_utils/json_utils.py +11 -3
- abstract_utilities/log_utils/log_file.py +73 -24
- abstract_utilities/parse_utils/parse_utils.py +23 -0
- abstract_utilities/path_utils/imports/module_imports.py +1 -1
- abstract_utilities/path_utils/path_utils.py +32 -35
- abstract_utilities/read_write_utils/imports/imports.py +1 -1
- abstract_utilities/read_write_utils/read_write_utils.py +102 -32
- abstract_utilities/safe_utils/safe_utils.py +30 -0
- abstract_utilities/type_utils/__init__.py +5 -1
- abstract_utilities/type_utils/get_type.py +116 -0
- abstract_utilities/type_utils/imports/__init__.py +1 -0
- abstract_utilities/type_utils/imports/constants.py +134 -0
- abstract_utilities/type_utils/imports/module_imports.py +25 -1
- abstract_utilities/type_utils/is_type.py +455 -0
- abstract_utilities/type_utils/make_type.py +126 -0
- abstract_utilities/type_utils/mime_types.py +68 -0
- abstract_utilities/type_utils/type_utils.py +0 -877
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/METADATA +1 -1
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/RECORD +66 -41
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/WHEEL +0 -0
- {abstract_utilities-0.2.2.540.dist-info → abstract_utilities-0.2.2.667.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# --- auto-package bootstrap (run-safe) ---------------------------------
|
|
2
2
|
from ..imports import *
|
|
3
3
|
from .dot_utils import get_dot_range
|
|
4
|
-
from .sysroot_utils import get_sysroot
|
|
4
|
+
from .sysroot_utils import get_sysroot,get_import_with_sysroot,get_py_files,get_all_py_sysroots
|
|
5
|
+
from .extract_utils import get_all_py_file_paths
|
|
5
6
|
def clean_imports(imports,commaClean=True):
|
|
6
7
|
chars=["*"]
|
|
7
8
|
if not commaClean:
|
|
@@ -9,6 +10,13 @@ def clean_imports(imports,commaClean=True):
|
|
|
9
10
|
if isinstance(imports,str):
|
|
10
11
|
imports = imports.split(',')
|
|
11
12
|
return [eatElse(imp,chars=chars) for imp in imports if imp]
|
|
13
|
+
def get_dot_range(import_pkg):
|
|
14
|
+
count = 0
|
|
15
|
+
for char in import_pkg:
|
|
16
|
+
if char != '.':
|
|
17
|
+
break
|
|
18
|
+
count+=1
|
|
19
|
+
return count
|
|
12
20
|
def get_cleaned_import_list(line,commaClean=True):
|
|
13
21
|
cleaned_import_list=[]
|
|
14
22
|
if IMPORT_TAG in line:
|
|
@@ -17,7 +25,7 @@ def get_cleaned_import_list(line,commaClean=True):
|
|
|
17
25
|
return cleaned_import_list
|
|
18
26
|
def get_module_from_import(imp,path=None):
|
|
19
27
|
path = path or os.getcwd()
|
|
20
|
-
i = get_dot_range(
|
|
28
|
+
i = get_dot_range(imp)
|
|
21
29
|
imp = eatAll(imp,'.')
|
|
22
30
|
sysroot = get_sysroot(path,i)
|
|
23
31
|
return os.path.join(sysroot, imp)
|
|
@@ -42,5 +50,61 @@ def safe_import(name: str, *, package: str | None = None, member: str | None = N
|
|
|
42
50
|
mod = importlib.import_module(name, package=package)
|
|
43
51
|
return getattr(mod, member) if member else mod
|
|
44
52
|
|
|
53
|
+
def dynamic_import(module_path: str, namespace: dict, all_imports = None):
|
|
54
|
+
"""
|
|
55
|
+
Emulates:
|
|
56
|
+
from module_path import *
|
|
57
|
+
but includes private (_xxx) names too.
|
|
58
|
+
"""
|
|
59
|
+
all_imports = if_none_change(all_imports,True)
|
|
60
|
+
if module_path:
|
|
61
|
+
module = importlib.import_module(module_path)
|
|
62
|
+
# Import literally everything except dunders, unless you want them too.
|
|
63
|
+
names = [n for n in dir(module) if n and ((not all_imports and not n.startswith("_")) or all_imports)]
|
|
64
|
+
for name in names:
|
|
65
|
+
namespace[name] = getattr(module, name)
|
|
66
|
+
return module
|
|
67
|
+
def get_monorepo_root(directory=None,files=None):
|
|
68
|
+
directory = directory or get_initial_caller_dir()
|
|
69
|
+
|
|
70
|
+
py_files = get_all_py_file_paths(directory,add=True)
|
|
71
|
+
sysroots = get_all_py_sysroots(directory=directory,files=py_files)
|
|
72
|
+
monorepo_root = get_common_root(sysroots)
|
|
73
|
+
return monorepo_root
|
|
74
|
+
def switch_to_monorepo_root(directory=None,files=None):
|
|
75
|
+
monorepo_root = get_monorepo_root(directory=directory,files=files)
|
|
76
|
+
if str(monorepo_root) not in sys.path:
|
|
77
|
+
sys.path.insert(0, str(monorepo_root))
|
|
78
|
+
return str(monorepo_root)
|
|
79
|
+
def get_all_imports(directory=None,sysroot=None,globs=None):
|
|
80
|
+
globs = globs or get_true_globals() or globals()
|
|
81
|
+
directory = directory or get_initial_caller_dir()
|
|
82
|
+
files = collect_globs(directory=directory,allowed_exts='.py').get('files')
|
|
83
|
+
sysroot = sysroot or switch_to_monorepo_root(directory=directory,files=files)
|
|
84
|
+
for glo in files:
|
|
85
|
+
imp = get_import_with_sysroot(glo, sysroot)
|
|
86
|
+
dynamic_import(imp, globs)
|
|
87
|
+
def get_all_imports_for_class(self, directory=None, sysroot=None, include_private=True):
|
|
88
|
+
"""
|
|
89
|
+
Load all modules under `directory` and assign their exports as attributes
|
|
90
|
+
on the class instance (self).
|
|
91
|
+
"""
|
|
92
|
+
directory = directory or get_initial_caller_dir()
|
|
93
|
+
files = collect_globs(directory=directory, allowed_exts='.py').get("files")
|
|
94
|
+
|
|
95
|
+
# Compute sysroot (monorepo root)
|
|
96
|
+
sysroot = sysroot or switch_to_monorepo_root(directory=directory, files=files)
|
|
97
|
+
|
|
98
|
+
for glo in files:
|
|
99
|
+
mod_path = get_import_with_sysroot(glo, sysroot)
|
|
100
|
+
module = importlib.import_module(mod_path)
|
|
101
|
+
|
|
102
|
+
for name in dir(module):
|
|
103
|
+
if name.startswith("__"):
|
|
104
|
+
continue
|
|
105
|
+
if not include_private and name.startswith("_"):
|
|
106
|
+
continue
|
|
45
107
|
|
|
108
|
+
setattr(self, name, getattr(module, name))
|
|
46
109
|
|
|
110
|
+
return self
|
|
@@ -297,3 +297,42 @@ def attach_self_functions(
|
|
|
297
297
|
attached[out_name] = bound
|
|
298
298
|
|
|
299
299
|
return attached
|
|
300
|
+
def initFuncs(self, mode=None):
|
|
301
|
+
"""
|
|
302
|
+
Load functions in either dev (dynamic) or prod (static) mode.
|
|
303
|
+
"""
|
|
304
|
+
mode = mode or "dev"
|
|
305
|
+
|
|
306
|
+
logger = get_logFile(__name__)
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
base_pkg = self.__class__.__module__.rsplit('.', 1)[0]
|
|
310
|
+
|
|
311
|
+
if mode == "prod":
|
|
312
|
+
# All imports come from the auto-generated import script
|
|
313
|
+
imports_mod = importlib.import_module(f"{base_pkg}.imports.funcs_imports")
|
|
314
|
+
|
|
315
|
+
# Attach all exports
|
|
316
|
+
for name in getattr(imports_mod, "__all__", []):
|
|
317
|
+
func = getattr(imports_mod, name)
|
|
318
|
+
setattr(self, name, func.__get__(self))
|
|
319
|
+
|
|
320
|
+
return self
|
|
321
|
+
|
|
322
|
+
# --- DEV MODE: your existing dynamic loader ---
|
|
323
|
+
import inspect, pkgutil, importlib
|
|
324
|
+
pkg = importlib.import_module(base_pkg + ".functions")
|
|
325
|
+
|
|
326
|
+
existing = set(self.__dict__) | set(dir(self))
|
|
327
|
+
|
|
328
|
+
for _, module_name, _ in pkgutil.iter_modules(pkg.__path__):
|
|
329
|
+
mod = importlib.import_module(f"{pkg.__name__}.{module_name}")
|
|
330
|
+
|
|
331
|
+
for name, obj in inspect.getmembers(mod, inspect.isfunction):
|
|
332
|
+
if name not in existing:
|
|
333
|
+
setattr(self, name, obj.__get__(self))
|
|
334
|
+
|
|
335
|
+
except Exception as e:
|
|
336
|
+
logger.error(f"initFuncs({mode}) error: {e}")
|
|
337
|
+
|
|
338
|
+
return self
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from ...imports import *
|
|
2
|
+
from .nullProxy import nullProxy,nullProxy_logger
|
|
3
|
+
@lru_cache(maxsize=None)
|
|
4
|
+
def lazy_import_single(name: str):
|
|
5
|
+
"""
|
|
6
|
+
Import module safely. If unavailable, return NullProxy.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
if name in sys.modules:
|
|
10
|
+
return sys.modules[name]
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
module = importlib.import_module(name)
|
|
14
|
+
return module
|
|
15
|
+
except Exception as e:
|
|
16
|
+
nullProxy_logger.warning(
|
|
17
|
+
"[lazy_import] Failed to import '%s': %s",
|
|
18
|
+
name,
|
|
19
|
+
e,
|
|
20
|
+
)
|
|
21
|
+
return nullProxy(name)
|
|
22
|
+
|
|
23
|
+
def get_lazy_attr(module_name: str, *attrs):
|
|
24
|
+
obj = lazy_import(module_name)
|
|
25
|
+
|
|
26
|
+
for attr in attrs:
|
|
27
|
+
try:
|
|
28
|
+
obj = getattr(obj, attr)
|
|
29
|
+
except Exception:
|
|
30
|
+
return nullProxy(module_name, attrs)
|
|
31
|
+
|
|
32
|
+
return obj
|
|
33
|
+
def lazy_import(name: str, *attrs):
|
|
34
|
+
"""
|
|
35
|
+
Import module safely. If unavailable, return NullProxy.
|
|
36
|
+
"""
|
|
37
|
+
if attrs:
|
|
38
|
+
obj = get_lazy_attr(name, *attrs)
|
|
39
|
+
else:
|
|
40
|
+
obj = lazy_import_single(name)
|
|
41
|
+
return obj
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from ...imports import *
|
|
2
|
+
nullProxy_logger = logging.getLogger("abstract.lazy_import")
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class nullProxy:
|
|
6
|
+
"""
|
|
7
|
+
Safe, chainable, callable placeholder for missing modules/attributes.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, name, path=()):
|
|
11
|
+
self._name = name
|
|
12
|
+
self._path = path
|
|
13
|
+
|
|
14
|
+
def __getattr__(self, attr):
|
|
15
|
+
return nullProxy(self._name, self._path + (attr,))
|
|
16
|
+
|
|
17
|
+
def __call__(self, *args, **kwargs):
|
|
18
|
+
nullProxy_logger.warning(
|
|
19
|
+
"[lazy_import] Call to missing module/attr: %s.%s args=%s kwargs=%s",
|
|
20
|
+
self._name,
|
|
21
|
+
".".join(self._path),
|
|
22
|
+
args,
|
|
23
|
+
kwargs,
|
|
24
|
+
)
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
def __repr__(self):
|
|
28
|
+
full = ".".join((self._name, *self._path))
|
|
29
|
+
return f"<nullProxy {full}>"
|
|
30
|
+
|
|
31
|
+
def __bool__(self):
|
|
32
|
+
return False # safe in conditionals
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from ...imports import *
|
|
2
|
+
lazy_import_logger = logging.getLogger("abstract.lazy_import")
|
|
3
|
+
class nullProxy:
|
|
4
|
+
"""
|
|
5
|
+
Safe, chainable, callable placeholder for missing modules/attributes.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
def __init__(self, name, path=()):
|
|
9
|
+
self._name = name
|
|
10
|
+
self._path = path
|
|
11
|
+
|
|
12
|
+
def __getattr__(self, attr):
|
|
13
|
+
return nullProxy(self._name, self._path + (attr,))
|
|
14
|
+
|
|
15
|
+
def __call__(self, *args, **kwargs):
|
|
16
|
+
lazy_import_logger.warning(
|
|
17
|
+
"[lazy_import] Call to missing module/attr: %s.%s args=%s kwargs=%s",
|
|
18
|
+
self._name,
|
|
19
|
+
".".join(self._path),
|
|
20
|
+
args,
|
|
21
|
+
kwargs,
|
|
22
|
+
)
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
def __repr__(self):
|
|
26
|
+
full = ".".join((self._name, *self._path))
|
|
27
|
+
return f"<nullProxy {full}>"
|
|
28
|
+
|
|
29
|
+
def __bool__(self):
|
|
30
|
+
return False # safe in conditionals
|
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
# safe_import_utils.py
|
|
2
2
|
from ..imports import *
|
|
3
3
|
from .import_functions import *
|
|
4
|
+
from ...safe_utils import *
|
|
5
|
+
from .sysroot_utils import get_import_with_sysroot
|
|
6
|
+
def try_is_file(file_path):
|
|
7
|
+
try:
|
|
8
|
+
return os.path.isfile(file_path)
|
|
9
|
+
except:
|
|
10
|
+
return False
|
|
11
|
+
def try_is_dir(file_path):
|
|
12
|
+
try:
|
|
13
|
+
return os.path.isdir(file_path)
|
|
14
|
+
except:
|
|
15
|
+
return False
|
|
16
|
+
def try_join(*args):
|
|
17
|
+
try:
|
|
18
|
+
return safe_join(*args)
|
|
19
|
+
except:
|
|
20
|
+
return False
|
|
21
|
+
def get_pkg_or_init(pkg_path):
|
|
22
|
+
if pkg_path:
|
|
23
|
+
if try_is_file(pkg_path):
|
|
24
|
+
return pkg_path
|
|
25
|
+
pkg_py_path = f"{pkg_path}.py"
|
|
26
|
+
if try_is_file(pkg_py_path):
|
|
27
|
+
return pkg_py_path
|
|
28
|
+
pkg_init_path = try_join(pkg_path,'__init__.py')
|
|
29
|
+
if try_is_dir(pkg_path):
|
|
30
|
+
if os.path.isfile(pkg_init_path):
|
|
31
|
+
return pkg_init_path
|
|
32
|
+
|
|
33
|
+
|
|
4
34
|
|
|
5
35
|
def ensure_import_pkg_js(import_pkg_js,file_path=None):
|
|
6
36
|
import_pkg_js = import_pkg_js or {"context":{}}
|
|
@@ -79,18 +109,42 @@ def ensure_caller_package(caller_file: str, caller_globals: dict | None = None)
|
|
|
79
109
|
if caller_globals and caller_globals.get("__name__") == "__main__" and not caller_globals.get("__package__"):
|
|
80
110
|
caller_globals["__package__"] = pkg
|
|
81
111
|
return pkg
|
|
112
|
+
def get_init_dots(import_pkg):
|
|
113
|
+
count = 0
|
|
114
|
+
for char in import_pkg:
|
|
115
|
+
if char != '.':
|
|
116
|
+
break
|
|
117
|
+
count+=1
|
|
118
|
+
return count
|
|
119
|
+
def make_relative_pkg(import_pkg,file_path):
|
|
120
|
+
full_pkg = eatAll(import_pkg,'.')
|
|
121
|
+
if file_path:
|
|
122
|
+
dirname = file_path
|
|
123
|
+
dot_count = get_init_dots(import_pkg)
|
|
124
|
+
for i in range(dot_count):
|
|
125
|
+
dirname = os.path.dirname(dirname)
|
|
126
|
+
dirbase = os.path.basename(dirname)
|
|
127
|
+
full_pkg=f"{dirbase}.{full_pkg}"
|
|
128
|
+
return full_pkg
|
|
129
|
+
def is_local_import(import_pkg,file_path=None):
|
|
130
|
+
relative_pkg = get_module_from_import(import_pkg,file_path)
|
|
131
|
+
if get_pkg_or_init(relative_pkg):
|
|
132
|
+
return True
|
|
133
|
+
return False
|
|
82
134
|
def get_import_pkg(line):
|
|
83
135
|
if is_line_group_import(line):
|
|
84
136
|
return clean_line(line.split(FROM_TAG)[1].split(IMPORT_TAG)[0])
|
|
85
137
|
def get_imports_from_import_pkg(line):
|
|
86
138
|
if is_line_group_import(line):
|
|
87
139
|
return get_cleaned_import_list(line,commaClean=True)
|
|
88
|
-
def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None):
|
|
140
|
+
def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None,file_path=None):
|
|
89
141
|
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
90
142
|
imports = clean_imports(imports)
|
|
143
|
+
pkg_path = get_module_from_import(import_pkg,file_path)
|
|
144
|
+
local_import = get_pkg_or_init(pkg_path)
|
|
91
145
|
if import_pkg not in import_pkg_js:
|
|
92
146
|
i = len(import_pkg_js["context"]["nulines"])
|
|
93
|
-
import_pkg_js[import_pkg]={"imports":imports,"line":i}
|
|
147
|
+
import_pkg_js[import_pkg]={"imports":imports,"line":i,"file_path":file_path,"local_import":local_import,"is_local":is_local_import(import_pkg,file_path=file_path)}
|
|
94
148
|
import_line = f"from {import_pkg} import "
|
|
95
149
|
if import_pkg == "import":
|
|
96
150
|
import_line = IMPORT_TAG
|
|
@@ -98,12 +152,12 @@ def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None):
|
|
|
98
152
|
else:
|
|
99
153
|
import_pkg_js[import_pkg]["imports"]+=imports
|
|
100
154
|
return import_pkg_js
|
|
101
|
-
def update_import_pkg_js(line,import_pkg_js=None):
|
|
155
|
+
def update_import_pkg_js(line,import_pkg_js=None,file_path=None):
|
|
102
156
|
import_pkg_js = ensure_import_pkg_js(import_pkg_js)
|
|
103
157
|
if is_line_group_import(line):
|
|
104
158
|
import_pkg = get_import_pkg(line)
|
|
105
159
|
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)
|
|
160
|
+
import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=import_pkg_js,file_path=file_path)
|
|
107
161
|
else:
|
|
108
162
|
if len(import_pkg_js["context"]["nulines"]) >0 and line == '' and is_line_import(import_pkg_js["context"]["nulines"][-1]):
|
|
109
163
|
pass
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from ..imports import *
|
|
2
2
|
from .dot_utils import *
|
|
3
|
-
|
|
3
|
+
from .extract_utils import get_all_py_file_paths
|
|
4
|
+
def get_py_files(directory=None):
|
|
5
|
+
directory = directory or get_initial_caller_dir()
|
|
6
|
+
return get_all_py_file_paths(directory,add=True)
|
|
4
7
|
def ensure_on_path(p: Path):
|
|
5
8
|
s = str(p)
|
|
6
9
|
if s not in sys.path:
|
|
@@ -19,7 +22,59 @@ def get_dot_range_sysroot(filepath):
|
|
|
19
22
|
sysroot = get_sysroot(sysroot,dot_range)
|
|
20
23
|
|
|
21
24
|
return sysroot
|
|
25
|
+
def get_import_with_sysroot(file_path, sysroot):
|
|
26
|
+
"""
|
|
27
|
+
Rewrite imports like:
|
|
28
|
+
from imports.constants import *
|
|
29
|
+
into:
|
|
30
|
+
from <relative_path>.imports.constants import *
|
|
31
|
+
Where <relative_path> is computed relative to sysroot.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Absolute paths
|
|
36
|
+
file_dir = os.path.dirname(os.path.abspath(file_path))
|
|
37
|
+
sysroot = os.path.abspath(sysroot)
|
|
38
|
+
|
|
39
|
+
# Compute relative path
|
|
40
|
+
relpath = os.path.relpath(file_dir, sysroot)
|
|
41
|
+
|
|
42
|
+
bare_rel = eatAll(relpath,'.')
|
|
43
|
+
|
|
44
|
+
# Turn filesystem path into dotted python path
|
|
45
|
+
if relpath == ".":
|
|
46
|
+
dotted = ""
|
|
47
|
+
else:
|
|
48
|
+
dotted = ".".join(part for part in relpath.split(os.sep) if part)
|
|
49
|
+
if bare_rel.startswith('/') and dotted.startswith('.'):
|
|
50
|
+
dotted = dotted[1:]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Build final rewritten import
|
|
54
|
+
return dotted
|
|
55
|
+
def get_all_sysroots(files):
|
|
56
|
+
sysroots=[]
|
|
57
|
+
for glo in files:
|
|
58
|
+
imp = compute_dotted_and_sysroot(glo)
|
|
59
|
+
sysroots.append(imp[-1])
|
|
60
|
+
return sysroots
|
|
61
|
+
def get_shortest_sysroot(files):
|
|
62
|
+
sysroots = get_all_sysroots(files)
|
|
63
|
+
return get_shortest_path(*sysroots)
|
|
64
|
+
def get_all_py_sysroots(directory=None,files=None):
|
|
65
|
+
py_files = files or get_py_files(directory=directory)
|
|
66
|
+
return [compute_dotted_and_sysroot(glo)[1] for glo in py_files]
|
|
22
67
|
|
|
68
|
+
def get__imports(directory=None, sysroot=None):
|
|
69
|
+
directory = directory or get_caller_dir(1)
|
|
70
|
+
globs = collect_globs(directory, allowed_exts='.py')
|
|
71
|
+
globs = [glo for glo in globs.get('files') if glo]
|
|
72
|
+
sysroots = [compute_dotted_and_sysroot(glo)[1] for glo in globs]
|
|
73
|
+
# ⭐ Get unified monorepo root
|
|
74
|
+
monorepo_root = get_common_root(sysroots)
|
|
75
|
+
if str(monorepo_root) not in sys.path:
|
|
76
|
+
sys.path.insert(0, str(monorepo_root))
|
|
77
|
+
get_all_imports(directory=directory, sysroot=monorepo_root)
|
|
23
78
|
def is_import_or_init(sysroot,likely=None):
|
|
24
79
|
file_data = get_file_parts(sysroot)
|
|
25
80
|
nuroot = sysroot
|
abstract_utilities/imports.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import re,pexpect,shlex,ezodf,tiktoken,geopandas as gpd,os,PyPDF2,json,tempfile,requests
|
|
3
3
|
import textwrap,pdfplumber,math,hashlib,pandas as pd,platform,textwrap as tw,glob,asyncio
|
|
4
|
-
import fnmatch,importlib,shutil,sys,time,threading,posixpath,importlib.util,types
|
|
4
|
+
import fnmatch,importlib,shutil,sys,time,threading,posixpath,importlib.util,types, logging
|
|
5
5
|
import subprocess,pytesseract,queue,logging,functools,pathlib,pkgutil,inspect
|
|
6
6
|
from typing import *
|
|
7
7
|
from datetime import timedelta,datetime
|
|
8
8
|
from flask import jsonify
|
|
9
9
|
from logging.handlers import RotatingFileHandler
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from functools import reduce
|
|
11
|
+
from functools import reduce,lru_cache
|
|
12
12
|
from types import MethodType,ModuleType
|
|
13
13
|
from werkzeug.utils import secure_filename
|
|
14
14
|
from werkzeug.datastructures import FileStorage
|
|
@@ -16,3 +16,4 @@ from pdf2image import convert_from_path # only used for OCR fallback
|
|
|
16
16
|
from dataclasses import dataclass,field,asdict
|
|
17
17
|
from pprint import pprint
|
|
18
18
|
from dotenv import load_dotenv
|
|
19
|
+
from types import MethodType
|
|
@@ -26,6 +26,13 @@ from .imports import *
|
|
|
26
26
|
|
|
27
27
|
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
28
28
|
logger = logging.getLogger(__name__)
|
|
29
|
+
def get_keys(mapping,typ=None):
|
|
30
|
+
typ = typ or set
|
|
31
|
+
if isinstance(mapping,dict):
|
|
32
|
+
mapping = mapping.keys()
|
|
33
|
+
return typ(mapping)
|
|
34
|
+
def make_key_map(dict_obj):
|
|
35
|
+
return {k:get_keys(v) for k,v in dict_obj.items()}
|
|
29
36
|
def convert_and_normalize_values(values):
|
|
30
37
|
for value in values:
|
|
31
38
|
if isinstance(value, str):
|
|
@@ -116,10 +123,11 @@ def safe_dump_to_file(data, file_path=None, ensure_ascii=False, indent=4, *args,
|
|
|
116
123
|
else:
|
|
117
124
|
logger.error("file_path and data must be provided to safe_dump_to_file")
|
|
118
125
|
|
|
119
|
-
def safe_read_from_json(
|
|
126
|
+
def safe_read_from_json(file_path,*args,**kwargs):
|
|
120
127
|
is_read=True
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
valid_file_path = get_file_path(file_path,*args,is_read=is_read,**kwargs)
|
|
123
131
|
if valid_file_path:
|
|
124
132
|
file_path = valid_file_path
|
|
125
133
|
try:
|
|
@@ -1,41 +1,90 @@
|
|
|
1
1
|
from .imports import *
|
|
2
|
-
|
|
2
|
+
import os, sys, inspect, logging
|
|
3
|
+
from logging.handlers import RotatingFileHandler
|
|
4
|
+
|
|
5
|
+
PACKAGE_NAME = "abstract_utilities" # ← update if needed
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _resolve_log_root():
|
|
9
|
+
"""
|
|
10
|
+
Returns a safe writable logging directory depending on environment:
|
|
11
|
+
- If running in a virtualenv → <venv>/.logs/<package>
|
|
12
|
+
- Else if user writable → ~/.cache/<package>/logs
|
|
13
|
+
- Else → /var/log/<package>
|
|
14
|
+
"""
|
|
15
|
+
# 1) Virtualenv or Conda environment
|
|
16
|
+
venv = os.getenv("VIRTUAL_ENV") or os.getenv("CONDA_PREFIX")
|
|
17
|
+
if venv:
|
|
18
|
+
root = os.path.join(venv, ".logs", PACKAGE_NAME)
|
|
19
|
+
os.makedirs(root, exist_ok=True)
|
|
20
|
+
return root
|
|
21
|
+
|
|
22
|
+
# 2) User home cache folder
|
|
23
|
+
home = os.path.expanduser("~")
|
|
24
|
+
user_cache_root = os.path.join(home, ".cache", PACKAGE_NAME, "logs")
|
|
25
|
+
try:
|
|
26
|
+
os.makedirs(user_cache_root, exist_ok=True)
|
|
27
|
+
return user_cache_root
|
|
28
|
+
except PermissionError:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
# 3) Last resort: system log dir (requires correct service user permissions)
|
|
32
|
+
system_root = f"/var/log/{PACKAGE_NAME}"
|
|
33
|
+
try:
|
|
34
|
+
os.makedirs(system_root, exist_ok=True)
|
|
35
|
+
return system_root
|
|
36
|
+
except PermissionError:
|
|
37
|
+
# Fail-safe fallback to /tmp
|
|
38
|
+
fallback = f"/tmp/{PACKAGE_NAME}/logs"
|
|
39
|
+
os.makedirs(fallback, exist_ok=True)
|
|
40
|
+
return fallback
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
LOG_ROOT = _resolve_log_root()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_logFile(bpName=None, maxBytes=100_000, backupCount=3):
|
|
3
47
|
"""
|
|
4
|
-
|
|
5
|
-
|
|
48
|
+
A logger that always writes to a safe OS-appropriate path.
|
|
49
|
+
Works even when installed through pip.
|
|
6
50
|
"""
|
|
7
51
|
if bpName is None:
|
|
8
|
-
# Find the first frame outside logging_utils.py
|
|
9
52
|
frame_idx = _find_caller_frame_index()
|
|
10
53
|
frame_info = inspect.stack()[frame_idx]
|
|
11
|
-
caller_path = frame_info.filename
|
|
54
|
+
caller_path = frame_info.filename
|
|
12
55
|
bpName = os.path.splitext(os.path.basename(caller_path))[0]
|
|
13
56
|
del frame_info
|
|
14
57
|
|
|
15
|
-
|
|
16
|
-
log_path = os.path.join(log_dir, f"{bpName}.log")
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(bpName)
|
|
58
|
+
logger = logging.getLogger(f"{PACKAGE_NAME}.{bpName}")
|
|
19
59
|
logger.setLevel(logging.INFO)
|
|
20
60
|
|
|
21
61
|
if not logger.handlers:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
print(f"{e}")
|
|
62
|
+
log_file = os.path.join(LOG_ROOT, f"{bpName}.log")
|
|
63
|
+
handler = RotatingFileHandler(log_file, maxBytes=maxBytes, backupCount=backupCount)
|
|
64
|
+
|
|
65
|
+
fmt = "%(asctime)s - %(levelname)s - %(pathname)s:%(lineno)d - %(message)s"
|
|
66
|
+
formatter = logging.Formatter(fmt)
|
|
67
|
+
handler.setFormatter(formatter)
|
|
68
|
+
|
|
69
|
+
logger.addHandler(handler)
|
|
70
|
+
|
|
71
|
+
# Console handler (optional; can disable for gunicorn)
|
|
72
|
+
console = logging.StreamHandler(sys.stdout)
|
|
73
|
+
console.setFormatter(formatter)
|
|
74
|
+
logger.addHandler(console)
|
|
75
|
+
|
|
37
76
|
return logger
|
|
38
77
|
|
|
78
|
+
|
|
79
|
+
def _find_caller_frame_index():
|
|
80
|
+
"""Find the correct caller module outside this logger."""
|
|
81
|
+
for idx, frame_info in enumerate(inspect.stack()):
|
|
82
|
+
if idx == 0:
|
|
83
|
+
continue
|
|
84
|
+
module = inspect.getmodule(frame_info.frame)
|
|
85
|
+
if module and module.__name__ not in (__name__, "logging"):
|
|
86
|
+
return idx
|
|
87
|
+
return 1
|
|
39
88
|
def _find_caller_frame_index():
|
|
40
89
|
"""
|
|
41
90
|
Scan up the call stack until we find a frame whose module is NOT logging_utils.
|
|
@@ -64,6 +64,29 @@ def detect_language_from_text(text: str):
|
|
|
64
64
|
|
|
65
65
|
likely = [lang for lang, score in scores.items() if score == max_score]
|
|
66
66
|
return likely[0] if len(likely) == 1 else 'uncertain'
|
|
67
|
+
def get_tripple_string(string):
|
|
68
|
+
nustring = ''
|
|
69
|
+
for i in range(3):
|
|
70
|
+
nustring +=string
|
|
71
|
+
return nustring
|
|
72
|
+
def get_within_quotes(text,quotes=None):
|
|
73
|
+
quotes_strings = quotes or ["'",'"']
|
|
74
|
+
in_quotes = []
|
|
75
|
+
for quotes_string in quotes_strings:
|
|
76
|
+
if not isinstance(quotes_string,list):
|
|
77
|
+
tripple= get_tripple_string(quotes_string)
|
|
78
|
+
texts = [text]
|
|
79
|
+
if tripple in text:
|
|
80
|
+
texts= text.split(tripple)
|
|
81
|
+
for text_part in texts:
|
|
82
|
+
quote_count = len(text_part) - len(text_part.replace(quotes_string,''))
|
|
83
|
+
quote_spl = text_part.split(quotes_string)
|
|
84
|
+
in_quotes+=[quote_spl[i] for i in range(quote_count) if ((i == 1 or i%2 != float(0)) and len(quote_spl) > i)]
|
|
85
|
+
else:
|
|
86
|
+
texts= text.split(quotes_string[0])
|
|
87
|
+
for text in texts:
|
|
88
|
+
in_quotes.append(text.split(quotes_string[1])[0])
|
|
89
|
+
return in_quotes
|
|
67
90
|
|
|
68
91
|
def search_code(code_languages, parts):
|
|
69
92
|
return [data for datas in parts for data in make_list(datas)
|
|
@@ -2,7 +2,7 @@ from ...string_utils import eatAll
|
|
|
2
2
|
from ...list_utils import make_list
|
|
3
3
|
from ...type_utils import get_media_exts, is_media_type,MIME_TYPES
|
|
4
4
|
from ...safe_utils import safe_join,get_slash
|
|
5
|
-
from ...class_utils import get_caller_path,get_caller_dir
|
|
5
|
+
from ...class_utils import get_caller_path,get_caller_dir,get_initial_caller,get_initial_caller_dir
|
|
6
6
|
from ...file_utils import is_file,is_dir,is_exists
|
|
7
7
|
from ...ssh_utils import is_file,is_dir,is_exists
|
|
8
8
|
from ...directory_utils import *
|