omlish 0.0.0.dev212__py3-none-any.whl → 0.0.0.dev213__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.dev212'
2
- __revision__ = 'bd253a140a7f57dc37a30f1a4f0b227123281988'
1
+ __version__ = '0.0.0.dev213'
2
+ __revision__ = '03c9d6a7f92cec54535af989bf531b8598a896c0'
3
3
 
4
4
 
5
5
  #
@@ -0,0 +1 @@
1
+ # @omlish-lite
@@ -0,0 +1,242 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import io
3
+ import typing as ta
4
+
5
+ from .proxy import AsyncIoProxy
6
+ from .proxy import _register_async_io_proxy_cls
7
+
8
+
9
+ SelfT = ta.TypeVar('SelfT')
10
+
11
+
12
+ ##
13
+
14
+
15
+ @_register_async_io_proxy_cls
16
+ class IOBaseAsyncIoProxy(AsyncIoProxy, proxied_cls=io.IOBase):
17
+ # https://github.com/python/cpython/blob/e65a1eb93ae35f9fbab1508606e3fbc89123629f/Lib/_pyio.py#L305
18
+
19
+ ##
20
+ # Positioning
21
+
22
+ async def seek(self, pos, whence=0):
23
+ raise TypeError
24
+
25
+ async def tell(self):
26
+ raise TypeError
27
+
28
+ async def truncate(self, pos=None):
29
+ raise TypeError
30
+
31
+ ##
32
+ # Flush and close
33
+
34
+ async def flush(self):
35
+ raise TypeError
36
+
37
+ async def close(self):
38
+ raise TypeError
39
+
40
+ ##
41
+ # Inquiries
42
+
43
+ def seekable(self):
44
+ raise TypeError
45
+
46
+ def readable(self):
47
+ raise TypeError
48
+
49
+ def writable(self):
50
+ raise TypeError
51
+
52
+ @property
53
+ def closed(self):
54
+ raise TypeError
55
+
56
+ ##
57
+ # Context manager
58
+
59
+ async def __aenter__(self: SelfT) -> SelfT:
60
+ raise TypeError
61
+
62
+ async def __aexit__(self, exc_type, exc_value, exc_tb):
63
+ raise TypeError
64
+
65
+ ##
66
+ # Lower-level APIs
67
+
68
+ def fileno(self):
69
+ raise TypeError
70
+
71
+ def isatty(self):
72
+ raise TypeError
73
+
74
+ ##
75
+ # Readline[s] and writelines
76
+
77
+ async def readline(self, size=-1):
78
+ raise TypeError
79
+
80
+ # def __iter__(self):
81
+ # raise TypeError
82
+
83
+ # def __next__(self):
84
+ # raise TypeError
85
+
86
+ async def readlines(self, hint=None):
87
+ raise TypeError
88
+
89
+ async def writelines(self, lines):
90
+ raise TypeError
91
+
92
+
93
+ @_register_async_io_proxy_cls
94
+ class RawIOBaseAsyncIoProxy(IOBaseAsyncIoProxy, proxied_cls=io.RawIOBase):
95
+ async def read(self, size=-1):
96
+ raise TypeError
97
+
98
+ async def readall(self):
99
+ raise TypeError
100
+
101
+ async def readinto(self, b):
102
+ raise TypeError
103
+
104
+ async def write(self, b):
105
+ raise TypeError
106
+
107
+
108
+ @_register_async_io_proxy_cls
109
+ class BufferedIOBaseAsyncIoProxy(IOBaseAsyncIoProxy, proxied_cls=io.BufferedIOBase):
110
+ async def read(self, size=-1):
111
+ raise TypeError
112
+
113
+ async def read1(self, size=-1):
114
+ raise TypeError
115
+
116
+ async def readinto(self, b):
117
+ raise TypeError
118
+
119
+ async def readinto1(self, b):
120
+ raise TypeError
121
+
122
+ async def write(self, b):
123
+ raise TypeError
124
+
125
+ async def detach(self):
126
+ raise TypeError
127
+
128
+
129
+ class BufferedIOMixinAsyncIoProxy(BufferedIOBaseAsyncIoProxy):
130
+ @property
131
+ def raw(self):
132
+ raise TypeError
133
+
134
+ @property
135
+ def name(self):
136
+ raise TypeError
137
+
138
+ @property
139
+ def mode(self):
140
+ raise TypeError
141
+
142
+
143
+ @_register_async_io_proxy_cls
144
+ class BytesIOAsyncIoProxy(BufferedIOBaseAsyncIoProxy, proxied_cls=io.BytesIO):
145
+ async def getvalue(self):
146
+ raise TypeError
147
+
148
+ async def getbuffer(self):
149
+ raise TypeError
150
+
151
+
152
+ @_register_async_io_proxy_cls
153
+ class BufferedReaderAsyncIoProxy(BufferedIOMixinAsyncIoProxy, proxied_cls=io.BufferedReader):
154
+ async def peek(self, size=0):
155
+ raise TypeError
156
+
157
+
158
+ @_register_async_io_proxy_cls
159
+ class BufferedWriterAsyncIoProxy(BufferedIOMixinAsyncIoProxy, proxied_cls=io.BufferedWriter):
160
+ pass
161
+
162
+
163
+ @_register_async_io_proxy_cls
164
+ class BufferedRWPairAsyncIoProxy(BufferedIOBaseAsyncIoProxy, proxied_cls=io.BufferedRWPair):
165
+ async def peek(self, size=0):
166
+ raise TypeError
167
+
168
+
169
+ @_register_async_io_proxy_cls
170
+ class BufferedRandomAsyncIoProxy(BufferedWriterAsyncIoProxy, BufferedReaderAsyncIoProxy, proxied_cls=io.BufferedRandom):
171
+ pass
172
+
173
+
174
+ @_register_async_io_proxy_cls
175
+ class FileIOAsyncIoProxy(RawIOBaseAsyncIoProxy, proxied_cls=io.FileIO):
176
+ @property
177
+ def closefd(self):
178
+ raise TypeError
179
+
180
+ @property
181
+ def mode(self):
182
+ raise TypeError
183
+
184
+
185
+ @_register_async_io_proxy_cls
186
+ class TextIOBaseAsyncIoProxy(IOBaseAsyncIoProxy, proxied_cls=io.TextIOBase):
187
+ async def read(self, size=-1):
188
+ raise TypeError
189
+
190
+ async def write(self, s):
191
+ raise TypeError
192
+
193
+ async def detach(self):
194
+ raise TypeError
195
+
196
+ @property
197
+ def encoding(self):
198
+ raise TypeError
199
+
200
+ @property
201
+ def newlines(self):
202
+ raise TypeError
203
+
204
+ @property
205
+ def errors(self):
206
+ raise TypeError
207
+
208
+
209
+ @_register_async_io_proxy_cls
210
+ class TextIOWrapperAsyncIoProxy(TextIOBaseAsyncIoProxy, proxied_cls=io.TextIOWrapper):
211
+ @property
212
+ def line_buffering(self):
213
+ raise TypeError
214
+
215
+ @property
216
+ def write_through(self):
217
+ raise TypeError
218
+
219
+ @property
220
+ def buffer(self):
221
+ raise TypeError
222
+
223
+ async def reconfigure(
224
+ self,
225
+ *,
226
+ encoding=None,
227
+ errors=None,
228
+ newline=Ellipsis,
229
+ line_buffering=None,
230
+ write_through=None,
231
+ ):
232
+ raise TypeError
233
+
234
+ @property
235
+ def name(self):
236
+ raise TypeError
237
+
238
+
239
+ @_register_async_io_proxy_cls
240
+ class StringIOAsyncIoProxy(TextIOWrapperAsyncIoProxy, proxied_cls=io.StringIO):
241
+ async def getvalue(self):
242
+ raise TypeError
@@ -0,0 +1,154 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import io
3
+ import types
4
+ import typing as ta
5
+
6
+ from .io import BufferedIOBaseAsyncIoProxy
7
+ from .io import BufferedRandomAsyncIoProxy
8
+ from .io import BufferedReaderAsyncIoProxy
9
+ from .io import BufferedRWPairAsyncIoProxy
10
+ from .io import BufferedWriterAsyncIoProxy
11
+ from .io import BytesIOAsyncIoProxy
12
+ from .io import FileIOAsyncIoProxy
13
+ from .io import IOBaseAsyncIoProxy
14
+ from .io import RawIOBaseAsyncIoProxy
15
+ from .io import StringIOAsyncIoProxy
16
+ from .io import TextIOBaseAsyncIoProxy
17
+ from .io import TextIOWrapperAsyncIoProxy
18
+ from .proxy import AsyncIoProxyRunner
19
+ from .proxy import AsyncIoProxyTarget
20
+ from .proxy import async_io_proxy_cls_for
21
+ from .proxy import async_io_proxy_fn
22
+ from .typing import TypingBinaryIOAsyncIoProxy
23
+ from .typing import TypingIOAsyncIoProxy
24
+ from .typing import TypingTextIOAsyncIoProxy
25
+
26
+
27
+ ##
28
+
29
+
30
+ @ta.final
31
+ class AsyncIoProxier:
32
+ def __init__(self, runner_policy: ta.Callable[[ta.Any], AsyncIoProxyRunner]) -> None:
33
+ super().__init__()
34
+
35
+ self._runner_policy = runner_policy
36
+
37
+ def get_runner(self, obj: ta.Any) -> AsyncIoProxyRunner:
38
+ return self._runner_policy(obj)
39
+
40
+ ##
41
+
42
+ def target_obj(self, obj: ta.Any) -> AsyncIoProxyTarget:
43
+ runner = self.get_runner(obj)
44
+ return AsyncIoProxyTarget(obj, runner)
45
+
46
+ def proxy_obj_with_cls(self, obj, proxy_cls):
47
+ target = self.target_obj(obj)
48
+ proxy = proxy_cls(target)
49
+ return proxy
50
+
51
+ def maybe_proxy_obj(self, obj):
52
+ if (proxy_cls := async_io_proxy_cls_for(obj)) is None:
53
+ return obj
54
+ return self.proxy_obj_with_cls(obj, proxy_cls)
55
+
56
+ ##
57
+
58
+ @ta.overload
59
+ def proxy_obj(self, obj: io.StringIO) -> StringIOAsyncIoProxy: # type: ignore[overload-overlap] # 1
60
+ ...
61
+
62
+ @ta.overload
63
+ def proxy_obj(self, obj: io.TextIOWrapper) -> TextIOWrapperAsyncIoProxy: # type: ignore[overload-overlap] # 2
64
+ ...
65
+
66
+ @ta.overload
67
+ def proxy_obj(self, obj: io.TextIOBase) -> TextIOBaseAsyncIoProxy: # 3
68
+ ...
69
+
70
+ @ta.overload
71
+ def proxy_obj(self, obj: io.FileIO) -> FileIOAsyncIoProxy: # type: ignore[overload-overlap] # 4
72
+ ...
73
+
74
+ @ta.overload
75
+ def proxy_obj(self, obj: io.BufferedRandom) -> BufferedRandomAsyncIoProxy: # type: ignore[overload-overlap] # 5
76
+ ...
77
+
78
+ @ta.overload
79
+ def proxy_obj(self, obj: io.BufferedRWPair) -> BufferedRWPairAsyncIoProxy: # 6
80
+ ...
81
+
82
+ @ta.overload
83
+ def proxy_obj(self, obj: io.BufferedWriter) -> BufferedWriterAsyncIoProxy: # type: ignore[overload-overlap] # 7
84
+ ...
85
+
86
+ @ta.overload
87
+ def proxy_obj(self, obj: io.BufferedReader) -> BufferedReaderAsyncIoProxy: # type: ignore[overload-overlap] # 8
88
+ ...
89
+
90
+ @ta.overload
91
+ def proxy_obj(self, obj: io.BytesIO) -> BytesIOAsyncIoProxy: # type: ignore[overload-overlap] # 9
92
+ ...
93
+
94
+ @ta.overload
95
+ def proxy_obj(self, obj: io.BufferedIOBase) -> BufferedIOBaseAsyncIoProxy: # 10
96
+ ...
97
+
98
+ @ta.overload
99
+ def proxy_obj(self, obj: io.RawIOBase) -> RawIOBaseAsyncIoProxy: # 11
100
+ ...
101
+
102
+ @ta.overload
103
+ def proxy_obj(self, obj: io.IOBase) -> IOBaseAsyncIoProxy: # 12
104
+ ...
105
+
106
+ #
107
+
108
+ @ta.overload
109
+ def proxy_obj(self, obj: ta.TextIO) -> TypingTextIOAsyncIoProxy: # 13
110
+ ...
111
+
112
+ @ta.overload
113
+ def proxy_obj(self, obj: ta.BinaryIO) -> TypingBinaryIOAsyncIoProxy: # 14
114
+ ...
115
+
116
+ @ta.overload
117
+ def proxy_obj(self, obj: ta.IO) -> TypingIOAsyncIoProxy: # 15
118
+ ...
119
+
120
+ #
121
+
122
+ def proxy_obj(self, obj):
123
+ if (proxy_cls := async_io_proxy_cls_for(obj)) is None:
124
+ raise TypeError(obj)
125
+ return self.proxy_obj_with_cls(obj, proxy_cls)
126
+
127
+ ##
128
+
129
+ def proxy_fn(self, fn, *, wrap_result='auto'):
130
+ if wrap_result == 'auto':
131
+ result_wrapper = self.maybe_proxy_obj
132
+ elif wrap_result is True:
133
+ result_wrapper = self.proxy_obj
134
+ elif wrap_result is False:
135
+ result_wrapper = None
136
+ else:
137
+ raise TypeError(wrap_result)
138
+ runner = self.get_runner(fn)
139
+ return async_io_proxy_fn(fn, runner, result_wrapper=result_wrapper)
140
+
141
+ ##
142
+
143
+ FN_TYPES: ta.Tuple[type, ...] = (
144
+ types.BuiltinFunctionType,
145
+ types.BuiltinMethodType,
146
+ types.FunctionType,
147
+ types.MethodType,
148
+ )
149
+
150
+ def proxy(self, obj):
151
+ if isinstance(obj, self.FN_TYPES):
152
+ return self.proxy_fn(obj)
153
+ else:
154
+ return self.proxy_obj(obj)
@@ -0,0 +1,141 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import functools
4
+ import inspect
5
+ import typing as ta
6
+
7
+ from ...lite.check import check
8
+
9
+
10
+ AsyncIoProxyRunner = ta.Callable[[ta.Callable], ta.Awaitable] # ta.TypeAlias
11
+
12
+
13
+ ##
14
+
15
+
16
+ _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS = ('__name__', '__qualname__')
17
+ _ASYNC_IO_PROXY_WRAPPER_ASSIGNMENTS = tuple(
18
+ a
19
+ for a in functools.WRAPPER_ASSIGNMENTS
20
+ if a not in _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS
21
+ )
22
+
23
+
24
+ def async_io_proxy_fn(fn, runner, *, result_wrapper=None):
25
+ @functools.wraps(fn, assigned=_ASYNC_IO_PROXY_WRAPPER_ASSIGNMENTS)
26
+ async def run(*args, **kwargs):
27
+ ret = await runner(functools.partial(fn, *args, **kwargs))
28
+ if result_wrapper is not None:
29
+ ret = result_wrapper(ret)
30
+ return ret
31
+
32
+ for na in _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS:
33
+ setattr(run, na, f'{getattr(run, na)}:{getattr(fn, na)}')
34
+
35
+ return run
36
+
37
+
38
+ ##
39
+
40
+
41
+ @dc.dataclass(frozen=True)
42
+ class AsyncIoProxyTarget:
43
+ obj: ta.Any
44
+ runner: AsyncIoProxyRunner
45
+
46
+
47
+ class AsyncIoProxy:
48
+ def __init__(self, target: AsyncIoProxyTarget) -> None:
49
+ super().__init__()
50
+
51
+ self._target = check.isinstance(target, AsyncIoProxyTarget)
52
+
53
+ #
54
+
55
+ class _Descriptor:
56
+ def __init__(self, name) -> None:
57
+ super().__init__()
58
+
59
+ self._name = name
60
+
61
+ def __get__(self, instance, owner=None):
62
+ if instance is None:
63
+ return self
64
+
65
+ target: AsyncIoProxyTarget = instance._target # noqa
66
+ v = self._get(target, instance)
67
+
68
+ setattr(instance, self._name, v)
69
+ return v
70
+
71
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
72
+ raise NotImplementedError
73
+
74
+ class _Property(_Descriptor):
75
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
76
+ return getattr(target.obj, self._name)
77
+
78
+ class _Method(_Descriptor):
79
+ def __call__(self, instance, *args, **kwargs):
80
+ return self.__get__(instance)(*args, **kwargs)
81
+
82
+ class _SyncMethod(_Method):
83
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
84
+ return getattr(target.obj, self._name)
85
+
86
+ class _AsyncMethod(_Method):
87
+ SPECIAL_METHOD_NAMES: ta.ClassVar[ta.Mapping[str, str]] = {
88
+ '__aenter__': '__enter__',
89
+ '__aexit__': '__exit__',
90
+ }
91
+
92
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
93
+ fa = self.SPECIAL_METHOD_NAMES.get(self._name, self._name)
94
+ fn = getattr(target.obj, fa)
95
+ if fa == '__enter__':
96
+ result_wrapper = lambda _: instance
97
+ else:
98
+ result_wrapper = None
99
+ run = async_io_proxy_fn(fn, target.runner, result_wrapper=result_wrapper)
100
+ return run
101
+
102
+ #
103
+
104
+ __proxied_cls__: ta.ClassVar[type]
105
+
106
+ def __init_subclass__(cls, *, proxied_cls=None, **kwargs): # noqa
107
+ super().__init_subclass__()
108
+
109
+ cls.__proxied_cls__ = check.isinstance(proxied_cls, (type, None))
110
+
111
+ for n, v in dict(cls.__dict__).items():
112
+ if n.startswith('_') and n not in cls._AsyncMethod.SPECIAL_METHOD_NAMES:
113
+ continue
114
+
115
+ if isinstance(v, property):
116
+ setattr(cls, n, cls._Property(n))
117
+
118
+ elif callable(v):
119
+ if inspect.iscoroutinefunction(v):
120
+ setattr(cls, n, cls._AsyncMethod(n))
121
+ else:
122
+ setattr(cls, n, cls._SyncMethod(n))
123
+
124
+ else:
125
+ raise TypeError(v)
126
+
127
+
128
+ ##
129
+
130
+
131
+ @functools.singledispatch
132
+ def async_io_proxy_cls_for(obj: ta.Any) -> ta.Optional[ta.Type[AsyncIoProxy]]:
133
+ return None
134
+
135
+
136
+ def _register_async_io_proxy_cls(cls):
137
+ async_io_proxy_cls_for.register(
138
+ check.isinstance(cls.__dict__['__proxied_cls__'], type),
139
+ lambda obj: cls,
140
+ )
141
+ return cls
@@ -0,0 +1,108 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import typing as ta
3
+
4
+ from .proxy import AsyncIoProxy
5
+ from .proxy import _register_async_io_proxy_cls
6
+
7
+
8
+ SelfT = ta.TypeVar('SelfT')
9
+
10
+ AnyStrT = ta.TypeVar('AnyStrT', bytes, str)
11
+
12
+
13
+ ##
14
+
15
+
16
+ @_register_async_io_proxy_cls
17
+ class TypingIOAsyncIoProxy(AsyncIoProxy, ta.Generic[AnyStrT], proxied_cls=ta.IO):
18
+ @property
19
+ def mode(self) -> str:
20
+ raise TypeError
21
+
22
+ @property
23
+ def name(self) -> str:
24
+ raise TypeError
25
+
26
+ async def close(self) -> None:
27
+ raise TypeError
28
+
29
+ @property
30
+ def closed(self) -> bool:
31
+ raise TypeError
32
+
33
+ def fileno(self) -> int:
34
+ raise TypeError
35
+
36
+ async def flush(self) -> None:
37
+ raise TypeError
38
+
39
+ def isatty(self) -> bool:
40
+ raise TypeError
41
+
42
+ async def read(self, n: int = -1) -> AnyStrT:
43
+ raise TypeError
44
+
45
+ def readable(self) -> bool:
46
+ raise TypeError
47
+
48
+ async def readline(self, limit: int = -1) -> AnyStrT:
49
+ raise TypeError
50
+
51
+ async def readlines(self, hint: int = -1) -> ta.List[AnyStrT]:
52
+ raise TypeError
53
+
54
+ async def seek(self, offset: int, whence: int = 0) -> int:
55
+ raise TypeError
56
+
57
+ def seekable(self) -> bool:
58
+ raise TypeError
59
+
60
+ async def tell(self) -> int:
61
+ raise TypeError
62
+
63
+ async def truncate(self, size: ta.Optional[int] = None) -> int:
64
+ raise TypeError
65
+
66
+ def writable(self) -> bool:
67
+ raise TypeError
68
+
69
+ async def write(self, s: AnyStrT) -> int:
70
+ raise TypeError
71
+
72
+ async def writelines(self, lines: ta.List[AnyStrT]) -> None:
73
+ raise TypeError
74
+
75
+ async def __aenter__(self: SelfT) -> SelfT:
76
+ raise TypeError
77
+
78
+ async def __aexit__(self, exc_type, exc_value, exc_tb):
79
+ raise TypeError
80
+
81
+
82
+ @_register_async_io_proxy_cls
83
+ class TypingBinaryIOAsyncIoProxy(TypingIOAsyncIoProxy[bytes], proxied_cls=ta.BinaryIO):
84
+ def write(self, s: ta.Union[bytes, bytearray]) -> int: # type: ignore[override]
85
+ raise TypeError
86
+
87
+
88
+ @_register_async_io_proxy_cls
89
+ class TypingTextIOAsyncIoProxy(TypingIOAsyncIoProxy[str], proxied_cls=ta.TextIO):
90
+ # @property
91
+ # def buffer(self) -> BinaryIO:
92
+ # pass
93
+
94
+ @property
95
+ def encoding(self) -> str:
96
+ raise TypeError
97
+
98
+ @property
99
+ def errors(self) -> ta.Optional[str]:
100
+ raise TypeError
101
+
102
+ @property
103
+ def line_buffering(self) -> bool:
104
+ raise TypeError
105
+
106
+ @property
107
+ def newlines(self) -> ta.Any:
108
+ raise TypeError
omlish/check.py CHANGED
@@ -85,6 +85,7 @@ not_none = check.not_none
85
85
  #
