abstract-utilities 0.2.2.449__py3-none-any.whl → 0.2.2.476__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 +18 -44
- 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/compare_utils/__init__.py +3 -0
- abstract_utilities/compare_utils/best_match.py +150 -0
- abstract_utilities/{compare_utils.py → compare_utils/compare_utils.py} +1 -1
- abstract_utilities/compare_utils/find_value.py +105 -0
- 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 +13 -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 +82 -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/json_utils.py +35 -0
- abstract_utilities/log_utils.py +14 -3
- abstract_utilities/path_utils.py +90 -6
- abstract_utilities/read_write_utils.py +176 -154
- 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 +48 -0
- abstract_utilities/type_utils.py +25 -2
- {abstract_utilities-0.2.2.449.dist-info → abstract_utilities-0.2.2.476.dist-info}/METADATA +15 -4
- abstract_utilities-0.2.2.476.dist-info/RECORD +92 -0
- {abstract_utilities-0.2.2.449.dist-info → abstract_utilities-0.2.2.476.dist-info}/WHEEL +1 -1
- abstract_utilities-0.2.2.449.dist-info/RECORD +0 -49
- {abstract_utilities-0.2.2.449.dist-info → abstract_utilities-0.2.2.476.dist-info}/top_level.txt +0 -0
|
@@ -1,115 +1,40 @@
|
|
|
1
1
|
"""
|
|
2
2
|
read_write_utils.py
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
-------------------
|
|
4
|
+
Unified read/write utility for safe file operations.
|
|
5
|
+
Supports:
|
|
6
|
+
- Writing content to a file
|
|
7
|
+
- Reading content from a file
|
|
8
|
+
- Creating and reading if missing
|
|
9
|
+
- Detecting file/content params via positional args or kwargs
|
|
6
10
|
|
|
7
11
|
Usage:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
1. Write content to a file.
|
|
11
|
-
2. Read content from a file.
|
|
12
|
-
3. Check if a string has a file extension.
|
|
13
|
-
4. Read from or write to a file depending on the number of arguments.
|
|
14
|
-
5. Create a file if it does not exist, then read from it.
|
|
12
|
+
from abstract_utilities.read_write_utils import *
|
|
13
|
+
"""
|
|
15
14
|
|
|
16
|
-
Each function includes a docstring to further explain its purpose, input parameters, and return values.
|
|
17
15
|
import os
|
|
16
|
+
import shlex
|
|
17
|
+
from .ssh_utils.utils import run_cmd,get_print_sudo_cmd,run_local_cmd,run_remote_cmd
|
|
18
|
+
from .file_utils.file_utils.type_checks import is_file,is_dir
|
|
19
|
+
from .abstract_classes import run_pruned_func
|
|
20
|
+
_FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
|
|
21
|
+
_CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
|
|
18
22
|
|
|
19
|
-
# File and Directory Operations
|
|
20
|
-
os.rename(src, dst) # Rename a file or directory
|
|
21
|
-
os.remove(path) # Remove a file
|
|
22
|
-
os.unlink(path) # Alias for os.remove()
|
|
23
|
-
os.rmdir(path) # Remove an empty directory
|
|
24
|
-
os.makedirs(path) # Create directories recursively
|
|
25
|
-
os.makedirs(path, exist_ok=True) # Create directories, ignore if exists
|
|
26
|
-
os.mkdir(path) # Create a single directory
|
|
27
|
-
os.listdir(path) # List files and directories in a path
|
|
28
|
-
os.chdir(path) # Change current working directory
|
|
29
|
-
os.getcwd() # Get current working directory
|
|
30
|
-
os.stat(path) # Get file/directory information
|
|
31
|
-
os.lstat(path) # Get symbolic link information
|
|
32
|
-
os.symlink(src, dst) # Create a symbolic link
|
|
33
|
-
os.readlink(path) # Read the target of a symbolic link
|
|
34
|
-
os.getcwd() # Get current working directory
|
|
35
|
-
os.chdir(path) # Change current working directory
|
|
36
|
-
|
|
37
|
-
# File and Directory Information
|
|
38
|
-
os.path.exists(path) # Check if a path exists
|
|
39
|
-
os.path.isfile(path) # Check if a path points to a file
|
|
40
|
-
os.path.isdir(path) # Check if a path points to a directory
|
|
41
|
-
os.path.islink(path) # Check if a path points to a symbolic link
|
|
42
|
-
os.path.abspath(path) # Get the absolute path of a file/directory
|
|
43
|
-
os.path.basename(path) # Get the base name of a path
|
|
44
|
-
os.path.dirname(path) # Get the directory name of a path
|
|
45
|
-
os.path.join(path1, path2, ...) # Join path components into a single path
|
|
46
|
-
|
|
47
|
-
# File Permissions
|
|
48
|
-
os.chmod(path, mode) # Change file permissions
|
|
49
|
-
os.access(path, mode) # Check if a file is accessible with given mode
|
|
50
|
-
|
|
51
|
-
# File Times
|
|
52
|
-
os.path.getatime(path) # Get last access time of a file
|
|
53
|
-
os.path.getmtime(path) # Get last modification time of a file
|
|
54
|
-
os.path.getctime(path) # Get creation time of a file
|
|
55
|
-
os.utime(path, times) # Set access and modification times
|
|
56
|
-
|
|
57
|
-
# Working with Paths
|
|
58
|
-
os.path.split(path) # Split a path into (head, tail)
|
|
59
|
-
os.path.splitext(path) # Split a path into (root, ext)
|
|
60
|
-
os.path.normpath(path) # Normalize a path (e.g., convert slashes)
|
|
61
|
-
|
|
62
|
-
# Other
|
|
63
|
-
os.path.samefile(path1, path2) # Check if two paths refer to the same file
|
|
64
|
-
|
|
65
|
-
# Directory Traversal
|
|
66
|
-
for root, dirs, files in os.walk(top, topdown=True):
|
|
67
|
-
# Traverse a directory tree, yielding root, dirs, and files lists
|
|
68
|
-
|
|
69
|
-
# Temporary Files and Directories
|
|
70
|
-
import tempfile
|
|
71
|
-
tempfile.mkstemp() # Create a temporary file
|
|
72
|
-
tempfile.mkdtemp() # Create a temporary directory
|
|
73
|
-
tempfile.TemporaryFile() # Create a temporary file object
|
|
74
|
-
|
|
75
|
-
# Environment Variables
|
|
76
|
-
os.environ # Dictionary of environment variables
|
|
77
|
-
os.environ['VAR_NAME'] # Access an environment variable
|
|
78
|
-
os.environ.get('VAR_NAME') # Access an environment variable (with default)
|
|
79
|
-
|
|
80
|
-
# Path Manipulation
|
|
81
|
-
os.path.abspath(path) # Convert relative path to absolute path
|
|
82
|
-
os.path.join(path1, path2, ...) # Join paths together
|
|
83
|
-
os.path.split(path) # Split a path into directory and filename
|
|
84
|
-
os.path.dirname(path) # Get the directory part of a path
|
|
85
|
-
os.path.basename(path) # Get the filename part of a path
|
|
86
|
-
os.path.exists(path) # Check if a path exists
|
|
87
|
-
os.path.isfile(path) # Check if a path points to a file
|
|
88
|
-
os.path.isdir(path) # Check if a path points to a directory
|
|
89
|
-
|
|
90
|
-
# File Permissions
|
|
91
|
-
os.chmod(path, mode) # Change file permissions
|
|
92
|
-
|
|
93
|
-
# Miscellaneous
|
|
94
|
-
os.getpid() # Get the current process ID
|
|
95
|
-
os.getlogin() # Get the name of the logged-in user
|
|
96
|
-
|
|
97
|
-
"""
|
|
98
|
-
import os
|
|
99
|
-
def break_down_find_existing(path):
|
|
100
|
-
test_path = ''
|
|
101
|
-
for part in path.split(os.sep):
|
|
102
|
-
test_path = os.path.join(test_path, part)
|
|
103
|
-
if not os.path.exists(test_path):
|
|
104
|
-
return test_path if test_path else None
|
|
105
|
-
return test_path
|
|
106
23
|
|
|
24
|
+
# --- Helper utilities --------------------------------------------------------
|
|
107
25
|
def string_in_keys(strings, kwargs):
|
|
108
|
-
|
|
26
|
+
"""Find a matching keyword in kwargs that contains any of the given substrings."""
|
|
27
|
+
for key in kwargs:
|
|
28
|
+
for s in strings:
|
|
29
|
+
if s.lower() in key.lower():
|
|
30
|
+
return key
|
|
31
|
+
return None
|
|
32
|
+
|
|
109
33
|
|
|
110
34
|
def get_path(paths):
|
|
35
|
+
"""Return the first valid path among given paths."""
|
|
111
36
|
for path in paths:
|
|
112
|
-
if isinstance(path,str):
|
|
37
|
+
if isinstance(path, str):
|
|
113
38
|
if os.path.isfile(path):
|
|
114
39
|
return path
|
|
115
40
|
dirname = os.path.dirname(path)
|
|
@@ -117,83 +42,180 @@ def get_path(paths):
|
|
|
117
42
|
return path
|
|
118
43
|
return None
|
|
119
44
|
|
|
45
|
+
|
|
46
|
+
def break_down_find_existing(path):
|
|
47
|
+
"""Return the first non-existent subpath within a path chain."""
|
|
48
|
+
test_path = ''
|
|
49
|
+
for part in path.split(os.sep):
|
|
50
|
+
test_path = os.path.join(test_path, part)
|
|
51
|
+
if not os.path.exists(test_path):
|
|
52
|
+
return test_path if test_path else None
|
|
53
|
+
return test_path
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# --- Parameter parsing --------------------------------------------------------
|
|
120
57
|
def check_read_write_params(*args, **kwargs):
|
|
121
|
-
|
|
122
|
-
contents
|
|
123
|
-
|
|
124
|
-
|
|
58
|
+
"""
|
|
59
|
+
Determine file_path and contents from arguments.
|
|
60
|
+
Returns a tuple: (file_path, contents)
|
|
61
|
+
"""
|
|
62
|
+
file_key = string_in_keys(_FILE_PATH_KEYS, kwargs)
|
|
63
|
+
content_key = string_in_keys(_CONTENTS_KEYS, kwargs)
|
|
125
64
|
|
|
126
|
-
|
|
65
|
+
file_path = kwargs.get(file_key) if file_key else None
|
|
66
|
+
contents = kwargs.get(content_key) if content_key else None
|
|
67
|
+
|
|
68
|
+
# Handle positional args (fallback)
|
|
127
69
|
if file_path is None and len(args) > 0:
|
|
128
70
|
file_path = args[0]
|
|
129
71
|
if contents is None and len(args) > 1:
|
|
130
72
|
contents = args[1]
|
|
131
|
-
elif contents is None and len(args) > 0 and file_path != args[0]:
|
|
132
|
-
contents = args[0]
|
|
133
|
-
|
|
134
|
-
if file_path is None or contents is None:
|
|
135
|
-
raise ValueError("Both 'file_path' and 'contents' (or 'data') are required.")
|
|
136
73
|
|
|
74
|
+
if file_path is None:
|
|
75
|
+
raise ValueError("Missing file_path argument.")
|
|
137
76
|
return file_path, contents
|
|
138
77
|
|
|
139
|
-
def
|
|
78
|
+
def write_to_path(
|
|
79
|
+
file_path: str,
|
|
80
|
+
contents: str,
|
|
81
|
+
*,
|
|
82
|
+
user_at_host: str = None,
|
|
83
|
+
cwd: str | None = None,
|
|
84
|
+
password=None,
|
|
85
|
+
key=None,
|
|
86
|
+
env_path=None,
|
|
87
|
+
**kwargs
|
|
88
|
+
) -> str:
|
|
140
89
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
file_path: The path of the file to write to.
|
|
145
|
-
contents: The content to write to the file.
|
|
146
|
-
|
|
147
|
-
Returns:
|
|
148
|
-
The contents that were written to the file.
|
|
90
|
+
Completely overwrite a file (locally or remotely).
|
|
91
|
+
Supports sudo and password-based remote execution.
|
|
149
92
|
"""
|
|
150
|
-
params = check_read_write_params(file_path=file_path, contents=contents,*args, **kwargs)
|
|
151
|
-
if params:
|
|
152
|
-
with open(params[0], 'w', encoding='UTF-8') as f:
|
|
153
|
-
f.write(params[1])
|
|
154
|
-
return contents
|
|
155
93
|
|
|
156
|
-
|
|
157
|
-
|
|
94
|
+
# sanitize for shell safety
|
|
95
|
+
quoted_path = shlex.quote(file_path)
|
|
96
|
+
quoted_data = shlex.quote(str(contents))
|
|
97
|
+
|
|
98
|
+
# shell command that fully overwrites
|
|
99
|
+
# (no append, replaces contents entirely)
|
|
100
|
+
base_cmd = f"echo {quoted_data} > {quoted_path}"
|
|
101
|
+
|
|
102
|
+
# optional sudo password injection
|
|
103
|
+
full_cmd = get_print_sudo_cmd(
|
|
104
|
+
cmd=base_cmd,
|
|
105
|
+
password=password,
|
|
106
|
+
key=key,
|
|
107
|
+
env_path=env_path
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# local or remote dispatch
|
|
111
|
+
if user_at_host:
|
|
112
|
+
return run_remote_cmd(
|
|
113
|
+
user_at_host=user_at_host,
|
|
114
|
+
cmd=full_cmd,
|
|
115
|
+
cwd=cwd,
|
|
116
|
+
password=password,
|
|
117
|
+
key=key,
|
|
118
|
+
env_path=env_path,
|
|
119
|
+
**kwargs
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
return run_local_cmd(
|
|
123
|
+
cmd=full_cmd,
|
|
124
|
+
cwd=cwd,
|
|
125
|
+
password=password,
|
|
126
|
+
key=key,
|
|
127
|
+
env_path=env_path,
|
|
128
|
+
**kwargs
|
|
129
|
+
)
|
|
130
|
+
### --- Core functionality -------------------------------------------------------
|
|
131
|
+
##def write_to_file(*args, **kwargs):
|
|
132
|
+
## """
|
|
133
|
+
## Write contents to a file (create if missing).
|
|
134
|
+
##
|
|
135
|
+
## Returns the file_path written.
|
|
136
|
+
## """
|
|
137
|
+
## file_path, contents = check_read_write_params(*args, **kwargs)
|
|
138
|
+
## if contents is None:
|
|
139
|
+
## raise ValueError("Missing contents to write.")
|
|
140
|
+
##
|
|
141
|
+
## os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
|
|
142
|
+
## with open(file_path, "w", encoding="utf-8") as f:
|
|
143
|
+
## f.write(str(contents))
|
|
144
|
+
## return file_path
|
|
145
|
+
# --- Core functionality -------------------------------------------------------
|
|
146
|
+
def write_to_file(*args, **kwargs):
|
|
158
147
|
"""
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
file_path: The path of the file to read from.
|
|
163
|
-
|
|
164
|
-
Returns:
|
|
165
|
-
The contents of the file.
|
|
148
|
+
Write contents to a file (create if missing).
|
|
149
|
+
|
|
150
|
+
Returns the file_path written.
|
|
166
151
|
"""
|
|
167
|
-
|
|
152
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
153
|
+
if contents is None:
|
|
154
|
+
raise ValueError("Missing contents to write.")
|
|
155
|
+
user_at_host = kwargs.get("user_at_host")
|
|
156
|
+
if user_at_host:
|
|
157
|
+
kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
|
|
158
|
+
# sanitize for shell safety
|
|
159
|
+
quoted_path = shlex.quote(file_path)
|
|
160
|
+
quoted_data = shlex.quote(str(contents))
|
|
161
|
+
# shell command that fully overwrites
|
|
162
|
+
# (no append, replaces contents entirely)
|
|
163
|
+
kwargs["cmd"] = f"echo {quoted_data} > {quoted_path}"
|
|
164
|
+
return run_pruned_func(run_cmd,**kwargs)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
|
|
168
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
169
|
+
f.write(str(contents))
|
|
170
|
+
return file_path
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def read_from_file(file_path,**kwargs):
|
|
174
|
+
user_at_host = kwargs.get("user_at_host")
|
|
175
|
+
if user_at_host:
|
|
176
|
+
kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
|
|
177
|
+
basename = os.path.basename(file_path)
|
|
178
|
+
kwargs["cmd"] = f'cat {basename}'
|
|
179
|
+
return run_pruned_func(run_cmd,**kwargs)
|
|
180
|
+
"""Read text content from a file."""
|
|
181
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
168
182
|
return f.read()
|
|
169
183
|
|
|
170
|
-
|
|
184
|
+
|
|
185
|
+
def create_and_read_file(*args, **kwargs):
|
|
171
186
|
"""
|
|
172
|
-
Create
|
|
173
|
-
|
|
174
|
-
Args:
|
|
175
|
-
file_path: The path of the file to create and read from.
|
|
176
|
-
contents: The content to write to the file if it does not exist.
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
The contents of the file.
|
|
187
|
+
Create the file (if missing) and read contents from it.
|
|
180
188
|
"""
|
|
189
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
181
190
|
if not os.path.isfile(file_path):
|
|
182
|
-
write_to_file(
|
|
191
|
+
write_to_file(file_path, contents or "")
|
|
183
192
|
return read_from_file(file_path)
|
|
193
|
+
|
|
194
|
+
|
|
184
195
|
def is_file_extension(obj: str) -> bool:
|
|
185
|
-
"""
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
Returns:
|
|
192
|
-
True if the string has a file extension, False otherwise.
|
|
193
|
-
"""
|
|
194
|
-
return len(obj) >= 4 and '.' in obj[-4:-3]
|
|
196
|
+
"""Return True if obj looks like a filename with extension."""
|
|
197
|
+
if not isinstance(obj, str):
|
|
198
|
+
return False
|
|
199
|
+
root, ext = os.path.splitext(obj)
|
|
200
|
+
return bool(root and ext)
|
|
201
|
+
|
|
195
202
|
|
|
196
203
|
def delete_file(file_path: str):
|
|
204
|
+
"""Safely delete a file if it exists."""
|
|
197
205
|
if os.path.isfile(file_path):
|
|
198
206
|
os.remove(file_path)
|
|
207
|
+
return True
|
|
208
|
+
return False
|
|
209
|
+
|
|
199
210
|
|
|
211
|
+
def get_content_lines(*args, **kwargs):
|
|
212
|
+
"""Return a list of lines from string or file path."""
|
|
213
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
214
|
+
if os.path.isfile(file_path):
|
|
215
|
+
contents = read_from_file(filepath)
|
|
216
|
+
|
|
217
|
+
if isinstance(contents, str):
|
|
218
|
+
return contents.splitlines()
|
|
219
|
+
elif isinstance(contents, list):
|
|
220
|
+
return contents
|
|
221
|
+
return []
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ..file_utils import *
|
|
2
2
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .imports import *
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from ...read_write_utils import read_from_file,write_to_file
|
|
2
|
+
from ...string_clean import eatAll,eatElse,clean_line
|
|
3
|
+
from ...class_utils import get_caller_path
|
|
4
|
+
from ...list_utils import make_list
|
|
5
|
+
import os
|
|
6
|
+
import_tag = 'import '
|
|
7
|
+
from_tag = 'from '
|
|
8
|
+
def get_text_or_read(text=None,file_path=None):
|
|
9
|
+
text = text or ''
|
|
10
|
+
imports_js = {}
|
|
11
|
+
if not text and file_path and os.path.isfile(file_path):
|
|
12
|
+
text=read_from_file(file_path)
|
|
13
|
+
return text
|
|
14
|
+
def is_line_import(line):
|
|
15
|
+
if line and (line.startswith(from_tag) or line.startswith(import_tag)):
|
|
16
|
+
return True
|
|
17
|
+
return False
|
|
18
|
+
def is_line_group_import(line):
|
|
19
|
+
if line and (line.startswith(from_tag) and import_tag in line):
|
|
20
|
+
return True
|
|
21
|
+
return False
|
|
22
|
+
def get_import_pkg(line):
|
|
23
|
+
if is_line_group_import(line):
|
|
24
|
+
return clean_line(line.split(from_tag)[1].split(import_tag)[0])
|
|
25
|
+
def get_imports_from_import_pkg(line):
|
|
26
|
+
if is_line_group_import(line):
|
|
27
|
+
return get_cleaned_import_list(line,commaClean=True)
|
|
28
|
+
|
|
29
|
+
def add_imports_to_import_pkg_js(import_pkg,imports,import_pkg_js=None):
|
|
30
|
+
import_pkg_js = import_pkg_js or {}
|
|
31
|
+
imports = clean_imports(imports)
|
|
32
|
+
if import_pkg not in import_pkg_js:
|
|
33
|
+
i = len(import_pkg_js["nulines"])
|
|
34
|
+
import_pkg_js[import_pkg]={"imports":imports,"line":i}
|
|
35
|
+
import_line = f"from {import_pkg} import "
|
|
36
|
+
if import_pkg == "import":
|
|
37
|
+
import_line = import_tag
|
|
38
|
+
import_pkg_js["nulines"].append(import_line)
|
|
39
|
+
else:
|
|
40
|
+
import_pkg_js[import_pkg]["imports"]+=imports
|
|
41
|
+
return import_pkg_js
|
|
42
|
+
def update_import_pkg_js(line,import_pkg_js=None):
|
|
43
|
+
import_pkg_js = import_pkg_js or {}
|
|
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 len(import_pkg_js["nulines"]) >0 and line == '' and is_line_import(import_pkg_js["nulines"][-1]):
|
|
50
|
+
pass
|
|
51
|
+
else:
|
|
52
|
+
import_pkg_js["nulines"].append(line)
|
|
53
|
+
return import_pkg_js
|
|
54
|
+
def is_from_line_group(line):
|
|
55
|
+
if line and line.startswith(from_tag) and import_tag in line and '(' in line:
|
|
56
|
+
import_spl = line.split(import_tag)[-1]
|
|
57
|
+
import_spl_clean = clean_line(line)
|
|
58
|
+
if not import_spl_clean.endswith(')'):
|
|
59
|
+
return True
|
|
60
|
+
return False
|
|
61
|
+
def clean_imports(imports,commaClean=True):
|
|
62
|
+
chars=["*"]
|
|
63
|
+
if not commaClean:
|
|
64
|
+
chars.append(',')
|
|
65
|
+
if isinstance(imports,str):
|
|
66
|
+
imports = imports.split(',')
|
|
67
|
+
return [eatElse(imp,chars=chars) for imp in imports if imp]
|
|
68
|
+
def get_cleaned_import_list(line,commaClean=True):
|
|
69
|
+
cleaned_import_list=[]
|
|
70
|
+
if import_tag in line:
|
|
71
|
+
imports = line.split(import_tag)[1]
|
|
72
|
+
cleaned_import_list+=clean_imports(imports,commaClean=commaClean)
|
|
73
|
+
return cleaned_import_list
|
|
74
|
+
def get_all_imports(text=None,file_path=None,import_pkg_js=None):
|
|
75
|
+
text = get_text_or_read(text=text,file_path=file_path)
|
|
76
|
+
lines = text.split('\n')
|
|
77
|
+
cleaned_import_list=[]
|
|
78
|
+
nu_lines = []
|
|
79
|
+
is_from_group = False
|
|
80
|
+
import_pkg_js = import_pkg_js or {}
|
|
81
|
+
if "nulines" not in import_pkg_js:
|
|
82
|
+
import_pkg_js["nulines"]=[]
|
|
83
|
+
if "file_path" not in import_pkg_js:
|
|
84
|
+
import_pkg_js["file_path"]=file_path
|
|
85
|
+
if "all_data" not in import_pkg_js:
|
|
86
|
+
import_pkg_js["all_data"]=[]
|
|
87
|
+
if file_path and file_path != import_pkg_js["file_path"]:
|
|
88
|
+
found=False
|
|
89
|
+
nu_data = {"file_path":import_pkg_js["file_path"],"nulines":import_pkg_js["nulines"]}
|
|
90
|
+
for i,data in enumerate(import_pkg_js["all_data"]):
|
|
91
|
+
if data.get('file_path') == import_pkg_js["file_path"]:
|
|
92
|
+
import_pkg_js["all_data"][i] = nu_data
|
|
93
|
+
found = True
|
|
94
|
+
break
|
|
95
|
+
if found == False:
|
|
96
|
+
import_pkg_js["all_data"].append(nu_data)
|
|
97
|
+
import_pkg_js["nulines"]=[]
|
|
98
|
+
import_pkg_js["file_path"]=file_path
|
|
99
|
+
|
|
100
|
+
for line in lines:
|
|
101
|
+
if line.startswith(import_tag) and ' from ' not in line:
|
|
102
|
+
cleaned_import_list = get_cleaned_import_list(line)
|
|
103
|
+
import_pkg_js = add_imports_to_import_pkg_js("import",cleaned_import_list,import_pkg_js=import_pkg_js)
|
|
104
|
+
else:
|
|
105
|
+
if is_from_group:
|
|
106
|
+
import_pkg=is_from_group
|
|
107
|
+
line = clean_line(line)
|
|
108
|
+
if line.endswith(')'):
|
|
109
|
+
is_from_group=False
|
|
110
|
+
line=line[:-1]
|
|
111
|
+
imports_from_import_pkg = clean_imports(line)
|
|
112
|
+
import_pkg_js = add_imports_to_import_pkg_js(import_pkg,imports_from_import_pkg,import_pkg_js=import_pkg_js)
|
|
113
|
+
|
|
114
|
+
else:
|
|
115
|
+
import_pkg_js=update_import_pkg_js(line,import_pkg_js=import_pkg_js)
|
|
116
|
+
if is_from_line_group(line) and is_from_group == False:
|
|
117
|
+
is_from_group=get_import_pkg(line)
|
|
118
|
+
return import_pkg_js
|
|
119
|
+
def clean_all_imports(text=None,file_path=None,import_pkg_js=None):
|
|
120
|
+
if not import_pkg_js:
|
|
121
|
+
import_pkg_js = get_all_imports(text=text,file_path=file_path)
|
|
122
|
+
nu_lines = import_pkg_js["nulines"]
|
|
123
|
+
for pkg,values in import_pkg_js.items():
|
|
124
|
+
comments = []
|
|
125
|
+
if pkg not in ["nulines","file_path","all_data"]:
|
|
126
|
+
line = values.get('line')
|
|
127
|
+
imports = values.get('imports')
|
|
128
|
+
for i,imp in enumerate(imports):
|
|
129
|
+
if '#' in imp:
|
|
130
|
+
imp_spl = imp.split('#')
|
|
131
|
+
comments.append(imp_spl[-1])
|
|
132
|
+
imports[i] = clean_line(imp_spl[0])
|
|
133
|
+
imports = list(set(imports))
|
|
134
|
+
if '*' in imports:
|
|
135
|
+
imports="*"
|
|
136
|
+
else:
|
|
137
|
+
imports=','.join(imports)
|
|
138
|
+
if comments:
|
|
139
|
+
comments=','.join(comments)
|
|
140
|
+
imports+=f" #{comments}"
|
|
141
|
+
import_pkg_js[pkg]["imports"]=imports
|
|
142
|
+
nu_lines[line] += imports
|
|
143
|
+
import_pkg_js["nulines"]=nu_lines
|
|
144
|
+
return import_pkg_js
|
|
145
|
+
|
|
146
|
+
def get_all_real_imps(file):
|
|
147
|
+
contents = read_from_file(file)
|
|
148
|
+
lines = contents.split('\n')
|
|
149
|
+
for line in lines:
|
|
150
|
+
if line.startswith('from '):
|
|
151
|
+
from_line = line.split('from ')[-1]
|
|
152
|
+
dot_fro = ""
|
|
153
|
+
dirname = file
|
|
154
|
+
for char in from_line:
|
|
155
|
+
if char != '.':
|
|
156
|
+
line = f"from {dot_fro}{eatAll(from_line,'.')}"
|
|
157
|
+
if line in all_imps:
|
|
158
|
+
line = ""
|
|
159
|
+
break
|
|
160
|
+
if dot_fro == "":
|
|
161
|
+
dot_fro = ""
|
|
162
|
+
dirname = os.path.dirname(dirname)
|
|
163
|
+
dirbase = os.path.basename(dirname)
|
|
164
|
+
dot_fro = f"{dirbase}.{dot_fro}"
|
|
165
|
+
if line:
|
|
166
|
+
all_imps.append(line)
|
|
167
|
+
|
|
168
|
+
return '\n'.join(all_imps)
|
|
169
|
+
def save_cleaned_imports(text=None,file_path=None,write=False,import_pkg_js=None):
|
|
170
|
+
import_pkg_js=get_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
|
|
171
|
+
import_pkg_js = clean_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
|
|
172
|
+
contents = '\n'.join(import_pkg_js["nulines"])
|
|
173
|
+
if file_path and write:
|
|
174
|
+
write_to_file(contents=contents,file_path=file_path)
|
|
175
|
+
return contents
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from types import ModuleType
|
|
2
|
+
from typing import Iterable
|
|
3
|
+
from ..file_utils import get_caller_dir,get_caller_path,define_defaults,get_files_and_dirs
|
|
4
|
+
from ..read_write_utils import *
|
|
5
|
+
import textwrap, pkgutil, os, re, textwrap, sys, types, importlib, importlib.util
|
|
6
|
+
from typing import *
|
|
7
|
+
ABSPATH = os.path.abspath(__file__)
|
|
8
|
+
ABSROOT = os.path.dirname(ABSPATH)
|