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
|
@@ -1,199 +1,292 @@
|
|
|
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.
|
|
15
|
-
|
|
16
|
-
Each function includes a docstring to further explain its purpose, input parameters, and return values.
|
|
17
|
-
import os
|
|
18
|
-
|
|
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
|
-
|
|
12
|
+
from abstract_utilities.read_write_utils import *
|
|
97
13
|
"""
|
|
14
|
+
|
|
98
15
|
import os
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return test_path
|
|
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,get_user_pass_host_key,is_exists
|
|
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']
|
|
106
22
|
|
|
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
|
|
109
32
|
|
|
110
|
-
def
|
|
33
|
+
def make_dirs(path,exist_ok=True,**kwargs):
|
|
34
|
+
if exist_ok or (not exist_ok and not is_dir(path,**kwargs)):
|
|
35
|
+
if get_user_pass_host_key(**kwargs):
|
|
36
|
+
kwargs['cmd']=f"mkdir {path}"
|
|
37
|
+
run_cmd(**kwargs)
|
|
38
|
+
else:
|
|
39
|
+
os.makedirs(path,exist_ok=exist_ok)
|
|
40
|
+
return ext_dir
|
|
41
|
+
def path_join(*args):
|
|
42
|
+
path = None
|
|
43
|
+
for i,arg in enumerate(args):
|
|
44
|
+
if arg:
|
|
45
|
+
if i == 0:
|
|
46
|
+
path = arg
|
|
47
|
+
else:
|
|
48
|
+
path = os.path.join(path,arg)
|
|
49
|
+
return path
|
|
50
|
+
def make_path(path,home_dir=None,file=None,**kwargs):
|
|
51
|
+
if path:
|
|
52
|
+
basename = os.path.basename(path)
|
|
53
|
+
parts = path.split('/')
|
|
54
|
+
parts = [part for part in parts if part]
|
|
55
|
+
|
|
56
|
+
full_dir = home_dir or ''
|
|
57
|
+
if file == True or (file == None and ('.' in basename)):
|
|
58
|
+
pieces = parts[:-1] if len(parts) > 1 else []
|
|
59
|
+
else:
|
|
60
|
+
pieces=parts
|
|
61
|
+
basename=None
|
|
62
|
+
for piece in pieces:
|
|
63
|
+
full_dir = os.path.join(full_dir,piece)
|
|
64
|
+
make_dirs(full_dir,exist_ok=True,**kwargs)
|
|
65
|
+
if basename:
|
|
66
|
+
full_dir=path_join(full_dir,basename)
|
|
67
|
+
print(f"full_dir == {full_dir}")
|
|
68
|
+
return full_dir
|
|
69
|
+
def get_path(paths,**kwargs):
|
|
70
|
+
"""Return the first valid path among given paths."""
|
|
111
71
|
for path in paths:
|
|
112
|
-
if isinstance(path,str):
|
|
113
|
-
if
|
|
72
|
+
if isinstance(path, str):
|
|
73
|
+
if is_file(path,**kwargs):
|
|
114
74
|
return path
|
|
115
75
|
dirname = os.path.dirname(path)
|
|
116
|
-
if
|
|
76
|
+
if is_exists(dirname):
|
|
117
77
|
return path
|
|
118
78
|
return None
|
|
119
79
|
|
|
80
|
+
|
|
81
|
+
def break_down_find_existing(path,**kwargs):
|
|
82
|
+
"""Return the first non-existent subpath within a path chain."""
|
|
83
|
+
test_path = ''
|
|
84
|
+
for part in path.split(os.sep):
|
|
85
|
+
test_path = os.path.join(test_path, part)
|
|
86
|
+
if not is_exists(test_path):
|
|
87
|
+
return test_path if test_path else None
|
|
88
|
+
return test_path
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# --- Parameter parsing --------------------------------------------------------
|
|
120
92
|
def check_read_write_params(*args, **kwargs):
|
|
121
|
-
|
|
122
|
-
contents
|
|
123
|
-
|
|
124
|
-
|
|
93
|
+
"""
|
|
94
|
+
Determine file_path and contents from arguments.
|
|
95
|
+
Returns a tuple: (file_path, contents)
|
|
96
|
+
"""
|
|
97
|
+
file_key = string_in_keys(_FILE_PATH_KEYS, kwargs)
|
|
98
|
+
content_key = string_in_keys(_CONTENTS_KEYS, kwargs)
|
|
99
|
+
|
|
100
|
+
file_path = kwargs.get(file_key) if file_key else None
|
|
101
|
+
contents = kwargs.get(content_key) if content_key else None
|
|
125
102
|
|
|
126
|
-
# Handle positional
|
|
103
|
+
# Handle positional args (fallback)
|
|
127
104
|
if file_path is None and len(args) > 0:
|
|
128
105
|
file_path = args[0]
|
|
129
106
|
if contents is None and len(args) > 1:
|
|
130
107
|
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
108
|
|
|
109
|
+
if file_path is None:
|
|
110
|
+
raise ValueError("Missing file_path argument.")
|
|
137
111
|
return file_path, contents
|
|
138
112
|
|
|
139
|
-
def
|
|
113
|
+
def write_to_path(
|
|
114
|
+
file_path: str,
|
|
115
|
+
contents: str,
|
|
116
|
+
*,
|
|
117
|
+
user_at_host: str = None,
|
|
118
|
+
cwd: str | None = None,
|
|
119
|
+
password=None,
|
|
120
|
+
key=None,
|
|
121
|
+
env_path=None,
|
|
122
|
+
**kwargs
|
|
123
|
+
) -> str:
|
|
140
124
|
"""
|
|
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.
|
|
125
|
+
Completely overwrite a file (locally or remotely).
|
|
126
|
+
Supports sudo and password-based remote execution.
|
|
149
127
|
"""
|
|
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
128
|
|
|
129
|
+
# sanitize for shell safety
|
|
130
|
+
quoted_path = shlex.quote(file_path)
|
|
131
|
+
quoted_data = shlex.quote(str(contents))
|
|
156
132
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
133
|
+
# shell command that fully overwrites
|
|
134
|
+
# (no append, replaces contents entirely)
|
|
135
|
+
base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
|
|
136
|
+
input(base_cmd)
|
|
137
|
+
# optional sudo password injection
|
|
138
|
+
full_cmd = get_print_sudo_cmd(
|
|
139
|
+
cmd=base_cmd,
|
|
140
|
+
password=password,
|
|
141
|
+
key=key,
|
|
142
|
+
env_path=env_path
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# local or remote dispatch
|
|
146
|
+
if user_at_host:
|
|
147
|
+
return run_remote_cmd(
|
|
148
|
+
user_at_host=user_at_host,
|
|
149
|
+
cmd=full_cmd,
|
|
150
|
+
cwd=cwd,
|
|
151
|
+
password=password,
|
|
152
|
+
key=key,
|
|
153
|
+
env_path=env_path,
|
|
154
|
+
**kwargs
|
|
155
|
+
)
|
|
156
|
+
else:
|
|
157
|
+
return run_local_cmd(
|
|
158
|
+
cmd=full_cmd,
|
|
159
|
+
cwd=cwd,
|
|
160
|
+
password=password,
|
|
161
|
+
key=key,
|
|
162
|
+
env_path=env_path,
|
|
163
|
+
**kwargs
|
|
164
|
+
)
|
|
165
|
+
### --- Core functionality -------------------------------------------------------
|
|
166
|
+
##def write_to_file(*args, **kwargs):
|
|
167
|
+
## """
|
|
168
|
+
## Write contents to a file (create if missing).
|
|
169
|
+
##
|
|
170
|
+
## Returns the file_path written.
|
|
171
|
+
## """
|
|
172
|
+
## file_path, contents = check_read_write_params(*args, **kwargs)
|
|
173
|
+
## if contents is None:
|
|
174
|
+
## raise ValueError("Missing contents to write.")
|
|
175
|
+
##
|
|
176
|
+
## os.makedirs(os.path.dirname(file_path) or ".", exist_ok=True)
|
|
177
|
+
## with open(file_path, "w", encoding="utf-8") as f:
|
|
178
|
+
## f.write(str(contents))
|
|
179
|
+
## return file_path
|
|
180
|
+
# --- Core functionality -------------------------------------------------------
|
|
181
|
+
def write_to_file(*args, **kwargs):
|
|
166
182
|
"""
|
|
167
|
-
|
|
168
|
-
return f.read()
|
|
183
|
+
Write contents to a file (create if missing).
|
|
169
184
|
|
|
170
|
-
|
|
185
|
+
Returns the file_path written.
|
|
171
186
|
"""
|
|
172
|
-
|
|
187
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
188
|
+
dirname = os.path.dirname(file_path)
|
|
173
189
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
190
|
+
if contents is None:
|
|
191
|
+
raise ValueError("Missing contents to write.")
|
|
192
|
+
user_at_host = kwargs.get("user_at_host")
|
|
193
|
+
if get_user_pass_host_key(**kwargs):
|
|
194
|
+
make_dirs(dirname, exist_ok=True,**kwargs)
|
|
195
|
+
kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
|
|
196
|
+
# sanitize for shell safety
|
|
197
|
+
quoted_path = shlex.quote(file_path)
|
|
198
|
+
quoted_data = shlex.quote(str(contents))
|
|
199
|
+
# shell command that fully overwrites
|
|
200
|
+
# (no append, replaces contents entirely)
|
|
201
|
+
kwargs["cmd"] = f'sh -c "echo {quoted_data} > {quoted_path}"'
|
|
202
|
+
if not kwargs.get('password') and not kwargs.get('key'):
|
|
203
|
+
kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
|
|
204
|
+
result = run_pruned_func(run_cmd,**kwargs)
|
|
205
|
+
if not is_file(file_path,**kwargs) or str(contents) != read_from_file(file_path,**kwargs):
|
|
206
|
+
kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
|
|
207
|
+
result = run_pruned_func(run_cmd,**kwargs)
|
|
208
|
+
return result
|
|
209
|
+
|
|
210
|
+
make_dirs(dirname or ".", exist_ok=True)
|
|
211
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
212
|
+
f.write(str(contents))
|
|
213
|
+
return file_path
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def read_from_file(file_path,**kwargs):
|
|
217
|
+
if get_user_pass_host_key(**kwargs):
|
|
218
|
+
kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
|
|
219
|
+
basename = os.path.basename(file_path)
|
|
220
|
+
kwargs["cmd"] = f'cat {basename}'
|
|
221
|
+
return run_pruned_func(run_cmd,**kwargs)
|
|
222
|
+
"""Read text content from a file."""
|
|
223
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
224
|
+
return f.read()
|
|
225
|
+
def get_rel_path(src,src_rel,directory):
|
|
226
|
+
if src.startswith(src_rel):
|
|
227
|
+
src = src[len(src_rel):]
|
|
228
|
+
rel_path = os.path.join(directory,src)
|
|
229
|
+
return rel_path
|
|
230
|
+
def make_relative_path(src,src_rel,dst,**kwargs):
|
|
231
|
+
print(f"src == {src}\nsrc_rel == {src_rel}\ndirectory == {directory}")
|
|
232
|
+
if src.startswith(src_rel):
|
|
233
|
+
rel_path = get_rel_path(src,src_rel,directory)
|
|
234
|
+
path = make_path(src,home_dir=rel_path,**kwargs)
|
|
235
|
+
print(f"path == {path}")
|
|
236
|
+
return path
|
|
237
|
+
def copy_dirs(dirs,dst,src_rel=None,**kwargs):
|
|
238
|
+
for src in dirs:
|
|
239
|
+
if rel_path:
|
|
240
|
+
dst = make_relative_path(src,src_rel,dst,**kwargs)
|
|
241
|
+
make_path(dst,**kwargs)
|
|
177
242
|
|
|
178
|
-
|
|
179
|
-
|
|
243
|
+
def copy_file(src,dst,rel_path=None,**kwargs):
|
|
244
|
+
if rel_path:
|
|
245
|
+
dst = make_relative_path(src,rel_path,dst,**kwargs)
|
|
246
|
+
if get_user_pass_host_key(**kwargs):
|
|
247
|
+
contents=read_from_file(src,**kwargs)
|
|
248
|
+
write_to_file(contents=contents,file_path=dst,**kwargs)
|
|
249
|
+
else:
|
|
250
|
+
shutil.copy(src,dst)
|
|
251
|
+
return dst
|
|
252
|
+
def copy_files(files,dst,rel_path=None,**kwargs):
|
|
253
|
+
for file in files:
|
|
254
|
+
copy_file(src=file,dst=dst,rel_path=rel_path,**kwargs)
|
|
255
|
+
|
|
256
|
+
def create_and_read_file(*args, **kwargs):
|
|
257
|
+
"""
|
|
258
|
+
Create the file (if missing) and read contents from it.
|
|
180
259
|
"""
|
|
260
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
181
261
|
if not os.path.isfile(file_path):
|
|
182
|
-
write_to_file(
|
|
262
|
+
write_to_file(file_path, contents or "")
|
|
183
263
|
return read_from_file(file_path)
|
|
264
|
+
|
|
265
|
+
|
|
184
266
|
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]
|
|
267
|
+
"""Return True if obj looks like a filename with extension."""
|
|
268
|
+
if not isinstance(obj, str):
|
|
269
|
+
return False
|
|
270
|
+
root, ext = os.path.splitext(obj)
|
|
271
|
+
return bool(root and ext)
|
|
272
|
+
|
|
195
273
|
|
|
196
274
|
def delete_file(file_path: str):
|
|
275
|
+
"""Safely delete a file if it exists."""
|
|
197
276
|
if os.path.isfile(file_path):
|
|
198
277
|
os.remove(file_path)
|
|
278
|
+
return True
|
|
279
|
+
return False
|
|
280
|
+
|
|
199
281
|
|
|
282
|
+
def get_content_lines(*args, **kwargs):
|
|
283
|
+
"""Return a list of lines from string or file path."""
|
|
284
|
+
file_path, contents = check_read_write_params(*args, **kwargs)
|
|
285
|
+
if os.path.isfile(file_path):
|
|
286
|
+
contents = read_from_file(filepath)
|
|
287
|
+
|
|
288
|
+
if isinstance(contents, str):
|
|
289
|
+
return contents.splitlines()
|
|
290
|
+
elif isinstance(contents, list):
|
|
291
|
+
return contents
|
|
292
|
+
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)
|