86
86
 
87
87
  equal = check.equal
88
+ not_equal = check.not_equal
88
89
  is_ = check.is_
89
90
  is_not = check.is_not
90
91
  callable = check.callable # noqa
@@ -29,8 +29,16 @@ class MatchingConfigRewriter(ConfigRewriter):
29
29
  self._paths = frozenset(check.isinstance(p, tuple) for p in paths)
30
30
  self._recurse = recurse
31
31
 
32
+ def match_path(self, path: ConfigRewriterPath) -> bool:
33
+ for test in self._paths:
34
+ if len(test) != len(path):
35
+ continue
36
+ if all(t is None or p == t for p, t in zip(path, test)):
37
+ return True
38
+ return False
39
+
32
40
  def rewrite(self, ctx: ConfigRewriter.Context[T]) -> T:
33
- if ctx.path in self._paths:
41
+ if self.match_path(ctx.path):
34
42
  no = self._fn(ctx.obj)
35
43
  if not self._recurse:
36
44
  return no
omlish/io/abc.py CHANGED
@@ -1,5 +1,6 @@
1
1
  # ruff: noqa: ANN204
2
2
 
3
+
3
4
  class IOBase:
4
5
  def seek(self, pos, whence=0): ...
5
6
 
omlish/lite/check.py CHANGED
@@ -49,6 +49,17 @@ class Checks:
49
49
 
