abstract-utilities 0.2.2.474__py3-none-any.whl → 0.2.2.488__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.
@@ -6,7 +6,8 @@ from ....ssh_utils import *
6
6
  from ....env_utils import *
7
7
  from ....read_write_utils import *
8
8
  from ....abstract_classes import SingletonMeta
9
-
9
+ from ....string_utils import get_from_kwargs
10
+ from ....abstract_classes import run_pruned_func
10
11
  from ....class_utils import get_caller, get_caller_path, get_caller_dir
11
12
 
12
13
 
@@ -1,34 +1,37 @@
1
1
  from .imports import *
2
2
 
3
+ def get_user_pass_host_key(**kwargs):
4
+ args = ['password','user_at_host','host','key','user']
5
+ kwargs['del_kwarg']=kwargs.get('del_kwarg',False)
6
+ values,kwargs = get_from_kwargs(*args,**kwargs)
7
+ return values
3
8
 
4
9
  # --- Base remote checker -----------------------------------------------------
5
- def _remote_test(path: str, test_flag: str, user_at_host: str, timeout: int = 5) -> bool:
10
+ def _remote_test(path: str, test_flag: str, timeout: int = 5,*args, **kwargs) -> bool:
6
11
  """
7
12
  Run a remote shell test (e.g. -f, -d) via SSH.
8
13
  Returns True if test succeeds, False otherwise.
9
14
  """
10
- cmd = f"[ {test_flag} {shlex.quote(path)} ] && echo 1 || echo 0"
11
15
  try:
12
- result = subprocess.check_output(
13
- ["ssh", user_at_host, cmd],
14
- stderr=subprocess.DEVNULL,
15
- text=True,
16
- timeout=timeout
17
- ).strip()
18
- return result == "1"
16
+ kwargs['cmd']=f"[ {test_flag} {shlex.quote(path)} ] && echo 1 || echo 0"
17
+ kwargs['text']=True
18
+ kwargs['timeout']=timeout
19
+ kwargs['stderr']=subprocess.DEVNULL
20
+ result = run_pruned_func(run_cmd,**kwargs)
21
+ return result.strip() == "1"
19
22
  except Exception:
20
23
  return False
21
24
 
22
25
 
23
26
  # --- Individual path checks --------------------------------------------------
24
- def is_remote_file(path: str, user_at_host: str) -> bool:
27
+ def is_remote_file(path: str,*args, **kwargs) -> bool:
25
28
  """True if remote path is a file."""
26
- return _remote_test(path, "-f", user_at_host)
29
+ return _remote_test(path, "-f", **kwargs)
27
30
 
28
31
 
29
- def is_remote_dir(path: str, user_at_host: str) -> bool:
32
+ def is_remote_dir(path: str,*args, **kwargs) -> bool:
30
33
  """True if remote path is a directory."""
31
- return _remote_test(path, "-d", user_at_host)
34
+ return _remote_test(path, "-d", **kwargs)
32
35
 
33
36
 
34
37
  def is_local_file(path: str) -> bool:
@@ -42,33 +45,40 @@ def is_local_dir(path: str) -> bool:
42
45
 
43
46
 
44
47
  # --- Unified interface -------------------------------------------------------
45
- def is_file(path: str,*args, user_at_host: Optional[str] = None,**kwargs) -> bool:
48
+
49
+ def is_file(path: str,*args,**kwargs) -> bool:
46
50
  """Determine if path is a file (works local or remote)."""
47
- if user_at_host:
48
- return is_remote_file(path, user_at_host)
51
+ if get_user_pass_host_key(**kwargs):
52
+ return is_remote_file(path, **kwargs)
49
53
  return is_local_file(path)
50
54
 
51
55
 
52
- def is_dir(path: str, *args,user_at_host: Optional[str] = None,**kwargs) -> bool:
56
+ def is_dir(path: str, *args,**kwargs) -> bool:
53
57
  """Determine if path is a directory (works local or remote)."""
54
- if user_at_host:
55
- return is_remote_dir(path, user_at_host)
58
+ if get_user_pass_host_key(**kwargs):
59
+ return is_remote_dir(path, **kwargs)
56
60
  return is_local_dir(path)
