omlish 0.0.0.dev457__py3-none-any.whl → 0.0.0.dev459__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.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev457'
2
- __revision__ = '64cce982d49f06067f317ce043a99f89db92e3ae'
1
+ __version__ = '0.0.0.dev459'
2
+ __revision__ = 'a12178d42c88b1d69bca74aaf2cd0f1fd8106a47'
3
3
 
4
4
 
5
5
  #
@@ -83,7 +83,7 @@ class Project(ProjectBase):
83
83
  ],
84
84
 
85
85
  'secrets': [
86
- 'cryptography ~= 45.0',
86
+ 'cryptography ~= 46.0',
87
87
  ],
88
88
 
89
89
  'sqlalchemy': [
omlish/diag/pydevd.py CHANGED
@@ -6,7 +6,7 @@ an already-debugging PyCharm instance to debug PySpark jobs.
6
6
  TODO:
7
7
  - https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html#
8
8
 
9
- ==
9
+ ====
10
10
 
11
11
  https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html#remote-debug-config ->
12
12
 
@@ -25,13 +25,34 @@ buf = textwrap.dedent(f'''
25
25
  stderrToServer=True,
26
26
  )
27
27
  ''') + '\n' * 2 + buf
28
+
29
+ ====
30
+
31
+ TODO: monkeypatch:
32
+
33
+ /Applications/PyCharm.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_monkey.py ::
34
+
35
+ def starts_with_python_shebang(path):
36
+ try:
37
+ with open(path) as f:
38
+ for line in f:
39
+ line = line.strip()
40
+ if line:
41
+ for name in PYTHON_NAMES:
42
+ if line.startswith('#!/usr/bin/env %s' % name):
43
+ return True
44
+ return False
45
+ except (UnicodeDecodeError, IsADirectoryError): # <-- Add catch for `IsADirectoryError`
46
+ return False
47
+ except:
48
+ traceback.print_exc()
49
+ return False
28
50
  """
29
51
  import json
30
52
  import os
31
53
  import sys
32
54
  import tempfile
33
55
  import textwrap
34
- import threading
35
56
  import types
36
57
  import typing as ta
37
58
 
@@ -255,23 +276,23 @@ def maybe_reexec(
255
276
  bootstrap_path = os.path.join(tmpdir, 'bootstrap.py')
256
277
  with open(bootstrap_path, 'w') as f:
257
278
  f.write(textwrap.dedent(f"""
258
- import sys
259
- old_paths = set(sys.path)
260
- for new_path in {sys.path!r}:
261
- if new_path not in old_paths:
262
- sys.path.insert(0, new_path)
263
-
264
- _stderr_write = sys.stderr.write
265
- def stderr_write(*args, **kwargs):
266
- code = sys._getframe(1).f_code
267
- if code is not None and code.co_filename and code.co_filename.endswith('/pydev_log.py'):
268
- return
269
- _stderr_write(*args, **kwargs)
270
- sys.stderr.write = stderr_write
271
-
272
- sys.argv = {args[1:]!r}
273
- import runpy
274
- runpy.run_path({args[1]!r}, run_name='__main__')
279
+ import sys
280
+ old_paths = set(sys.path)
281
+ for new_path in {sys.path!r}:
282
+ if new_path not in old_paths:
283
+ sys.path.insert(0, new_path)
284
+
285
+ _stderr_write = sys.stderr.write
286
+ def stderr_write(*args, **kwargs):
287
+ code = sys._getframe(1).f_code
288
+ if code is not None and code.co_filename and code.co_filename.endswith('/pydev_log.py'):
289
+ return
290
+ _stderr_write(*args, **kwargs)
291
+ sys.stderr.write = stderr_write
292
+
293
+ sys.argv = {args[1:]!r}
294
+ import runpy
295
+ runpy.run_path({args[1]!r}, run_name='__main__')
275
296
  """))
276
297
  args = [args[0], bootstrap_path]
277
298
 
@@ -284,29 +305,14 @@ def debug_unhandled_exception(exc_info: ta.Any = None) -> None:
284
305
 
285
306
  try:
286
307
  import pydevd
287
- from pydevd import pydevd_tracing
288
308
 
289
309
  except ImportError:
290
310
  return
291
311
 
292
- exctype, value, traceback = exc_info
293
- frames = []
294
- while traceback:
295
- frames.append(traceback.tb_frame)
296
- traceback = traceback.tb_next
297
-
298
- thread = threading.current_thread()
299
- frames_by_id = {id(frame): frame for frame in frames}
300
- frame = frames[-1]
301
- exception = (exctype, value, traceback)
302
-
303
- if hasattr(thread, 'additional_info'):
304
- thread.additional_info.pydev_message = 'server exception'
305
- try:
306
- debugger = pydevd.debugger # noqa
307
- except AttributeError:
308
- debugger = pydevd.get_global_debugger() # noqa
312
+ et, e, tb = exc_info
309
313
 
310
- pydevd_tracing.SetTrace(None)
314
+ while tb.tb_next is not None:
315
+ tb = tb.tb_next
316
+ original_frame = tb.tb_frame
311
317
 
312
- debugger.stop_on_unhandled_exception(thread, frame, frames_by_id, exception)
318
+ pydevd.settrace(stop_at_frame=original_frame, suspend=True)
@@ -5,6 +5,9 @@
5
5
  #define Py_BUILD_CORE 1
6
6
  #include "Python.h"
7
7
  #include "internal/pycore_frame.h"
8
+ #if PY_VERSION_HEX >= 0x030E0000
9
+ #include "internal/pycore_interpframe.h"
10
+ #endif
8
11
  #undef Py_BUILD_CORE
9
12
 
10
13
  #if PY_VERSION_HEX < 0x030D0000
@@ -50,14 +53,12 @@ _set_frame_builtins(PyObject *self, PyObject *args)
50
53
 
51
54
  std::atomic_ref<PyObject*> builtins_ref(iframe->f_builtins);
52
55
  PyObject* expected = old_builtins;
53
- bool success = builtins_ref.compare_exchange_strong(
56
+ if (builtins_ref.compare_exchange_strong(
54
57
  expected,
55
58
  new_builtins,
56
59
  std::memory_order_acq_rel,
57
60
  std::memory_order_acquire
58
- );
59
-
60
- if (success) {
61
+ )) {
61
62
  Py_RETURN_TRUE;
62
63
  } else {
63
64
  Py_RETURN_FALSE;
@@ -15,6 +15,7 @@ Possible alt impls:
15
15
  import builtins
16
16
  import contextlib
17
17
  import functools
18
+ import importlib.util
18
19
  import sys
19
20
  import threading
20
21
  import types
@@ -46,14 +47,27 @@ class ImportCaptureErrors:
46
47
  return f'{self.__class__.__qualname__}(module={self.module!r}, name={self.name!r})'
47
48
 
48
49
  class ImportError(ImportCaptureError): # noqa
49
- def __init__(self, module: str, from_list: ta.Sequence[str] | None) -> None:
50
+ def __init__(
51
+ self,
52
+ name: str,
53
+ *,
54
+ level: int | None = None,
55
+ from_list: ta.Sequence[str] | None,
56
+ ) -> None:
50
57
  super().__init__()
51
58
 
52
- self.module = module
59
+ self.name = name
60
+ self.level = level
53
61
  self.from_list = from_list
54
62
 
55
63
  def __repr__(self) -> str:
56
- return f'{self.__class__.__qualname__}(module={self.module!r}, from_list={self.from_list!r})'
64
+ return ''.join([
65
+ f'{self.__class__.__qualname__}(',
66
+ f'name={self.name!r}',
67
+ *([f', level={self.level!r}'] if self.level is not None else []),
68
+ *([f', from_list={self.from_list!r}'] if self.from_list is not None else []),
69
+ ')',
70
+ ])
57
71
 
58
72
  class ImportStarForbiddenError(ImportError):
59
73
  pass
@@ -62,7 +76,7 @@ class ImportCaptureErrors:
62
76
  pass
63
77
 
64
78
  class UnreferencedImportsError(ImportCaptureError):
65
- def __init__(self, unreferenced: ta.Mapping[str, ta.Sequence[str | None]]) -> None:
79
+ def __init__(self, unreferenced: ta.Sequence[str]) -> None:
66
80
  super().__init__()
67
81
 
68
82
  self.unreferenced = unreferenced
@@ -78,136 +92,144 @@ class ImportCaptureErrors:
78
92
 
79
93
 
80
94
  class _ImportCaptureHook:
81
- class ModuleSpec(ta.NamedTuple):
82
- name: str
83
- level: int
84
-
85
- def __str__(self) -> str:
86
- return f'{"." * self.level}{self.name}'
87
-
88
- def __repr__(self) -> str:
89
- return repr(str(self))
90
-
91
95
  def __init__(
92
96
  self,
93
97
  *,
98
+ package: str | None = None,
94
99
  forbid_uncaptured_imports: bool = False,
95
100
  ) -> None:
96
101
  super().__init__()
97
102
 
103
+ self._package = package
98
104
  self._forbid_uncaptured_imports = forbid_uncaptured_imports
99
105
 
100
- self._modules_by_spec: dict[_ImportCaptureHook.ModuleSpec, _ImportCaptureHook._Module] = {}
106
+ self._modules_by_name: dict[str, _ImportCaptureHook._Module] = {}
101
107
  self._modules_by_module_obj: dict[types.ModuleType, _ImportCaptureHook._Module] = {}
102
108
 
103
- self._attrs: dict[_ImportCaptureHook._ModuleAttr, tuple[_ImportCaptureHook._Module, str]] = {}
104
-
105
109
  #
106
110
 
107
- class _ModuleAttr:
111
+ class _Module:
108
112
  def __init__(
109
113
  self,
110
- module: '_ImportCaptureHook._Module',
111
114
  name: str,
115
+ getattr_handler: ta.Callable[['_ImportCaptureHook._Module', str], ta.Any],
116
+ *,
117
+ parent: ta.Optional['_ImportCaptureHook._Module'] = None,
112
118
  ) -> None:
113
119
  super().__init__()
114
120
 
115
- self.__module = module
116
- self.__name = name
121
+ if name.startswith('.'):
122
+ raise ImportCaptureError
123
+ self.name = name
124
+ self.base_name = name.rpartition('.')[2]
125
+ self.parent = parent
126
+
127
+ self.module_obj = types.ModuleType(f'<{self.__class__.__qualname__}: {name}>')
128
+ self.module_obj.__file__ = None
129
+ self.module_obj.__getattr__ = functools.partial(getattr_handler, self) # type: ignore[method-assign] # noqa
130
+ self.initial_module_dict = dict(self.module_obj.__dict__)
131
+
132
+ self.children: dict[str, _ImportCaptureHook._Module] = {}
133
+ self.descendants: set[_ImportCaptureHook._Module] = set()
134
+ self.explicit = False
135
+ self.immediate = False
117
136
 
118
137
  def __repr__(self) -> str:
119
- return f'<{self.__class__.__name__}: {f"{self.__module.spec}:{self.__name}"!r}>'
138
+ return f'{self.__class__.__name__}<{self.name}{"!" if self.immediate else "+" if self.explicit else ""}>'
120
139
 
121
- class _Module:
122
- def __init__(
123
- self,
124
- spec: '_ImportCaptureHook.ModuleSpec',
125
- *,
126
- getattr_handler: ta.Callable[['_ImportCaptureHook._Module', str], ta.Any] | None = None,
127
- ) -> None:
128
- super().__init__()
140
+ @property
141
+ def root(self) -> '_ImportCaptureHook._Module':
142
+ out = self
143
+ while out.parent is not None:
144
+ out = out.parent
145
+ return out
146
+
147
+ def set_explicit(self) -> None:
148
+ cur: _ImportCaptureHook._Module | None = self
149
+ while cur is not None and not cur.explicit:
150
+ cur.explicit = True
151
+ cur = cur.parent
129
152
 
130
- self.spec = spec
153
+ #
131
154
 
132
- self.module_obj = types.ModuleType(f'<{self.__class__.__qualname__}: {spec!r}>')
133
- if getattr_handler is not None:
134
- self.module_obj.__getattr__ = functools.partial(getattr_handler, self) # type: ignore[method-assign] # noqa
135
- self.initial_module_dict = dict(self.module_obj.__dict__)
155
+ @property
156
+ def _modules(self) -> ta.Sequence[_Module]:
157
+ return sorted(self._modules_by_name.values(), key=lambda m: m.name)
158
+
159
+ def _get_or_make_module(self, name: str) -> _Module:
160
+ def rec(name: str) -> _ImportCaptureHook._Module: # noqa
161
+ try:
162
+ return self._modules_by_name[name]
163
+ except KeyError:
164
+ pass
165
+
166
+ parent: _ImportCaptureHook._Module | None = None
167
+ if '.' in name:
168
+ rest, _, attr = name.rpartition('.')
169
+ parent = rec(rest)
170
+ if attr in parent.children:
171
+ raise ImportCaptureErrors.AttrError(rest, attr)
172
+
173
+ module = self._Module(
174
+ name,
175
+ self._handle_module_getattr,
176
+ parent=parent,
177
+ )
178
+ self._modules_by_name[name] = module
179
+ self._modules_by_module_obj[module.module_obj] = module
136
180
 
137
- self.contents: dict[str, _ImportCaptureHook._ModuleAttr | types.ModuleType] = {}
138
- self.imported_whole = False
181
+ if parent is not None:
182
+ parent.children[attr] = module # noqa
183
+ setattr(parent.module_obj, attr, module.module_obj)
184
+ parent.root.descendants.add(module)
139
185
 
140
- def __repr__(self) -> str:
141
- return f'{self.__class__.__name__}({self.spec!r})'
186
+ return module
142
187
 
143
- def _get_or_make_module(self, spec: ModuleSpec) -> _Module:
144
- try:
145
- return self._modules_by_spec[spec]
146
- except KeyError:
147
- pass
188
+ return rec(name)
148
189
 
149
- module = self._Module(
150
- spec,
151
- getattr_handler=self._handle_module_getattr,
152
- )
153
- self._modules_by_spec[spec] = module
154
- self._modules_by_module_obj[module.module_obj] = module
155
- return module
190
+ def _make_child_module(self, module: _Module, attr: str) -> _Module:
191
+ if attr in module.children:
192
+ raise ImportCaptureErrors.AttrError(module.name, attr)
156
193
 
157
- def _handle_module_getattr(self, module: _Module, attr: str) -> ta.Any:
158
- if attr in module.contents:
159
- raise ImportCaptureErrors.AttrError(str(module.spec), attr)
194
+ return self._get_or_make_module(f'{module.name}.{attr}')
160
195
 
161
- v: _ImportCaptureHook._ModuleAttr | types.ModuleType
162
- if not module.spec.name:
163
- if not module.spec.level:
164
- raise ImportCaptureError
165
- cs = _ImportCaptureHook.ModuleSpec(attr, module.spec.level)
166
- cm = self._get_or_make_module(cs)
167
- cm.imported_whole = True
168
- v = cm.module_obj
196
+ #
169
197
 
170
- else:
171
- ma = _ImportCaptureHook._ModuleAttr(module, attr)
172
- self._attrs[ma] = (module, attr)
173
- v = ma
198
+ def _handle_module_getattr(self, module: _Module, attr: str) -> ta.Any:
199
+ if not module.explicit:
200
+ raise ImportCaptureErrors.AttrError(module.name, attr)
174
201
 
175
- module.contents[attr] = v
176
- setattr(module.module_obj, attr, v)
177
- return v
202
+ return self._make_child_module(module, attr).module_obj
178
203
 
179
204
  def _handle_import(
180
205
  self,
181
- module: _Module,
206
+ name: str,
182
207
  *,
183
208
  from_list: ta.Sequence[str] | None,
184
- ) -> None:
185
- if from_list is None:
186
- if module.spec.level or not module.spec.name:
187
- raise ImportCaptureError
209
+ ) -> types.ModuleType:
210
+ module = self._get_or_make_module(name)
188
211
 
189
- module.imported_whole = True
212
+ if from_list is None:
213
+ module.set_explicit()
214
+ module.root.immediate = True
215
+ return module.root.module_obj
190
216
 
191
217
  else:
192
218
  for attr in from_list:
193
219
  if attr == '*':
194
- raise ImportCaptureErrors.ImportStarForbiddenError(str(module.spec), from_list)
220
+ raise ImportCaptureErrors.ImportStarForbiddenError(module.name, from_list=from_list)
221
+
222
+ if (cm := module.children.get(attr)) is None:
223
+ cm = self._make_child_module(module, attr)
224
+ cm.set_explicit()
225
+ cm.immediate = True
226
+ continue
195
227
 
196
228
  x = getattr(module.module_obj, attr)
229
+ if x is not cm.module_obj or x not in self._modules_by_module_obj:
230
+ raise ImportCaptureErrors.AttrError(module.name, attr)
197
231
 
198
- bad = False
199
- if x is not module.contents.get(attr):
200
- bad = True
201
- if isinstance(x, _ImportCaptureHook._ModuleAttr):
202
- if self._attrs[x] != (module, attr):
203
- bad = True
204
- elif isinstance(x, types.ModuleType):
205
- if x not in self._modules_by_module_obj:
206
- bad = True
207
- else:
208
- bad = True
209
- if bad:
210
- raise ImportCaptureErrors.AttrError(str(module.spec), attr)
232
+ return module.module_obj
211
233
 
212
234
  #
213
235
 
@@ -227,16 +249,16 @@ class _ImportCaptureHook:
227
249
  ):
228
250
  return None
229
251
 
230
- spec = _ImportCaptureHook.ModuleSpec(name, level)
231
- module = self._get_or_make_module(spec)
252
+ if level:
253
+ if not self._package:
254
+ raise ImportCaptureError
255
+ name = importlib.util.resolve_name(('.' * level) + name, self._package)
232
256
 
233
- self._handle_import(
234
- module,
257
+ return self._handle_import(
258
+ name,
235
259
  from_list=from_list,
236
260
  )
237
261
 
238
- return module.module_obj
239
-
240
262
  @ta.final
241
263
  @contextlib.contextmanager
242
264
  def hook_context(
@@ -271,18 +293,24 @@ class _ImportCaptureHook:
271
293
  self,
272
294
  mod_globals: ta.MutableMapping[str, ta.Any], # noqa
273
295
  ) -> None:
274
- for m in self._modules_by_spec.values():
296
+ for m in self._modules_by_name.values():
297
+ if m.immediate and not m.explicit:
298
+ raise ImportCaptureError
299
+
300
+ if not m.explicit and m.children:
301
+ raise ImportCaptureError
302
+
275
303
  for a, o in m.module_obj.__dict__.items():
276
304
  try:
277
305
  i = m.initial_module_dict[a]
278
306
 
279
307
  except KeyError:
280
- if o is not m.contents[a]:
281
- raise ImportCaptureErrors.AttrError(str(m.spec), a) from None
308
+ if o is not m.children[a].module_obj:
309
+ raise ImportCaptureErrors.AttrError(m.name, a) from None
282
310
 
283
311
  else:
284
312
  if o != i:
285
- raise ImportCaptureErrors.AttrError(str(m.spec), a)
313
+ raise ImportCaptureErrors.AttrError(m.name, a)
286
314
 
287
315
  #
288
316
 
@@ -292,24 +320,16 @@ class _ImportCaptureHook:
292
320
  *,
293
321
  collect_unreferenced: bool = False,
294
322
  ) -> 'ImportCapture.Captured':
295
- dct: dict[_ImportCaptureHook._Module, list[tuple[str | None, str]]] = {}
296
-
297
- rem_whole_mods: set[_ImportCaptureHook._Module] = set()
298
- rem_mod_attrs: set[_ImportCaptureHook._ModuleAttr] = set()
323
+ rem_explicit_mods: set[_ImportCaptureHook._Module] = set()
299
324
  if collect_unreferenced:
300
- rem_whole_mods.update([m for m in self._modules_by_spec.values() if m.imported_whole])
301
- rem_mod_attrs.update(self._attrs)
325
+ rem_explicit_mods.update([m for m in self._modules_by_name.values() if m.immediate])
302
326
 
303
- for attr, obj in mod_globals.items():
304
- if isinstance(obj, _ImportCaptureHook._ModuleAttr):
305
- try:
306
- m, a = self._attrs[obj]
307
- except KeyError:
308
- raise ImportCaptureErrors.AttrError(None, attr) from None
309
- dct.setdefault(m, []).append((a, attr))
310
- rem_mod_attrs.discard(obj)
327
+ #
328
+
329
+ dct: dict[_ImportCaptureHook._Module, list[tuple[str | None, str]]] = {}
311
330
 
312
- elif isinstance(obj, _ImportCaptureHook._Module):
331
+ for attr, obj in mod_globals.items():
332
+ if isinstance(obj, _ImportCaptureHook._Module):
313
333
  raise ImportCaptureErrors.AttrError(None, attr) from None
314
334
 
315
335
  elif isinstance(obj, types.ModuleType):
@@ -317,41 +337,80 @@ class _ImportCaptureHook:
317
337
  m = self._modules_by_module_obj[obj]
318
338
  except KeyError:
319
339
  continue
320
- if not m.imported_whole:
321
- raise RuntimeError(f'ImportCapture module {m.spec!r} not imported_whole')
322
- dct.setdefault(m, []).append((None, attr))
323
- rem_whole_mods.discard(m)
324
-
325
- lst: list[ImportCapture.Import] = []
326
- for m, ts in dct.items():
327
- if not m.spec.name:
328
- if not m.spec.level:
329
- raise ImportCaptureError
330
- for imp_attr, as_attr in ts:
331
- if not imp_attr:
332
- raise RuntimeError
333
- lst.append(ImportCapture.Import(
334
- '.' * m.spec.level + imp_attr,
335
- [(None, as_attr)],
336
- ))
337
340
 
338
- else:
339
- lst.append(ImportCapture.Import(
340
- str(m.spec),
341
- ts,
342
- ))
343
-
344
- unreferenced: dict[str, list[str | None]] | None = None
345
- if collect_unreferenced and (rem_whole_mods or rem_mod_attrs):
346
- unreferenced = {}
347
- for m in rem_whole_mods:
348
- unreferenced.setdefault(str(m.spec), []).append(None)
349
- for ma in rem_mod_attrs:
350
- m, a = self._attrs[ma]
351
- unreferenced.setdefault(str(m.spec), []).append(a)
341
+ if m.explicit:
342
+ dct.setdefault(m, []).append((None, attr))
343
+ if m in rem_explicit_mods:
344
+ # Remove everything reachable from this root *except* items imported immediately, such as
345
+ # `from x import y` - those still need to be immediately reachable.
346
+ rem_explicit_mods -= {dm for dm in m.descendants if not dm.immediate}
347
+ rem_explicit_mods.remove(m)
348
+
349
+ else:
350
+ p = m.parent
351
+ if p is None or not p.explicit:
352
+ raise ImportCaptureError
353
+ dct.setdefault(p, []).append((m.base_name, attr))
354
+
355
+ #
356
+
357
+ mods: dict[str, ImportCapture.Module] = {}
358
+
359
+ def build_import_module(m: _ImportCaptureHook._Module) -> ImportCapture.Module:
360
+ children: dict[str, ImportCapture.Module] = {}
361
+ attrs: list[str] = []
362
+ for cm in sorted(m.children.values(), key=lambda cm: cm.name):
363
+ if not cm.explicit:
364
+ attrs.append(cm.base_name)
365
+ else:
366
+ children[cm.base_name] = build_import_module(cm)
367
+
368
+ mod = ImportCapture.Module(
369
+ m.name,
370
+ children or None,
371
+ attrs or None,
372
+ )
373
+
374
+ if m.parent is None:
375
+ mod.parent = None
376
+ for c in children.values():
377
+ c.parent = mod
378
+
379
+ mods[mod.name] = mod
380
+ return mod
381
+
382
+ root_mods: dict[str, ImportCapture.Module] = {
383
+ m.base_name: build_import_module(m)
384
+ for m in self._modules_by_name.values()
385
+ if m.parent is None
386
+ }
387
+
388
+ mods = dict(sorted(mods.items(), key=lambda t: t[0]))
389
+ root_mods = dict(sorted(root_mods.items(), key=lambda t: t[0]))
390
+
391
+ #
392
+
393
+ imps: list[ImportCapture.Import] = []
394
+
395
+ for m, ts in sorted(dct.items(), key=lambda t: t[0].name):
396
+ imps.append(ImportCapture.Import(
397
+ mods[m.name],
398
+ [r for l, r in ts if l is None],
399
+ [(l, r) for l, r in ts if l is not None],
400
+ ))
401
+
402
+ #
403
+
404
+ unreferenced: list[str] | None = None
405
+ if collect_unreferenced and rem_explicit_mods:
406
+ unreferenced = sorted(m.name for m in rem_explicit_mods)
352
407
 
353
408
  return ImportCapture.Captured(
354
- lst,
409
+ {i.module.name: i for i in imps},
410
+
411
+ mods,
412
+ root_mods,
413
+
355
414
  unreferenced,
356
415
  )
357
416
 
@@ -379,8 +438,9 @@ class _AbstractBuiltinsImportCaptureHook(_ImportCaptureHook):
379
438
 
380
439
  if self._forbid_uncaptured_imports:
381
440
  raise ImportCaptureErrors.UncapturedImportForbiddenError(
382
- str(_ImportCaptureHook.ModuleSpec(name, level)),
383
- fromlist,
441
+ name,
442
+ level=level,
443
+ from_list=fromlist,
384
444
  )
385
445
 
386
446
  return old_import(
@@ -579,6 +639,8 @@ def _new_import_capture_hook(
579
639
  if frame is None or frame.f_globals is not mod_globals:
580
640
  raise ImportCaptureError("Can't find importing frame")
581
641
 
642
+ kwargs.setdefault('package', mod_globals.get('__package__'))
643
+
582
644
  if _capture is not None:
583
645
  return _FrameBuiltinsImportCaptureHook(_frame=frame, **kwargs)
584
646
 
@@ -588,21 +650,110 @@ def _new_import_capture_hook(
588
650
  ##
589
651
 
590
652
 
653
+ ImportCaptureModuleKind: ta.TypeAlias = ta.Literal[
654
+ 'parent',
655
+ 'terminal',
656
+ 'leaf',
657
+ ]
658
+
659
+
591
660
  class ImportCapture:
592
- class Import(ta.NamedTuple):
593
- spec: str
594
- attrs: ta.Sequence[tuple[str | None, str]]
661
+ @ta.final
662
+ class Module:
663
+ def __init__(
664
+ self,
665
+ name: str,
666
+ children: ta.Mapping[str, 'ImportCapture.Module'] | None = None,
667
+ attrs: ta.Sequence[str] | None = None,
668
+ ) -> None:
669
+ self.name = name
670
+ self.children = children
671
+ self.attrs = attrs
672
+
673
+ self.base_name = name.rpartition('.')[2]
674
+
675
+ if not self.children and not self.attrs:
676
+ self.kind = 'leaf'
677
+ elif not self.children or all(c.kind == 'leaf' for c in self.children.values()):
678
+ self.kind = 'terminal'
679
+ else:
680
+ self.kind = 'parent'
681
+
682
+ parent: ta.Optional['ImportCapture.Module']
683
+
684
+ kind: ImportCaptureModuleKind
685
+
686
+ def __repr__(self) -> str:
687
+ return ''.join([
688
+ f'{self.__class__.__name__}(',
689
+ f'{self.name!r}',
690
+ f', :{self.kind}',
691
+ *([f', children=[{", ".join(map(repr, self.children))}]'] if self.children else []),
692
+ *([f', attrs={self.attrs!r}'] if self.attrs else []),
693
+ ')',
694
+ ])
695
+
696
+ @property
697
+ def root(self) -> 'ImportCapture.Module':
698
+ out = self
699
+ while out.parent is not None:
700
+ out = out.parent
701
+ return out
702
+
703
+ @ta.final
704
+ class Import:
705
+ def __init__(
706
+ self,
707
+ module: 'ImportCapture.Module',
708
+ as_: ta.Sequence[str],
709
+ attrs: ta.Sequence[tuple[str, str]], # ('foo', 'bar') -> `import foo as bar` - explicitly not a dict
710
+ ) -> None:
711
+ self.module = module
712
+ self.as_ = as_
713
+ self.attrs = attrs
714
+
715
+ def __repr__(self) -> str:
716
+ return ''.join([
717
+ f'{self.__class__.__name__}(',
718
+ f'{self.module.name!r}',
719
+ *([f', as_={self.as_!r}'] if self.as_ else []),
720
+ *([f', attrs={self.attrs!r}'] if self.attrs else []),
721
+ ')',
722
+ ])
723
+
724
+ @ta.final
725
+ class Captured:
726
+ def __init__(
727
+ self,
595
728
 
596
- class Captured(ta.NamedTuple):
597
- imports: ta.Sequence['ImportCapture.Import']
598
- unreferenced: ta.Mapping[str, ta.Sequence[str | None]] | None
729
+ imports: ta.Mapping[str, 'ImportCapture.Import'],
730
+
731
+ modules: ta.Mapping[str, 'ImportCapture.Module'],
732
+ root_modules: ta.Mapping[str, 'ImportCapture.Module'],
733
+
734
+ unreferenced: ta.Sequence[str] | None,
735
+ ) -> None:
736
+ self.imports = imports
737
+
738
+ self.modules = modules
739
+ self.root_modules = root_modules
740
+
741
+ self.unreferenced = unreferenced
599
742
 
600
743
  @property
601
744
  def attrs(self) -> ta.Iterator[str]:
602
- for pi in self.imports:
745
+ for pi in self.imports.values():
746
+ yield from pi.as_
603
747
  for _, a in pi.attrs:
604
748
  yield a
605
749
 
750
+ EMPTY_CAPTURED: ta.ClassVar[Captured] = Captured(
751
+ {},
752
+ {},
753
+ {},
754
+ None,
755
+ )
756
+
606
757
  #
607
758
 
608
759
  def __init__(
@@ -651,7 +802,7 @@ class ImportCapture:
651
802
  def capture(
652
803
  self,
653
804
  *,
654
- unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
805
+ unreferenced_callback: ta.Callable[[ta.Sequence[str]], None] | None = None,
655
806
  raise_unreferenced: bool = False,
656
807
  ) -> ta.Iterator[ta.Self]:
657
808
  if self._result_ is not None:
@@ -659,10 +810,7 @@ class ImportCapture:
659
810
 
660
811
  if self._disabled:
661
812
  self._result_ = ImportCapture._Result(
662
- ImportCapture.Captured(
663
- [],
664
- None,
665
- ),
813
+ ImportCapture.EMPTY_CAPTURED,
666
814
  )
667
815
  yield self
668
816
  return
@@ -683,9 +831,8 @@ class ImportCapture:
683
831
  if raise_unreferenced:
684
832
  raise ImportCaptureErrors.UnreferencedImportsError(blt.unreferenced)
685
833
 
686
- for pi in blt.imports:
687
- for _, a in pi.attrs:
688
- del self._mod_globals[a]
834
+ for a in blt.attrs:
835
+ del self._mod_globals[a]
689
836
 
690
837
  self._result_ = ImportCapture._Result(
691
838
  blt,
@@ -1,7 +1,3 @@
1
- """
2
- TODO:
3
- - if already imported just return?
4
- """
5
1
  import contextlib
6
2
  import functools
7
3
  import importlib.util
@@ -16,6 +12,47 @@ from .capture import _new_import_capture_hook
16
12
  ##
17
13
 
18
14
 
15
+ def _translate_old_style_import_capture(
16
+ cap: ImportCapture.Captured,
17
+ ) -> ta.Mapping[str, ta.Sequence[tuple[str | None, str]]]:
18
+ dct: dict[str, list[tuple[str | None, str]]] = {}
19
+
20
+ for ci in cap.imports.values():
21
+ if ci.module.kind == 'leaf':
22
+ if (p := ci.module.parent) is None:
23
+ raise NotImplementedError
24
+
25
+ if ci.attrs:
26
+ raise NotImplementedError
27
+
28
+ for a in ci.as_:
29
+ dct.setdefault(p.name, []).append(
30
+ (ci.module.base_name, a),
31
+ )
32
+
33
+ elif ci.module.kind == 'terminal':
34
+ if ci.module.children:
35
+ raise NotImplementedError
36
+
37
+ for a in ci.as_:
38
+ dct.setdefault(ci.module.name, []).append(
39
+ (None, a),
40
+ )
41
+
42
+ for sa, da in ci.attrs:
43
+ dct.setdefault(ci.module.name, []).append(
44
+ (sa, da),
45
+ )
46
+
47
+ else:
48
+ raise NotImplementedError
49
+
50
+ return dct
51
+
52
+
53
+ ##
54
+
55
+
19
56
  def proxy_import(
20
57
  spec: str,
21
58
  package: str | None = None,
@@ -48,7 +85,7 @@ def auto_proxy_import(
48
85
  *,
49
86
  disable: bool = False,
50
87
 
51
- unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
88
+ unreferenced_callback: ta.Callable[[ta.Sequence[str]], None] | None = None,
52
89
  raise_unreferenced: bool = False,
53
90
 
54
91
  _stack_offset: int = 0,
@@ -70,10 +107,9 @@ def auto_proxy_import(
70
107
  ):
71
108
  yield inst
72
109
 
73
- pkg = mod_globals.get('__package__')
74
- for pi in inst.captured.imports:
75
- for sa, ma in pi.attrs:
76
- mod_globals[ma] = proxy_import(pi.spec + (('.' + sa) if sa is not None else ''), pkg)
110
+ for spec, attrs in _translate_old_style_import_capture(inst.captured).items():
111
+ for sa, ma in attrs:
112
+ mod_globals[ma] = proxy_import(spec + (('.' + sa) if sa is not None else ''))
77
113
 
78
114
  return inner()
79
115
 
@@ -87,7 +123,7 @@ class _ProxyInit:
87
123
  package: str
88
124
 
89
125
  class _Import(ta.NamedTuple):
90
- spec: str
126
+ name: str
91
127
  attr: str | None
92
128
 
93
129
  def __init__(
@@ -101,7 +137,6 @@ class _ProxyInit:
101
137
  self._name_package = name_package
102
138
 
103
139
  self._imps_by_attr: dict[str, _ProxyInit._Import] = {}
104
- self._mods_by_spec: dict[str, ta.Any] = {}
105
140
 
106
141
  @property
107
142
  def name_package(self) -> NamePackage:
@@ -109,21 +144,18 @@ class _ProxyInit:
109
144
 
110
145
  def add(
111
146
  self,
112
- package: str,
147
+ name: str,
113
148
  attrs: ta.Iterable[tuple[str | None, str]],
114
149
  ) -> None:
115
150
  for imp_attr, as_attr in attrs:
116
151
  if imp_attr is None:
117
- self._imps_by_attr[as_attr] = self._Import(package, None)
152
+ self._imps_by_attr[as_attr] = self._Import(name, None)
118
153
  self._lazy_globals.set_fn(as_attr, functools.partial(self.get, as_attr))
119
154
 
120
155
  else:
121
- self._imps_by_attr[as_attr] = self._Import(package, imp_attr)
156
+ self._imps_by_attr[as_attr] = self._Import(name, imp_attr)
122
157
  self._lazy_globals.set_fn(as_attr, functools.partial(self.get, as_attr))
123
158
 
124
- def _import_module(self, name: str) -> ta.Any:
125
- return importlib.import_module(name, package=self._name_package.package)
126
-
127
159
  def get(self, attr: str) -> ta.Any:
128
160
  try:
129
161
  imp = self._imps_by_attr[attr]
@@ -133,14 +165,19 @@ class _ProxyInit:
133
165
  val: ta.Any
134
166
 
135
167
  if imp.attr is None:
136
- val = self._import_module(imp.spec)
168
+ val = importlib.import_module(imp.name)
169
+
170
+ elif imp.name == self._name_package.name:
171
+ val = importlib.import_module(f'{imp.name}.{imp.attr}')
137
172
 
138
173
  else:
139
- try:
140
- mod = self._mods_by_spec[imp.spec]
141
- except KeyError:
142
- mod = self._import_module(imp.spec)
143
- self._mods_by_spec[imp.spec] = mod
174
+ mod = __import__(
175
+ imp.name,
176
+ self._lazy_globals._globals, # noqa
177
+ {},
178
+ [imp.attr],
179
+ 0,
180
+ )
144
181
 
145
182
  val = getattr(mod, imp.attr)
146
183
 
@@ -152,6 +189,13 @@ def proxy_init(
152
189
  spec: str,
153
190
  attrs: ta.Iterable[str | tuple[str | None, str | None] | None] | None = None,
154
191
  ) -> None:
192
+ name = importlib.util.resolve_name(
193
+ spec,
194
+ package=init_globals['__package__'] if spec.startswith('.') else None,
195
+ )
196
+
197
+ #
198
+
155
199
  if isinstance(attrs, str):
156
200
  raise TypeError(attrs)
157
201
 
@@ -201,7 +245,7 @@ def proxy_init(
201
245
  if pi.name_package != init_name_package:
202
246
  raise Exception(f'Wrong init name: {pi.name_package=} != {init_name_package=}')
203
247
 
204
- pi.add(spec, al)
248
+ pi.add(name, al)
205
249
 
206
250
 
207
251
  #
@@ -213,7 +257,7 @@ def auto_proxy_init(
213
257
  disable: bool = False,
214
258
  eager: bool = False,
215
259
 
216
- unreferenced_callback: ta.Callable[[ta.Mapping[str, ta.Sequence[str | None]]], None] | None = None,
260
+ unreferenced_callback: ta.Callable[[ta.Sequence[str]], None] | None = None,
217
261
  raise_unreferenced: bool = False,
218
262
 
219
263
  update_exports: bool = False,
@@ -237,11 +281,11 @@ def auto_proxy_init(
237
281
  ):
238
282
  yield inst
239
283
 
240
- for pi in inst.captured.imports:
284
+ for spec, attrs in _translate_old_style_import_capture(inst.captured).items():
241
285
  proxy_init(
242
286
  init_globals,
243
- pi.spec,
244
- pi.attrs,
287
+ spec,
288
+ attrs,
245
289
  )
246
290
 
247
291
  if eager:
omlish/term/confirm.py CHANGED
@@ -15,7 +15,7 @@ def confirm_action(
15
15
  stdin = sys.stdin
16
16
  if not stdin.isatty():
17
17
  raise OSError(f'stdin {stdin!r} is not a tty')
18
- # FIXME: we want to make sure we only run on a tty, but we als want input()'s readline goodies..
18
+ # FIXME: we want to make sure we only run on a tty, but we also want input()'s readline goodies..
19
19
  if stdin is not sys.stdin:
20
20
  raise RuntimeError('Unsupported stdin')
21
21
 
@@ -24,15 +24,15 @@ def confirm_action(
24
24
  if not stdout.isatty():
25
25
  raise OSError(f'stdout {stdout!r} is not a tty')
26
26
 
27
- while True:
28
- if message and not message[-1].isspace():
29
- if '\n' in message:
30
- prefix = message + '\n\n'
31
- else:
32
- prefix = message + ' '
27
+ if message:
28
+ if '\n' in message:
29
+ prefix = message + '\n\n'
33
30
  else:
34
- prefix = ''
31
+ prefix = message + ' '
32
+ else:
33
+ prefix = ''
35
34
 
35
+ while True:
36
36
  c = input(f'{prefix}(y/n): ').lower().strip()
37
37
 
38
38
  if c == 'y':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev457
3
+ Version: 0.0.0.dev459
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -34,7 +34,7 @@ Requires-Dist: cbor2~=5.7; extra == "all"
34
34
  Requires-Dist: cloudpickle~=3.1; extra == "all"
35
35
  Requires-Dist: httpx[http2]~=0.28; extra == "all"
36
36
  Requires-Dist: wrapt~=1.17; extra == "all"
37
- Requires-Dist: cryptography~=45.0; extra == "all"
37
+ Requires-Dist: cryptography~=46.0; extra == "all"
38
38
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "all"
39
39
  Requires-Dist: pg8000~=1.31; extra == "all"
40
40
  Requires-Dist: pymysql~=1.1; extra == "all"
@@ -80,7 +80,7 @@ Requires-Dist: httpx[http2]~=0.28; extra == "http"
80
80
  Provides-Extra: misc
81
81
  Requires-Dist: wrapt~=1.17; extra == "misc"
82
82
  Provides-Extra: secrets
83
- Requires-Dist: cryptography~=45.0; extra == "secrets"
83
+ Requires-Dist: cryptography~=46.0; extra == "secrets"
84
84
  Provides-Extra: sqlalchemy
85
85
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "sqlalchemy"
86
86
  Provides-Extra: sqldrivers
@@ -1,5 +1,5 @@
1
1
  omlish/.omlish-manifests.json,sha256=FLw7xkPiSXuImZgqSP8BwrEib2R1doSzUPLUkc-QUIA,8410
2
- omlish/__about__.py,sha256=7wUq7VUXvYMZngckEy8GopODX5t4PieoLpMrovKdKsI,3613
2
+ omlish/__about__.py,sha256=xtL6Mzn2wu2_IspeSZ_MxiJmXyGvptjs7xRjcNyq79E,3613
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ZNIMl1kwg3qdei4DiUrJPQe5M81S1e76N-GuNSwLBAE,8683
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -205,7 +205,7 @@ omlish/diag/procfs.py,sha256=eeB3L9UpNBpAfsax3U6OczayYboPlFzOGplqlQ4gBNY,9700
205
205
  omlish/diag/procstats.py,sha256=EJEe2Zc58ykBoTfqMXro7H52aQa_pd6uC2hsIPFceso,825
206
206
  omlish/diag/ps.py,sha256=MEpMU6fbkh0bSWrOHh_okOa0JDTUSUQUVSYBdh1TGvE,1672
207
207
  omlish/diag/pycharm.py,sha256=_WVmPm1E66cBtR4ukgUAaApe_3rX9Cv3sQRP5PL37P8,5013
208
- omlish/diag/pydevd.py,sha256=P8izkeCEJWXFLqOWS6X8qUH3rlcfhiE07ZJOPGa5xYU,8203
208
+ omlish/diag/pydevd.py,sha256=JEHC0hiSJxL-vVtuxKUi1BNkgUKnRC1N4alDg6JP5WQ,8363
209
209
  omlish/diag/threads.py,sha256=sjtlTl41wxssoVCDkBB6xeLF-9kJEK3eA6hmSFWJSQA,3643
210
210
  omlish/diag/timers.py,sha256=cxX3GgjTIjBx9DI4pzCCO5Hfqb1TM3uo22yim7kjfRU,3831
211
211
  omlish/diag/_pycharm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -451,11 +451,11 @@ omlish/lang/classes/restrict.py,sha256=xHLIK20MQ_jJPQ7JVzMNhyN4Xc4eLBgrcxqDnTbeK
451
451
  omlish/lang/classes/simple.py,sha256=3AJSs-plVg2flq4SC6I39LxP0nBaB241puv3D5YCP5I,2973
452
452
  omlish/lang/classes/virtual.py,sha256=J4y-uiv1RaP2rfFeptXqQ1a4MRek0TMlAFFraO_lzhs,3397
453
453
  omlish/lang/imports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
454
- omlish/lang/imports/_capture.cc,sha256=jAKW9pOV3ER4Vzd-aywmAeOxbv-b_jNdaxAaVdxfueg,2261
455
- omlish/lang/imports/capture.py,sha256=wjWuXDUYYHUZ78t_OxVzi27PshBOlhpSoglg7H67zXA,21890
454
+ omlish/lang/imports/_capture.cc,sha256=cp-L5yFGjftfBa12sKNz0Q5Yhh54a88DH7VEN1oa5hU,2313
455
+ omlish/lang/imports/capture.py,sha256=z91F2CVcBDX4trhd2oRB5YL_d_Nu9KBTjzhy98N9YDQ,26170
456
456
  omlish/lang/imports/conditional.py,sha256=R-E47QD95mMonPImWlrde3rnJrFKCCkYz71c94W05sc,1006
457
457
  omlish/lang/imports/lazy.py,sha256=Eefs9hkj5surMdwgxX_Q3BOqPcox10v0sKT5rKIQknc,808
458
- omlish/lang/imports/proxy.py,sha256=wlXJrl1GiXQ-t5cO_aJLqp1mr_Erl4oMk4uySkkK7bg,6516
458
+ omlish/lang/imports/proxy.py,sha256=tIIChKvl5TCZp_vg6D7WR7NxnN0J-L-bqjp0DYvgUuA,7562
459
459
  omlish/lang/imports/resolving.py,sha256=DeRarn35Fryg5JhVhy8wbiC9lvr58AnllI9B_reswUE,2085
460
460
  omlish/lang/imports/traversal.py,sha256=pbFQIa880NGjSfcLsno2vE_G41_CLwDHb-7gWg2J3BI,2855
461
461
  omlish/lifecycles/__init__.py,sha256=zOuvV4pErPwxcKUSgshmME2Duw9GrjwckpNmW3FPKng,810
@@ -758,7 +758,7 @@ omlish/subprocesses/wrap.py,sha256=AhGV8rsnaVUMQCFYKkrjj35fs3O-VJLZC1hZ14dz3C8,7
758
758
  omlish/term/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
759
759
  omlish/term/codes.py,sha256=6_g4wwXP4z9koC9oEW3jSEuw27mQRf43ngD5RA-Qu2s,6390
760
760
  omlish/term/coloring.py,sha256=5lV7E2fyFDixAfm4tM5MFV9vreW5RM94AgUHB9hKaVE,2598
761
- omlish/term/confirm.py,sha256=M3DAyyPO2yREhSXOAWF-KQcLTHRRZCVsg2nrIKT8kHI,1111
761
+ omlish/term/confirm.py,sha256=0Qoo-MFBWw26khMMHv92tFXFHNB9GOubfdPLi48KkkY,1054
762
762
  omlish/term/progressbar.py,sha256=nCnTX1dUNCGle9FzzeTBuoxQaellErOQkyBsKVrGG1I,3679
763
763
  omlish/term/vt100/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
764
764
  omlish/term/vt100/c.py,sha256=93HARU6Dd1rVF-n8cAyXqkEqleYLcofuLgSUNd6-GbU,3537
@@ -826,9 +826,9 @@ omlish/typedvalues/marshal.py,sha256=2xqX6JllhtGpmeYkU7C-qzgU__0x-vd6CzYbAsocQlc
826
826
  omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
827
827
  omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
828
828
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
829
- omlish-0.0.0.dev457.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
830
- omlish-0.0.0.dev457.dist-info/METADATA,sha256=h9XOPiW_Qp1WAj_ufmcGrj-r6mDLA89_nNzZJPP52W8,19003
831
- omlish-0.0.0.dev457.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
832
- omlish-0.0.0.dev457.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
833
- omlish-0.0.0.dev457.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
834
- omlish-0.0.0.dev457.dist-info/RECORD,,
829
+ omlish-0.0.0.dev459.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
830
+ omlish-0.0.0.dev459.dist-info/METADATA,sha256=vA7Ker_93at2wRMI8zaoBhaoAnE8BmZqvBEDDGy9gEg,19003
831
+ omlish-0.0.0.dev459.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
832
+ omlish-0.0.0.dev459.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
833
+ omlish-0.0.0.dev459.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
834
+ omlish-0.0.0.dev459.dist-info/RECORD,,