50
50
  #
51
51
 
52
+ def register_on_raise_breakpoint_if_env_var_set(self, key: str) -> None:
53
+ import os
54
+
55
+ def on_raise(exc: Exception) -> None: # noqa
56
+ if key in os.environ:
57
+ breakpoint() # noqa
58
+
59
+ self.register_on_raise(on_raise)
60
+
61
+ #
62
+
52
63
  def set_exception_factory(self, factory: CheckExceptionFactory) -> None:
53
64
  self._exception_factory = factory
54
65
 
@@ -364,6 +375,18 @@ class Checks:
364
375
 
365
376
  return v
366
377
 
378
+ def not_equal(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
379
+ if o == v:
380
+ self._raise(
381
+ ValueError,
382
+ 'Must not be equal',
383
+ msg,
384
+ Checks._ArgsKwargs(v, o),
385
+ render_fmt='%s == %s',
386
+ )
387
+
388
+ return v
389
+
367
390
  def is_(self, v: T, o: ta.Any, msg: CheckMessage = None) -> T:
368
391
  if o is not v:
369
392
  self._raise(
@@ -7,6 +7,7 @@ from .check import check
7
7
 
8
8
  T = ta.TypeVar('T')
9
9
  ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
10
+ AsyncExitStackedT = ta.TypeVar('AsyncExitStackedT', bound='AsyncExitStacked')
10
11
 
11
12
 
12
13
  ##
@@ -35,6 +36,33 @@ class ExitStacked:
35
36
  return es.enter_context(cm)
36
37
 
37
38
 
39
+ class AsyncExitStacked:
40
+ _exit_stack: ta.Optional[contextlib.AsyncExitStack] = None
41
+
42
+ async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
43
+ check.state(self._exit_stack is None)
44
+ es = self._exit_stack = contextlib.AsyncExitStack()
45
+ await es.__aenter__()
46
+ return self
47
+
48
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
49
+ if (es := self._exit_stack) is None:
50
+ return None
51
+ await self._async_exit_contexts()
52
+ return await es.__aexit__(exc_type, exc_val, exc_tb)
53
+
54
+ async def _async_exit_contexts(self) -> None:
55
+ pass
56
+
57
+ def _enter_context(self, cm: ta.ContextManager[T]) -> T:
58
+ es = check.not_none(self._exit_stack)
59
+ return es.enter_context(cm)
60
+
61
+ async def _enter_async_context(self, cm: ta.AsyncContextManager[T]) -> T:
62
+ es = check.not_none(self._exit_stack)
63
+ return await es.enter_async_context(cm)
64
+
65
+
38
66
  ##
39
67
 
40
68
 
@@ -46,6 +74,17 @@ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
46
74
  fn()
47
75
 
48
76
 
77
+ @contextlib.asynccontextmanager
78
+ async def adefer(fn: ta.Callable) -> ta.AsyncGenerator[ta.Callable, None]:
79
+ try:
80
+ yield fn
81
+ finally:
82
+ await fn()
83
+
84
+
85
+ ##
86
+
87
+
49
88
  @contextlib.contextmanager
50
89
  def attr_setting(obj, attr, val, *, default=None): # noqa
51
90
  not_set = object()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev212
3
+ Version: 0.0.0.dev213
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,9 +1,9 @@
1
1
  omlish/.manifests.json,sha256=dyIpveH7Z8OnQp2pTn6NVv7LCDXVrozJWAzbk8PBavg,7950
2
- omlish/__about__.py,sha256=EVqT_pFn9H9Ehs4S5FdbIXxCF65SGUz2Q7kpn0C25PE,3409
2
+ omlish/__about__.py,sha256=rTnrIQNQ5FRbHCr1olR3EzpCFMG4gqKht36KMpz3fPk,3409
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
5
5
  omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
6
- omlish/check.py,sha256=RzMJhp8_dDnpHXnPiHDyZTW13KGDTopeuMgpwKCowPs,1988
6
+ omlish/check.py,sha256=THqm6jD1a0skAO5EC8SOVg58yq96Vk5wcuruBkCYxyU,2016
7
7
  omlish/datetimes.py,sha256=HajeM1kBvwlTa-uR1TTZHmZ3zTPnnUr1uGGQhiO1XQ0,2152
8
8
  omlish/defs.py,sha256=9uUjJuVIbCBL3g14fyzAp-9gH935MFofvlfOGwcBIaM,4913
9
9
  omlish/dynamic.py,sha256=35C_cCX_Vq2HrHzGk5T-zbrMvmUdiIiwDzDNixczoDo,6541
@@ -108,6 +108,11 @@ omlish/asyncs/bluelet/events.py,sha256=iXpRWmy64YcshT_nuyiJ39jbketZdtj8LrdlX3Jmp
108
108
  omlish/asyncs/bluelet/files.py,sha256=pgcLV_3oGbpqQmOrii8SeizyYLp8XKofQJhqM82RlKw,2389
109
109
  omlish/asyncs/bluelet/runner.py,sha256=F6Ep0th09f-FkIRJfMN3_u-iG21jNNv11WyqnHyITYU,15475
110
110
  omlish/asyncs/bluelet/sockets.py,sha256=RrC2vU52dOEBYKzvoh1qA39uUE8p3uCB_oxnhaP1AeA,6752
111
+ omlish/asyncs/ioproxy/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
112
+ omlish/asyncs/ioproxy/io.py,sha256=nIvaKi5CEMrycj1N_gfBeMwILNfFA_H1rklgR87xKCM,4987
113
+ omlish/asyncs/ioproxy/proxier.py,sha256=yhHud-00DuGZeSlJHJs6dpsXUpsmuD1Kw0vw9gTsdpU,4456
114
+ omlish/asyncs/ioproxy/proxy.py,sha256=cPzwHRlptaRPAKC5XdqwnBEObGNfSUsI4JWaUgFoZ64,3905
115
+ omlish/asyncs/ioproxy/typing.py,sha256=Aa9ysSEFww_P39Bza0p-CehRpvwg0UvcopeQ-L_isyc,2440
111
116
  omlish/bootstrap/__init__.py,sha256=-Rtsg7uPQNhh1dIT9nqrz96XlqizwoLnWf-FwOEstJI,730
112
117
  omlish/bootstrap/__main__.py,sha256=4jCwsaogp0FrJjJZ85hzF4-WqluPeheHbfeoKynKvNs,194
113
118
  omlish/bootstrap/base.py,sha256=d8hqn4hp1XMMi5PgcJBQXPKmW47epu8CxBlqDZiRZb4,1073
@@ -159,7 +164,7 @@ omlish/configs/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
159
164
  omlish/configs/processing/all.py,sha256=roIQ7EZJXSzsyUxNHNJaZsXcD2jdT46Ly1XXfG8xEcI,722
160
165
  omlish/configs/processing/flattening.py,sha256=1duZH5zbrGuoYqaJco5LN5qx6e76QP5pHbIyItkQsFY,5021
161
166
  omlish/configs/processing/inheritance.py,sha256=lFD8eWRE0cG0Z3-eCu7pMsP2skWhUNaoAtWi9fNfn8k,1218
162
- omlish/configs/processing/matching.py,sha256=JMS9r58pMCBbpewOhPY5oPtBu3uD6z6YBfZq4jnLwBE,1236
167
+ omlish/configs/processing/matching.py,sha256=R64RxpPB1uX5Ztvvk2dQ2xi_xwlaxkxQgZwtDVR9spY,1514
163
168
  omlish/configs/processing/names.py,sha256=weHmaTclzgM9lUn3aBtw-kwZ3mc2N-CZlFg3Kd_UsKo,1093
164
169
  omlish/configs/processing/rewriting.py,sha256=v7PfHtuTn5v_5Y6Au7oMN2Z0nxAMy1iYyO5CXnTvZhs,4226
165
170
  omlish/configs/processing/strings.py,sha256=qFS2oh6z02IaM_q4lTKLdufzkJqAJ6J-Qjrz5S-QJoM,826
@@ -325,7 +330,7 @@ omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNx
325
330
  omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
326
331
  omlish/inject/impl/scopes.py,sha256=hKnzNieB-fJSFEXDP_QG1mCfIKoVFIfFlf9LiIt5tk4,5920
327
332
  omlish/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
328
- omlish/io/abc.py,sha256=Cxs8KB1B_69rxpUYxI-MTsilAmNooJJn3w07DKqYKkE,1255
333
+ omlish/io/abc.py,sha256=M40QB2udYpCEqmlxCcHv6FlJYJY6ymmJQBlaklYv0U8,1256
329
334
  omlish/io/buffers.py,sha256=qo1hCqTfKvlbSmddneporqCtW0rZJ_Mv2GrQTI1Hbk0,5636
330
335
  omlish/io/pyio.py,sha256=q4RBFVpBE5PYjnGPGT-_4pcZb7dFJmLJ4LtI8OoDRQY,95433
331
336
  omlish/io/trampoline.py,sha256=oUKTQg1F5xQS1431Kt7MbK-NZpX509ubcXU-s86xJr8,7171
@@ -392,9 +397,9 @@ omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1
392
397
  omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
393
398
  omlish/lite/__init__.py,sha256=ISLhM4q0LR1XXTCaHdZOZxBRyIsoZqYm4u0bf1BPcVk,148
394
399
  omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
395
- omlish/lite/check.py,sha256=0PD-GKtaDqDX6jU5KbzbMvH-vl6jH82xgYfplmfTQkg,12941
400
+ omlish/lite/check.py,sha256=OLwtE2x6nlbGx4vS3Rda7zMHpgqzDSLJminTAX2lqLA,13529
396
401
  omlish/lite/configs.py,sha256=Ev_19sbII67pTWzInYjYqa9VyTiZBvyjhZqyG8TtufE,908
397
- omlish/lite/contextmanagers.py,sha256=m9JO--p7L7mSl4cycXysH-1AO27weDKjP3DZG61cwwM,1683
402
+ omlish/lite/contextmanagers.py,sha256=ciaMl0D3QDHToM7M28-kwZ-Q48LtwgCxiud3nekgutA,2863
398
403
  omlish/lite/dataclasses.py,sha256=M6UD4VwGo0Ky7RNzKWbO0IOy7iBZVCIbTiC6EYbFnX8,1035
399
404
  omlish/lite/inject.py,sha256=qBUftFeXMiRgANYbNS2e7TePMYyFAcuLgsJiLyMTW5o,28769
400
405
  omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
@@ -609,9 +614,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
609
614
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
610
615
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
611
616
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
612
- omlish-0.0.0.dev212.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
613
- omlish-0.0.0.dev212.dist-info/METADATA,sha256=HJccL3nK4sY04Ozm3b3wHJwjuZciBHbzD9MHSNowj9E,4264
614
- omlish-0.0.0.dev212.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
615
- omlish-0.0.0.dev212.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
616
- omlish-0.0.0.dev212.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
617
- omlish-0.0.0.dev212.dist-info/RECORD,,
617
+ omlish-0.0.0.dev213.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
618
+ omlish-0.0.0.dev213.dist-info/METADATA,sha256=IpkbQXwChAhIh8w_W3662VHEfMYUAs1Kcq1NRDjAr6Q,4264
619
+ omlish-0.0.0.dev213.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
620
+ omlish-0.0.0.dev213.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
621
+ omlish-0.0.0.dev213.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
622
+ omlish-0.0.0.dev213.dist-info/RECORD,,