57
61
 
58
-
62
+ def is_exists(path: str, *args,**kwargs) -> bool:
63
+ if is_file(path,**kwargs):
64
+ return True
65
+ if is_dir(path,**kwargs):
66
+ return True
67
+ return False
59
68
  # --- Optional: keep your original all-in-one wrapper ------------------------
60
69
  def check_path_type(
61
70
  path: str,
62
- user_at_host: Optional[str] = None,
71
+ *args,
72
+ **kwargs
63
73
  ) -> str:
64
74
  """
65
75
  Return 'file', 'directory', 'missing', or 'unknown'.
66
76
  Uses isolated is_file/is_dir functions.
67
77
  """
68
- if user_at_host:
69
- if is_remote_file(path, user_at_host):
78
+ if get_user_pass_host_key(**kwargs):
79
+ if is_remote_file(path,**kwargs):
70
80
  return "file"
71
- elif is_remote_dir(path, user_at_host):
81
+ elif is_remote_dir(path,**kwargs):
72
82
  return "directory"
73
83
  else:
74
84
  return "missing"
@@ -15,12 +15,13 @@ Usage:
15
15
  import os
16
16
  import shlex
17
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
18
+ from .file_utils.file_utils.type_checks import is_file,is_dir,get_user_pass_host_key,is_exists
19
19
  from .abstract_classes import run_pruned_func
20
+ from .string_utils import get_from_kwargs
20
21
  _FILE_PATH_KEYS = ['file', 'filepath', 'file_path', 'path', 'directory', 'f', 'dst', 'dest']
21
22
  _CONTENTS_KEYS = ['cont', 'content', 'contents', 'data', 'datas', 'dat', 'src', 'source']
22
23
 
23
-
24
+
24
25
  # --- Helper utilities --------------------------------------------------------
25
26
  def string_in_keys(strings, kwargs):
26
27
  """Find a matching keyword in kwargs that contains any of the given substrings."""
@@ -30,25 +31,60 @@ def string_in_keys(strings, kwargs):
30
31
  return key
31
32
  return None
32
33
 
33
-
34
- def get_path(paths):
34
+ def make_dirs(path,exist_ok=True,**kwargs):
35
+ if exist_ok or (not exist_ok and not is_dir(path,**kwargs)):
36
+ if get_user_pass_host_key(**kwargs):
37
+ kwargs['cmd']=f"mkdir {path}"
38
+ run_pruned_func(run_cmd,**kwargs)
39
+ else:
40
+ os.makedirs(path,exist_ok=exist_ok)
41
+ return path
42
+ def path_join(*args):
43
+ path = None
44
+ for i,arg in enumerate(args):
45
+ if arg:
46
+ if i == 0:
47
+ path = arg
48
+ else:
49
+ path = os.path.join(path,arg)
50
+ return path
51
+ def make_path(path,home_dir=None,file=None,**kwargs):
52
+ if path:
53
+ basename = os.path.basename(path)
54
+ parts = path.split('/')
55
+ parts = [part for part in parts if part]
56
+
57
+ full_dir = home_dir or ''
58
+ if file == True or (file == None and ('.' in basename)):
59
+ pieces = parts[:-1] if len(parts) > 1 else []
60
+ else:
61
+ pieces=parts
62
+ basename=None
63
+ for piece in pieces:
64
+ full_dir = os.path.join(full_dir,piece)
65
+ make_dirs(full_dir,exist_ok=True,**kwargs)
66
+ if basename:
67
+ full_dir=path_join(full_dir,basename)
68
+ print(f"full_dir == {full_dir}")
69
+ return full_dir
70
+ def get_path(paths,**kwargs):
35
71
  """Return the first valid path among given paths."""
36
72
  for path in paths:
37
73
  if isinstance(path, str):
38
- if os.path.isfile(path):
74
+ if is_file(path,**kwargs):
39
75
  return path
40
76
  dirname = os.path.dirname(path)
41
- if os.path.exists(dirname):
77
+ if is_exists(dirname,**kwargs):
42
78
  return path
43
79
  return None
44
80
 
45
81
 
46
- def break_down_find_existing(path):
82
+ def break_down_find_existing(path,**kwargs):
47
83
  """Return the first non-existent subpath within a path chain."""
48
84
  test_path = ''
49
85
  for part in path.split(os.sep):
50
86
  test_path = os.path.join(test_path, part)
51
- if not os.path.exists(test_path):
87
+ if not is_exists(test_path,**kwargs):
52
88
  return test_path if test_path else None
53
89
  return test_path
54
90
 
@@ -97,8 +133,8 @@ def write_to_path(
97
133
 
98
134
  # shell command that fully overwrites
99
135
  # (no append, replaces contents entirely)
100
- base_cmd = f"echo {quoted_data} > {quoted_path}"
101
-
136
+ base_cmd = f'sudo sh -c "echo {quoted_data} > {quoted_path}"'
137
+ input(base_cmd)
102
138
  # optional sudo password injection
103
139
  full_cmd = get_print_sudo_cmd(
104
140
  cmd=base_cmd,
@@ -150,29 +186,37 @@ def write_to_file(*args, **kwargs):
150
186
  Returns the file_path written.
151
187
  """
152
188
  file_path, contents = check_read_write_params(*args, **kwargs)
189
+ values,kwargs = get_from_kwargs(['file_path','contents'],del_kwarg=True,**kwargs)
190
+ dirname = os.path.dirname(file_path)
191
+
153
192
  if contents is None:
154
193
  raise ValueError("Missing contents to write.")
155
194
  user_at_host = kwargs.get("user_at_host")
156
- if user_at_host:
195
+ if get_user_pass_host_key(**kwargs):
196
+ make_dirs(dirname, exist_ok=True,**kwargs)
157
197
  kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
158
198
  # sanitize for shell safety
159
199
  quoted_path = shlex.quote(file_path)
160
200
  quoted_data = shlex.quote(str(contents))
161
201
  # shell command that fully overwrites
162
202
  # (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)
203
+ kwargs["cmd"] = f'sh -c "echo {quoted_data} > {quoted_path}"'
204
+ if not kwargs.get('password') and not kwargs.get('key'):
205
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
206
+ result = run_pruned_func(run_cmd,**kwargs)
207
+ if not is_file(file_path,**kwargs) or str(contents) != read_from_file(file_path,**kwargs):
208
+ kwargs["cmd"]=f'sudo {kwargs["cmd"]}'
209
+ result = run_pruned_func(run_cmd,**kwargs)
210
+ return result
211
+
212
+ make_dirs(dirname or ".", exist_ok=True)
168
213
  with open(file_path, "w", encoding="utf-8") as f:
169
214
  f.write(str(contents))
170
215
  return file_path
171
216
 
172
217
 
173
218
  def read_from_file(file_path,**kwargs):
174
- user_at_host = kwargs.get("user_at_host")
175
- if user_at_host:
219
+ if get_user_pass_host_key(**kwargs):
176
220
  kwargs["cwd"] = kwargs.get('cwd') or os.path.dirname(file_path)
177
221
  basename = os.path.basename(file_path)
178
222
  kwargs["cmd"] = f'cat {basename}'
@@ -180,7 +224,36 @@ def read_from_file(file_path,**kwargs):
180
224
  """Read text content from a file."""
181
225
  with open(file_path, "r", encoding="utf-8") as f:
182
226
  return f.read()
183
-
227
+ def get_rel_path(src,src_rel,directory):
228
+ if src.startswith(src_rel):
229
+ src = src[len(src_rel):]
230
+ rel_path = os.path.join(directory,src)
231
+ return rel_path
232
+ def make_relative_path(src,src_rel,dst,**kwargs):
233
+ print(f"src == {src}\nsrc_rel == {src_rel}\dst == {dst}")
234
+ if src.startswith(src_rel):
235
+ rel_path = get_rel_path(src,src_rel,dst)
236
+ path = make_path(src,home_dir=rel_path,**kwargs)
237
+ print(f"path == {path}")
238
+ return path
239
+ def copy_dirs(dirs,dst,src_rel=None,**kwargs):
240
+ for src in dirs:
241
+ if rel_path:
242
+ dst = make_relative_path(src,src_rel,dst,**kwargs)
243
+ make_path(dst,**kwargs)
244
+
245
+ def copy_file(src,dst,rel_path=None,**kwargs):
246
+ if rel_path:
247
+ dst = make_relative_path(src,rel_path,dst,**kwargs)
248
+ if get_user_pass_host_key(**kwargs):
249
+ contents=read_from_file(src,**kwargs)
250
+ write_to_file(contents=contents,file_path=dst,**kwargs)
251
+ else:
252
+ shutil.copy(src,dst)
253
+ return dst
254
+ def copy_files(files,dst,rel_path=None,**kwargs):
255
+ for file in files:
256
+ copy_file(src=file,dst=dst,rel_path=rel_path,**kwargs)
184
257
 
185
258
  def create_and_read_file(*args, **kwargs):
186
259
  """
@@ -8,8 +8,8 @@ from_tag = 'from '
8
8
  def get_text_or_read(text=None,file_path=None):
9
9
  text = text or ''
10
10
  imports_js = {}
11
- if file_path and os.path.isfile(file_path):
12
- text+=read_from_file(file_path)
11
+ if not text and file_path and os.path.isfile(file_path):
12
+ text=read_from_file(file_path)
13
13
  return text
14
14
  def is_line_import(line):
15
15
  if line and (line.startswith(from_tag) or line.startswith(import_tag)):
@@ -142,6 +142,30 @@ def clean_all_imports(text=None,file_path=None,import_pkg_js=None):
142
142
  nu_lines[line] += imports
143
143
  import_pkg_js["nulines"]=nu_lines
144
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)
145
169
  def save_cleaned_imports(text=None,file_path=None,write=False,import_pkg_js=None):
146
170
  import_pkg_js=get_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
147
171
  import_pkg_js = clean_all_imports(text=text,file_path=file_path,import_pkg_js=import_pkg_js)
@@ -1,3 +1,42 @@
1
+ from .list_utils import make_list
2
+ def get_from_kwargs(*args,**kwargs):
3
+ del_kwarg = kwargs.get('del_kwargs',False)
4
+ values = {}
5
+ for key in args:
6
+ if key:
7
+ key = str(key)
8
+ if key in kwargs:
9
+ values[key] = kwargs.get(key)
10
+ if del_kwarg:
11
+ del kwargs[key]
12
+ return values,kwargs
13
+
14
+ def replace_it(string,item,rep):
15
+ if item in string:
16
+ string = string.replace(item,rep)
17
+ return string
18
+ def while_replace(string,item,rep):
19
+ while True:
20
+ string = replace_it(string,item,rep)
21
+ if item not in string or item in rep:
22
+ return string
23
+ def for_replace(string,item,replace):
24
+ replace = make_list(replace)
25
+ for rep in replace:
26
+ string = while_replace(string,item,rep)
27
+ return string
28
+ def replace_all(string,*args,**kwargs):
29
+ for items in args:
30
+ if items and isinstance(items,list):
31
+ item = items[0]
32
+ replace = items[1:] if len(items)>1 else items[-1]
33
+ string = for_replace(string,item,replace)
34
+ values,kwargs = get_from_kwargs('item','replace',**kwargs)
35
+ if values:
36
+ string = for_replace(string,**values)
37
+ for item,replace in kwargs.items():
38
+ string = for_replace(string,item,rep)
39
+ return string
1
40
  def get_lines(string,strip=True):
2
41
  lines = string.split('\n')
3
42
  if strip:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: abstract_utilities
3
- Version: 0.2.2.474
3
+ Version: 0.2.2.488
4
4
  Summary: abstract_utilities is a collection of utility modules providing a variety of functions to aid in tasks such as data comparison, list manipulation, JSON handling, string manipulation, mathematical computations, and time operations.
5
5
  Home-page: https://github.com/AbstractEndeavors/abstract_utilities
6
6
  Author: putkoff
@@ -14,10 +14,10 @@ abstract_utilities/log_utils.py,sha256=W74Y-CmdQP4Kj88HmAgejVxWgyWlvgCKMwLvOfyFf
14
14
  abstract_utilities/math_utils.py,sha256=0o1ls1En03UAkYmxTBildCCJDfHygmNuvVnrNrLYtK0,6578
15
15
  abstract_utilities/parse_utils.py,sha256=Z5OGRwHuzCzY91fz0JJojk1BPAo1XF2quNNLuBF4_Vk,18602
16
16
  abstract_utilities/path_utils.py,sha256=X_U9cPBbNu5Wi0F3hQE0gXQX1gfhzxhxALbairTEOZU,19252
17
- abstract_utilities/read_write_utils.py,sha256=S8Sj0mtErRze9uOOzdWl2ZreREdXKKQMbyQKC75c_Vc,6921
17
+ abstract_utilities/read_write_utils.py,sha256=9jW-eQojjXGAtyeCQp2m_1Rx6KgDGp3GHN0jwdqZlcA,9941
18
18
  abstract_utilities/safe_utils.py,sha256=_uoZny6dJjopVakOiaf0UIZcvRRXMh51FpfDUooe0xY,3733
19
19
  abstract_utilities/string_clean.py,sha256=oQv85J-mA4sP2NJwbTI-1k0RXw7V0AmqZolYaAZvex4,6916
20
- abstract_utilities/string_utils.py,sha256=02xdIEDySWEexrtY3skBYOdeDmr3XgE5j1nqAeAv7w8,352
20
+ abstract_utilities/string_utils.py,sha256=PnII0wFQBchVzFjhvEHP9ej1zxLehsRKodtc8Qol4-8,1645
21
21
  abstract_utilities/tetsts.py,sha256=PrejTUew5dAAqNb4erMJwfdSHxDyuuHGWY2fMlWk5hk,21
22
22
  abstract_utilities/thread_utils.py,sha256=LhE1ylSuOKkkMErBf6SjZprjO_vfh3IKfvNKJQiCxho,5460
23
23
  abstract_utilities/time_utils.py,sha256=yikMjn7i-OBKfmOujfNtDz4R0VTMgi3dfQNrCIZUbQU,13052
@@ -50,12 +50,12 @@ abstract_utilities/file_utils/file_utils/find_collect.py,sha256=bPM7EDrNHlvwZx7C
50
50
  abstract_utilities/file_utils/file_utils/imports.py,sha256=rF3zdWY98UKuSPwzEzhG0H4cfIVjLqCW3FwsGqFeakE,319
51
51
  abstract_utilities/file_utils/file_utils/map_utils.py,sha256=B_MlkLP8s-o0yU0R3Y2LcTpBntBzysJO18qq181xz9c,1043
52
52
  abstract_utilities/file_utils/file_utils/pdf_utils.py,sha256=D_wg8h-SapCvqinxRIKxMri1jWZNpr5jGvKq9EJePfY,10335
53
- abstract_utilities/file_utils/file_utils/type_checks.py,sha256=S1k5lDM1Qd5g1FE_KqIE1aWexsFI0Af9droRI6qVb30,2576
53
+ abstract_utilities/file_utils/file_utils/type_checks.py,sha256=XuKDtdYJFNHATZX3VcWLatqqcvyxl7is-bEZKxWglpE,2890
54
54
  abstract_utilities/file_utils/file_utils/imports/__init__.py,sha256=Mip2n-nY1PLvaWtwTeVs0rdVd6J3_jfwKmIyGYxf9Vo,72
55
55
  abstract_utilities/file_utils/file_utils/imports/constants.py,sha256=eIeSj48vtfa8CTYKuuZXbgJQepBrMracfVguaSuN41U,1626
56
56
  abstract_utilities/file_utils/file_utils/imports/file_functions.py,sha256=25yta20DDsdgenXYjpm4Ma3Fd6WK9Q16EjyhcZubDFg,291
57
57
  abstract_utilities/file_utils/file_utils/imports/imports.py,sha256=nLtDCj-E9htQ1rbbISevHSqviUGCxgCoTZ7KTAQrCpU,1488
58
- abstract_utilities/file_utils/file_utils/imports/module_imports.py,sha256=pvRkjtWxQ9R4TisCKMQ9asDak63Y9eMGbpCB7DsEyqs,453
58
+ abstract_utilities/file_utils/file_utils/imports/module_imports.py,sha256=BG_eTb_lnOOHCye_aXYc0CoESzFtXw_8qMMEH3CPLmU,546
59
59
  abstract_utilities/file_utils/imports/__init__.py,sha256=PRJBiiPT7oElD3RvHTW80Xd5rIIMdzGN23FD5IkszDI,101
60
60
  abstract_utilities/file_utils/imports/classes.py,sha256=zw16D_h5AxJiks4ydbqkWkXVfvgmE-BpiC4eKInY_KI,12259
61
61
  abstract_utilities/file_utils/imports/clean_imps.py,sha256=DB_NEKR8YLla5qCkTMuNscMoTnipEm3nCWnaH8wqQDc,5287
@@ -73,7 +73,7 @@ abstract_utilities/robust_readers/__init__.py,sha256=_1vhOG1FJnfrRK0ubkT1v6U6udH
73
73
  abstract_utilities/robust_readers/imports.py,sha256=FtNxdPoLeeNycDnl-6rBGxBfYjhQ7VhmI5guj8XKFcU,355
74
74
  abstract_utilities/robust_readers/initFuncGen.py,sha256=nrQn1KpSlPNKoOngN1uizVwNMA4llrcd8aGKqlzpXzI,5436
75
75
  abstract_utilities/robust_readers/import_utils/__init__.py,sha256=0XaHXUzvgMjSV-4VXcBB-sLcXzL3U3ssHZ95YkvgS9w,195
76
- abstract_utilities/robust_readers/import_utils/clean_imports.py,sha256=i37JKV85rNDk5VEqN41dcN6rQnfpusVD_0WXVhYx-74,6418
76
+ abstract_utilities/robust_readers/import_utils/clean_imports.py,sha256=eQo7UvO9jiMY7ncFpHyT-BFLNvov6QA4IRoP7MITuls,7228
77
77
  abstract_utilities/robust_readers/import_utils/dot_utils.py,sha256=pmwnY461mOnDjIjgHD6H9MhQXFaF-q8kWerJDgJ1DuI,2364
78
78
  abstract_utilities/robust_readers/import_utils/function_utils.py,sha256=Q9NKvRov3uAaz2Aal3d6fb_opWNXHF9C8GSKOjgfO8Y,1622
79
79
  abstract_utilities/robust_readers/import_utils/import_utils.py,sha256=l0GYdtj5FEYX2yknL-8ru7_U2Sp9Hi1NpegqWPLRMc8,11705
@@ -86,7 +86,7 @@ abstract_utilities/ssh_utils/classes.py,sha256=3Q9BfLpyagNFYyiF4bt-5UCezeUJv9NK9
86
86
  abstract_utilities/ssh_utils/imports.py,sha256=oX8WAv-pkhizzko_h3fIUp9Vhsse4nR7RN2vwONxIx0,317
87
87
  abstract_utilities/ssh_utils/pexpect_utils.py,sha256=JBdOIXBTXAqE5TrsFjmPWJgwSaWyRJN8rbJ6y3_zKPY,10556
88
88
  abstract_utilities/ssh_utils/utils.py,sha256=smUWAx3nW1h0etTndJ_te9bkUX5YzQ8kYd9_gD1TXLk,4882
89
- abstract_utilities-0.2.2.474.dist-info/METADATA,sha256=kY7j3j6pms-_O3a1KChnVHxB75JMcar9Mf6C63VLmzI,28108
90
- abstract_utilities-0.2.2.474.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
- abstract_utilities-0.2.2.474.dist-info/top_level.txt,sha256=BF0GZ0xVFfN1K-hFIWPO3viNsOs1sSF86n1vHBg39FM,19
92
- abstract_utilities-0.2.2.474.dist-info/RECORD,,
89
+ abstract_utilities-0.2.2.488.dist-info/METADATA,sha256=rta42TF8pwLWyBz2dR-dx085mU_Sd-HOpzQLVpeLYro,28108
90
+ abstract_utilities-0.2.2.488.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
91
+ abstract_utilities-0.2.2.488.dist-info/top_level.txt,sha256=BF0GZ0xVFfN1K-hFIWPO3viNsOs1sSF86n1vHBg39FM,19
92
+ abstract_utilities-0.2.2.488.dist-info/RECORD,,