omlish 0.0.0.dev22__py3-none-any.whl → 0.0.0.dev24__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 +10 -3
- omlish/asyncs/bridge.py +3 -0
- omlish/bootstrap/__init__.py +39 -0
- omlish/bootstrap/base.py +3 -1
- omlish/bootstrap/diag.py +48 -1
- omlish/bootstrap/main.py +2 -1
- omlish/bootstrap/marshal.py +18 -0
- omlish/check.py +305 -37
- omlish/collections/__init__.py +2 -2
- omlish/collections/utils.py +3 -3
- omlish/concurrent/threadlets.py +5 -0
- omlish/dataclasses/__init__.py +1 -0
- omlish/dataclasses/impl/init.py +10 -2
- omlish/dataclasses/impl/metadata.py +3 -3
- omlish/dataclasses/impl/reflect.py +1 -1
- omlish/dataclasses/utils.py +16 -3
- omlish/diag/asts.py +132 -0
- omlish/diag/pycharm.py +139 -0
- omlish/docker.py +19 -11
- omlish/genmachine.py +59 -0
- omlish/graphs/trees.py +1 -1
- omlish/lang/__init__.py +13 -1
- omlish/lang/cached.py +5 -2
- omlish/lang/descriptors.py +33 -16
- omlish/lang/resources.py +60 -0
- omlish/lite/logs.py +133 -4
- omlish/logs/__init__.py +17 -2
- omlish/logs/configs.py +13 -1
- omlish/logs/formatters.py +0 -1
- omlish/marshal/__init__.py +6 -0
- omlish/marshal/base64.py +4 -0
- omlish/marshal/helpers.py +27 -0
- omlish/marshal/primitives.py +6 -0
- omlish/marshal/standard.py +4 -0
- omlish/marshal/unions.py +101 -0
- omlish/matchfns.py +3 -3
- omlish/specs/jsonschema/keywords/base.py +2 -2
- omlish/specs/jsonschema/keywords/parse.py +1 -1
- omlish/sql/__init__.py +18 -0
- omlish/sql/qualifiedname.py +82 -0
- omlish/stats.py +1 -0
- {omlish-0.0.0.dev22.dist-info → omlish-0.0.0.dev24.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev22.dist-info → omlish-0.0.0.dev24.dist-info}/RECORD +46 -39
- {omlish-0.0.0.dev22.dist-info → omlish-0.0.0.dev24.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev22.dist-info → omlish-0.0.0.dev24.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev22.dist-info → omlish-0.0.0.dev24.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev24'
|
2
|
+
__revision__ = '4ab439ef967fda27804fe7d241924c6f08757b54'
|
3
3
|
|
4
4
|
|
5
5
|
#
|
@@ -80,7 +80,11 @@ class Project(ProjectBase):
|
|
80
80
|
'sqlalchemy[asyncio] ~= 2.0',
|
81
81
|
|
82
82
|
'pg8000 ~= 1.31',
|
83
|
+
# 'psycopg2 ~= 2.9',
|
84
|
+
|
83
85
|
'pymysql ~= 1.1',
|
86
|
+
# 'mysql-connector-python ~= 9.0',
|
87
|
+
# 'mysqlclient ~= 2.2',
|
84
88
|
|
85
89
|
'aiomysql ~= 0.2',
|
86
90
|
'aiosqlite ~= 0.20',
|
@@ -110,7 +114,10 @@ class SetuptoolsBase:
|
|
110
114
|
include_package_data = False
|
111
115
|
|
112
116
|
find_packages = {
|
113
|
-
'exclude': [
|
117
|
+
'exclude': [
|
118
|
+
'*.tests',
|
119
|
+
'*.tests.*',
|
120
|
+
],
|
114
121
|
}
|
115
122
|
|
116
123
|
|
omlish/asyncs/bridge.py
CHANGED
omlish/bootstrap/__init__.py
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
from .base import ( # noqa
|
2
|
+
Bootstrap,
|
3
|
+
ContextBootstrap,
|
4
|
+
SimpleBootstrap,
|
5
|
+
)
|
6
|
+
|
7
|
+
from .diag import ( # noqa
|
8
|
+
CheckBootstrap,
|
9
|
+
CprofileBootstrap,
|
10
|
+
PycharmBootstrap,
|
11
|
+
ThreadDumpBootstrap,
|
12
|
+
TimebombBootstrap,
|
13
|
+
)
|
14
|
+
|
1
15
|
from .harness import ( # noqa
|
2
16
|
bootstrap,
|
3
17
|
)
|
18
|
+
|
19
|
+
from .sys import ( # noqa
|
20
|
+
CwdBootstrap,
|
21
|
+
EnvBootstrap,
|
22
|
+
FaulthandlerBootstrap,
|
23
|
+
FdsBootstrap,
|
24
|
+
GcBootstrap,
|
25
|
+
GcDebugFlag,
|
26
|
+
ImportBootstrap,
|
27
|
+
LogBootstrap,
|
28
|
+
NiceBootstrap,
|
29
|
+
PidfileBootstrap,
|
30
|
+
PrctlBootstrap,
|
31
|
+
PrintPidBootstrap,
|
32
|
+
RlimitBootstrap,
|
33
|
+
SetuidBootstrap,
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
##
|
38
|
+
|
39
|
+
|
40
|
+
from ..lang.imports import _register_conditional_import # noqa
|
41
|
+
|
42
|
+
_register_conditional_import('..marshal', '.marshal', __package__)
|
omlish/bootstrap/base.py
CHANGED
@@ -2,6 +2,8 @@ import abc
|
|
2
2
|
import dataclasses as dc
|
3
3
|
import typing as ta
|
4
4
|
|
5
|
+
from omlish import lang
|
6
|
+
|
5
7
|
|
6
8
|
BootstrapConfigT = ta.TypeVar('BootstrapConfigT', bound='Bootstrap.Config')
|
7
9
|
|
@@ -9,7 +11,7 @@ BootstrapConfigT = ta.TypeVar('BootstrapConfigT', bound='Bootstrap.Config')
|
|
9
11
|
##
|
10
12
|
|
11
13
|
|
12
|
-
class Bootstrap(abc.ABC, ta.Generic[BootstrapConfigT]):
|
14
|
+
class Bootstrap(abc.ABC, lang.PackageSealed, ta.Generic[BootstrapConfigT]):
|
13
15
|
@dc.dataclass(frozen=True)
|
14
16
|
class Config(abc.ABC): # noqa
|
15
17
|
pass
|
omlish/bootstrap/diag.py
CHANGED
@@ -5,28 +5,56 @@ import signal
|
|
5
5
|
import sys
|
6
6
|
import typing as ta
|
7
7
|
|
8
|
+
from .. import check
|
8
9
|
from .. import lang
|
9
10
|
from .base import Bootstrap
|
10
11
|
from .base import ContextBootstrap
|
12
|
+
from .base import SimpleBootstrap
|
11
13
|
|
12
14
|
|
13
15
|
if ta.TYPE_CHECKING:
|
14
16
|
import cProfile # noqa
|
15
17
|
import pstats
|
16
18
|
|
19
|
+
from ..diag import pycharm as diagpc
|
17
20
|
from ..diag import threads as diagt
|
18
21
|
|
19
22
|
else:
|
20
23
|
cProfile = lang.proxy_import('cProfile') # noqa
|
21
24
|
pstats = lang.proxy_import('pstats')
|
22
25
|
|
26
|
+
diagpc = lang.proxy_import('..diag.pycharm', __package__)
|
23
27
|
diagt = lang.proxy_import('..diag.threads', __package__)
|
24
28
|
|
25
29
|
|
26
30
|
##
|
27
31
|
|
28
32
|
|
29
|
-
class
|
33
|
+
class CheckBootstrap(ContextBootstrap['CheckBootstrap.Config']):
|
34
|
+
@dc.dataclass(frozen=True)
|
35
|
+
class Config(Bootstrap.Config):
|
36
|
+
breakpoint: bool = False
|
37
|
+
|
38
|
+
@staticmethod
|
39
|
+
def _breakpoint(exc: Exception) -> None: # noqa
|
40
|
+
breakpoint() # noqa
|
41
|
+
|
42
|
+
@contextlib.contextmanager
|
43
|
+
def enter(self) -> ta.Iterator[None]:
|
44
|
+
if not self._config.breakpoint:
|
45
|
+
return
|
46
|
+
|
47
|
+
check.register_on_raise(CheckBootstrap._breakpoint)
|
48
|
+
try:
|
49
|
+
yield
|
50
|
+
finally:
|
51
|
+
check.unregister_on_raise(CheckBootstrap._breakpoint)
|
52
|
+
|
53
|
+
|
54
|
+
##
|
55
|
+
|
56
|
+
|
57
|
+
class CprofileBootstrap(ContextBootstrap['CprofileBootstrap.Config']):
|
30
58
|
@dc.dataclass(frozen=True)
|
31
59
|
class Config(Bootstrap.Config):
|
32
60
|
enable: bool = False
|
@@ -128,3 +156,22 @@ class TimebombBootstrap(ContextBootstrap['TimebombBootstrap.Config']):
|
|
128
156
|
yield
|
129
157
|
finally:
|
130
158
|
tbt.stop_nowait()
|
159
|
+
|
160
|
+
|
161
|
+
##
|
162
|
+
|
163
|
+
|
164
|
+
class PycharmBootstrap(SimpleBootstrap['PycharmBootstrap.Config']):
|
165
|
+
@dc.dataclass(frozen=True)
|
166
|
+
class Config(Bootstrap.Config):
|
167
|
+
debug_host: ta.Optional[str] = None
|
168
|
+
debug_port: ta.Optional[int] = None
|
169
|
+
version: ta.Optional[str] = None
|
170
|
+
|
171
|
+
def run(self) -> None:
|
172
|
+
if self._config.debug_port is not None:
|
173
|
+
diagpc.pycharm_remote_debugger_attach(
|
174
|
+
self._config.debug_host,
|
175
|
+
self._config.debug_port,
|
176
|
+
version=self._config.version,
|
177
|
+
)
|
omlish/bootstrap/main.py
CHANGED
@@ -156,8 +156,9 @@ def _main() -> int:
|
|
156
156
|
with bootstrap(*cfgs):
|
157
157
|
tgt = args.target
|
158
158
|
|
159
|
+
sys.argv = [tgt, *(args.args or ())]
|
160
|
+
|
159
161
|
if args.module:
|
160
|
-
sys.argv = [tgt, *(args.args or ())]
|
161
162
|
runpy._run_module_as_main(tgt) # type: ignore # noqa
|
162
163
|
|
163
164
|
else:
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from .. import lang
|
2
|
+
from .. import marshal as msh
|
3
|
+
from .base import Bootstrap
|
4
|
+
from .harness import BOOTSTRAP_TYPES_BY_NAME
|
5
|
+
|
6
|
+
|
7
|
+
@lang.cached_function
|
8
|
+
def _install_standard_marshalling() -> None:
|
9
|
+
cfgs_poly = msh.Polymorphism(
|
10
|
+
Bootstrap.Config,
|
11
|
+
[msh.Impl(b.Config, n) for n, b in BOOTSTRAP_TYPES_BY_NAME.items()],
|
12
|
+
)
|
13
|
+
|
14
|
+
msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.PolymorphismMarshalerFactory(cfgs_poly)]
|
15
|
+
msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.PolymorphismUnmarshalerFactory(cfgs_poly)]
|
16
|
+
|
17
|
+
|
18
|
+
_install_standard_marshalling()
|
omlish/check.py
CHANGED
@@ -3,6 +3,7 @@ TODO:
|
|
3
3
|
- def maybe(v: lang.Maybe[T])
|
4
4
|
"""
|
5
5
|
import collections
|
6
|
+
import threading
|
6
7
|
import typing as ta
|
7
8
|
|
8
9
|
|
@@ -21,6 +22,65 @@ _callable = callable
|
|
21
22
|
##
|
22
23
|
|
23
24
|
|
25
|
+
_CONFIG_LOCK = threading.RLock()
|
26
|
+
|
27
|
+
|
28
|
+
OnRaiseFn: ta.TypeAlias = ta.Callable[[Exception], None]
|
29
|
+
_ON_RAISE: ta.Sequence[OnRaiseFn] = []
|
30
|
+
|
31
|
+
|
32
|
+
def register_on_raise(fn: OnRaiseFn) -> None:
|
33
|
+
global _ON_RAISE
|
34
|
+
with _CONFIG_LOCK:
|
35
|
+
_ON_RAISE = [*_ON_RAISE, fn]
|
36
|
+
|
37
|
+
|
38
|
+
def unregister_on_raise(fn: OnRaiseFn) -> None:
|
39
|
+
global _ON_RAISE
|
40
|
+
with _CONFIG_LOCK:
|
41
|
+
_ON_RAISE = [e for e in _ON_RAISE if e != fn]
|
42
|
+
|
43
|
+
|
44
|
+
#
|
45
|
+
|
46
|
+
|
47
|
+
_render_args: ta.Callable[..., str | None] | None = None
|
48
|
+
|
49
|
+
|
50
|
+
def enable_args_rendering() -> bool:
|
51
|
+
global _render_args
|
52
|
+
if _render_args is not None:
|
53
|
+
return True
|
54
|
+
|
55
|
+
with _CONFIG_LOCK:
|
56
|
+
if _render_args is not None:
|
57
|
+
return True # type: ignore
|
58
|
+
|
59
|
+
try:
|
60
|
+
from .diag.asts import ArgsRenderer
|
61
|
+
|
62
|
+
ArgsRenderer.smoketest()
|
63
|
+
|
64
|
+
except Exception: # noqa
|
65
|
+
return False
|
66
|
+
|
67
|
+
def _real_render_args(fmt: str, *args: ta.Any) -> str | None:
|
68
|
+
ra = ArgsRenderer(back=3).render_args(*args)
|
69
|
+
if ra is None:
|
70
|
+
return None
|
71
|
+
|
72
|
+
return fmt % tuple(str(a) for a in ra)
|
73
|
+
|
74
|
+
_render_args = _real_render_args
|
75
|
+
return True
|
76
|
+
|
77
|
+
|
78
|
+
enable_args_rendering()
|
79
|
+
|
80
|
+
|
81
|
+
#
|
82
|
+
|
83
|
+
|
24
84
|
def _default_exception_factory(exc_cls: type[Exception], *args, **kwargs) -> Exception:
|
25
85
|
return exc_cls(*args, **kwargs) # noqa
|
26
86
|
|
@@ -28,20 +88,45 @@ def _default_exception_factory(exc_cls: type[Exception], *args, **kwargs) -> Exc
|
|
28
88
|
_EXCEPTION_FACTORY = _default_exception_factory
|
29
89
|
|
30
90
|
|
91
|
+
class _Args:
|
92
|
+
def __init__(self, *args, **kwargs):
|
93
|
+
self.args = args
|
94
|
+
self.kwargs = kwargs
|
95
|
+
|
96
|
+
|
31
97
|
def _raise(
|
32
98
|
exception_type: type[Exception],
|
33
99
|
default_message: str,
|
34
100
|
message: Message,
|
35
|
-
|
36
|
-
|
101
|
+
ak: _Args = _Args(),
|
102
|
+
*,
|
103
|
+
render_fmt: str | None = None,
|
37
104
|
) -> ta.NoReturn:
|
105
|
+
exc_args = ()
|
38
106
|
if _callable(message):
|
39
|
-
message = ta.cast(ta.Callable, message)(*args, **kwargs)
|
107
|
+
message = ta.cast(ta.Callable, message)(*ak.args, **ak.kwargs)
|
40
108
|
if _isinstance(message, tuple):
|
41
|
-
message, *
|
109
|
+
message, *exc_args = message # type: ignore
|
110
|
+
|
42
111
|
if message is None:
|
43
112
|
message = default_message
|
44
|
-
|
113
|
+
|
114
|
+
if render_fmt is not None and _render_args is not None:
|
115
|
+
rendered_args = _render_args(render_fmt, *ak.args)
|
116
|
+
if rendered_args is not None:
|
117
|
+
message = f'{message} : {rendered_args}'
|
118
|
+
|
119
|
+
exc = _EXCEPTION_FACTORY(
|
120
|
+
exception_type,
|
121
|
+
message,
|
122
|
+
*exc_args,
|
123
|
+
*ak.args,
|
124
|
+
**ak.kwargs,
|
125
|
+
)
|
126
|
+
|
127
|
+
for fn in _ON_RAISE:
|
128
|
+
fn(exc)
|
129
|
+
|
45
130
|
raise exc
|
46
131
|
|
47
132
|
|
@@ -60,7 +145,14 @@ def _unpack_isinstance_spec(spec: ta.Any) -> tuple:
|
|
60
145
|
|
61
146
|
def isinstance(v: ta.Any, spec: type[T] | tuple, msg: Message = None) -> T: # noqa
|
62
147
|
if not _isinstance(v, _unpack_isinstance_spec(spec)):
|
63
|
-
_raise(
|
148
|
+
_raise(
|
149
|
+
TypeError,
|
150
|
+
'Must be instance',
|
151
|
+
msg,
|
152
|
+
_Args(v, spec),
|
153
|
+
render_fmt='not isinstance(%s, %s)',
|
154
|
+
)
|
155
|
+
|
64
156
|
return v
|
65
157
|
|
66
158
|
|
@@ -73,7 +165,13 @@ def of_isinstance(spec: type[T] | tuple, msg: Message = None) -> ta.Callable[[ta
|
|
73
165
|
|
74
166
|
def cast(v: ta.Any, cls: type[T], msg: Message = None) -> T: # noqa
|
75
167
|
if not _isinstance(v, cls):
|
76
|
-
_raise(
|
168
|
+
_raise(
|
169
|
+
TypeError,
|
170
|
+
'Must be instance',
|
171
|
+
msg,
|
172
|
+
_Args(v, cls),
|
173
|
+
)
|
174
|
+
|
77
175
|
return v
|
78
176
|
|
79
177
|
|
@@ -86,7 +184,14 @@ def of_cast(cls: type[T], msg: Message = None) -> ta.Callable[[T], T]:
|
|
86
184
|
|
87
185
|
def not_isinstance(v: T, spec: ta.Any, msg: Message = None) -> T: # noqa
|
88
186
|
if _isinstance(v, _unpack_isinstance_spec(spec)):
|
89
|
-
_raise(
|
187
|
+
_raise(
|
188
|
+
TypeError,
|
189
|
+
'Must not be instance',
|
190
|
+
msg,
|
191
|
+
_Args(v, spec),
|
192
|
+
render_fmt='isinstance(%s, %s)',
|
193
|
+
)
|
194
|
+
|
90
195
|
return v
|
91
196
|
|
92
197
|
|
@@ -102,13 +207,27 @@ def of_not_isinstance(spec: ta.Any, msg: Message = None) -> ta.Callable[[T], T]:
|
|
102
207
|
|
103
208
|
def issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: # noqa
|
104
209
|
if not _issubclass(v, spec):
|
105
|
-
_raise(
|
210
|
+
_raise(
|
211
|
+
TypeError,
|
212
|
+
'Must be subclass',
|
213
|
+
msg,
|
214
|
+
_Args(v, spec),
|
215
|
+
render_fmt='not issubclass(%s, %s)',
|
216
|
+
)
|
217
|
+
|
106
218
|
return v
|
107
219
|
|
108
220
|
|
109
221
|
def not_issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: # noqa
|
110
222
|
if _issubclass(v, spec):
|
111
|
-
_raise(
|
223
|
+
_raise(
|
224
|
+
TypeError,
|
225
|
+
'Must not be subclass',
|
226
|
+
msg,
|
227
|
+
_Args(v, spec),
|
228
|
+
render_fmt='issubclass(%s, %s)',
|
229
|
+
)
|
230
|
+
|
112
231
|
return v
|
113
232
|
|
114
233
|
|
@@ -117,32 +236,84 @@ def not_issubclass(v: type[T], spec: ta.Any, msg: Message = None) -> type[T]: #
|
|
117
236
|
|
118
237
|
def in_(v: T, c: ta.Container[T], msg: Message = None) -> T:
|
119
238
|
if v not in c:
|
120
|
-
_raise(
|
239
|
+
_raise(
|
240
|
+
ValueError,
|
241
|
+
'Must be in',
|
242
|
+
msg,
|
243
|
+
_Args(v, c),
|
244
|
+
render_fmt='%s not in %s',
|
245
|
+
)
|
246
|
+
|
121
247
|
return v
|
122
248
|
|
123
249
|
|
124
250
|
def not_in(v: T, c: ta.Container[T], msg: Message = None) -> T:
|
125
251
|
if v in c:
|
126
|
-
_raise(
|
252
|
+
_raise(
|
253
|
+
ValueError,
|
254
|
+
'Must not be in',
|
255
|
+
msg,
|
256
|
+
_Args(v, c),
|
257
|
+
render_fmt='%s in %s',
|
258
|
+
)
|
259
|
+
|
127
260
|
return v
|
128
261
|
|
129
262
|
|
130
263
|
def empty(v: SizedT, msg: Message = None) -> SizedT:
|
131
264
|
if len(v) != 0:
|
132
|
-
_raise(
|
265
|
+
_raise(
|
266
|
+
ValueError,
|
267
|
+
'Must be empty',
|
268
|
+
msg,
|
269
|
+
_Args(v),
|
270
|
+
render_fmt='%s',
|
271
|
+
)
|
272
|
+
|
273
|
+
return v
|
274
|
+
|
275
|
+
|
276
|
+
def iterempty(v: ta.Iterable[T], msg: Message = None) -> ta.Iterable[T]:
|
277
|
+
it = iter(v)
|
278
|
+
try:
|
279
|
+
next(it)
|
280
|
+
except StopIteration:
|
281
|
+
pass
|
282
|
+
else:
|
283
|
+
_raise(
|
284
|
+
ValueError,
|
285
|
+
'Must be empty',
|
286
|
+
msg,
|
287
|
+
_Args(v),
|
288
|
+
render_fmt='%s',
|
289
|
+
)
|
290
|
+
|
133
291
|
return v
|
134
292
|
|
135
293
|
|
136
294
|
def not_empty(v: SizedT, msg: Message = None) -> SizedT:
|
137
295
|
if len(v) == 0:
|
138
|
-
_raise(
|
296
|
+
_raise(
|
297
|
+
ValueError,
|
298
|
+
'Must not be empty',
|
299
|
+
msg,
|
300
|
+
_Args(v),
|
301
|
+
render_fmt='%s',
|
302
|
+
)
|
303
|
+
|
139
304
|
return v
|
140
305
|
|
141
306
|
|
142
307
|
def unique(it: ta.Iterable[T], msg: Message = None) -> ta.Iterable[T]:
|
143
308
|
dupes = [e for e, c in collections.Counter(it).items() if c > 1]
|
144
309
|
if dupes:
|
145
|
-
_raise(
|
310
|
+
_raise(
|
311
|
+
ValueError,
|
312
|
+
'Must be unique',
|
313
|
+
msg,
|
314
|
+
_Args(it, dupes),
|
315
|
+
)
|
316
|
+
|
146
317
|
return it
|
147
318
|
|
148
319
|
|
@@ -150,9 +321,15 @@ def single(obj: ta.Iterable[T], message: Message = None) -> T:
|
|
150
321
|
try:
|
151
322
|
[value] = obj
|
152
323
|
except ValueError:
|
153
|
-
_raise(
|
154
|
-
|
155
|
-
|
324
|
+
_raise(
|
325
|
+
ValueError,
|
326
|
+
'Must be single',
|
327
|
+
message,
|
328
|
+
_Args(obj),
|
329
|
+
render_fmt='%s',
|
330
|
+
)
|
331
|
+
|
332
|
+
return value
|
156
333
|
|
157
334
|
|
158
335
|
def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
|
@@ -161,11 +338,19 @@ def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
|
|
161
338
|
value = next(it)
|
162
339
|
except StopIteration:
|
163
340
|
return None
|
341
|
+
|
164
342
|
try:
|
165
343
|
next(it)
|
166
344
|
except StopIteration:
|
167
345
|
return value # noqa
|
168
|
-
|
346
|
+
|
347
|
+
_raise(
|
348
|
+
ValueError,
|
349
|
+
'Must be empty or single',
|
350
|
+
message,
|
351
|
+
_Args(obj),
|
352
|
+
render_fmt='%s',
|
353
|
+
)
|
169
354
|
|
170
355
|
|
171
356
|
##
|
@@ -173,59 +358,142 @@ def optional_single(obj: ta.Iterable[T], message: Message = None) -> T | None:
|
|
173
358
|
|
174
359
|
def none(v: ta.Any, msg: Message = None) -> None:
|
175
360
|
if v is not None:
|
176
|
-
_raise(
|
361
|
+
_raise(
|
362
|
+
ValueError,
|
363
|
+
'Must be None',
|
364
|
+
msg,
|
365
|
+
_Args(v),
|
366
|
+
render_fmt='%s',
|
367
|
+
)
|
177
368
|
|
178
369
|
|
179
370
|
def not_none(v: T | None, msg: Message = None) -> T:
|
180
371
|
if v is None:
|
181
|
-
_raise(
|
372
|
+
_raise(
|
373
|
+
ValueError,
|
374
|
+
'Must not be None',
|
375
|
+
msg,
|
376
|
+
_Args(v),
|
377
|
+
render_fmt='%s',
|
378
|
+
)
|
379
|
+
|
182
380
|
return v
|
183
381
|
|
184
382
|
|
185
383
|
##
|
186
384
|
|
187
385
|
|
188
|
-
def equal(v: T,
|
189
|
-
|
190
|
-
|
191
|
-
|
386
|
+
def equal(v: T, o: ta.Any, msg: Message = None) -> T:
|
387
|
+
if o != v:
|
388
|
+
_raise(
|
389
|
+
ValueError,
|
390
|
+
'Must be equal',
|
391
|
+
msg,
|
392
|
+
_Args(v, o),
|
393
|
+
render_fmt='%s != %s',
|
394
|
+
)
|
395
|
+
|
192
396
|
return v
|
193
397
|
|
194
398
|
|
195
|
-
def is_(v: T,
|
196
|
-
|
197
|
-
|
198
|
-
|
399
|
+
def is_(v: T, o: ta.Any, msg: Message = None) -> T:
|
400
|
+
if o is not v:
|
401
|
+
_raise(
|
402
|
+
ValueError,
|
403
|
+
'Must be the same',
|
404
|
+
msg,
|
405
|
+
_Args(v, o),
|
406
|
+
render_fmt='%s is not %s',
|
407
|
+
)
|
408
|
+
|
199
409
|
return v
|
200
410
|
|
201
411
|
|
202
|
-
def is_not(v: T,
|
203
|
-
|
204
|
-
|
205
|
-
|
412
|
+
def is_not(v: T, o: ta.Any, msg: Message = None) -> T:
|
413
|
+
if o is v:
|
414
|
+
_raise(
|
415
|
+
ValueError,
|
416
|
+
'Must not be the same',
|
417
|
+
msg,
|
418
|
+
_Args(v, o),
|
419
|
+
render_fmt='%s is %s',
|
420
|
+
)
|
421
|
+
|
206
422
|
return v
|
207
423
|
|
208
424
|
|
209
425
|
def callable(v: T, msg: Message = None) -> T: # noqa
|
210
426
|
if not _callable(v):
|
211
|
-
_raise(
|
427
|
+
_raise(
|
428
|
+
TypeError,
|
429
|
+
'Must be callable',
|
430
|
+
msg,
|
431
|
+
_Args(v),
|
432
|
+
render_fmt='%s',
|
433
|
+
)
|
434
|
+
|
212
435
|
return v # type: ignore
|
213
436
|
|
214
437
|
|
215
438
|
def non_empty_str(v: str | None, msg: Message = None) -> str:
|
216
439
|
if not _isinstance(v, str) or not v:
|
217
|
-
_raise(
|
440
|
+
_raise(
|
441
|
+
ValueError,
|
442
|
+
'Must be non-empty str',
|
443
|
+
msg,
|
444
|
+
_Args(v),
|
445
|
+
render_fmt='%s',
|
446
|
+
)
|
447
|
+
|
218
448
|
return v
|
219
449
|
|
220
450
|
|
451
|
+
def replacing(expected: ta.Any, old: ta.Any, new: T, msg: Message = None) -> T:
|
452
|
+
if old != expected:
|
453
|
+
_raise(
|
454
|
+
ValueError,
|
455
|
+
'Must be replacing',
|
456
|
+
msg,
|
457
|
+
_Args(expected, old, new),
|
458
|
+
render_fmt='%s -> %s -> %s',
|
459
|
+
)
|
460
|
+
|
461
|
+
return new
|
462
|
+
|
463
|
+
|
464
|
+
def replacing_none(old: ta.Any, new: T, msg: Message = None) -> T:
|
465
|
+
if old is not None:
|
466
|
+
_raise(
|
467
|
+
ValueError,
|
468
|
+
'Must be replacing None',
|
469
|
+
msg,
|
470
|
+
_Args(old, new),
|
471
|
+
render_fmt='%s -> %s',
|
472
|
+
)
|
473
|
+
|
474
|
+
return new
|
475
|
+
|
476
|
+
|
221
477
|
##
|
222
478
|
|
223
479
|
|
224
480
|
def arg(v: bool, msg: Message = None) -> None:
|
225
481
|
if not v:
|
226
|
-
_raise(
|
482
|
+
_raise(
|
483
|
+
RuntimeError,
|
484
|
+
'Argument condition not met',
|
485
|
+
msg,
|
486
|
+
_Args(v),
|
487
|
+
render_fmt='%s',
|
488
|
+
)
|
227
489
|
|
228
490
|
|
229
491
|
def state(v: bool, msg: Message = None) -> None:
|
230
492
|
if not v:
|
231
|
-
_raise(
|
493
|
+
_raise(
|
494
|
+
RuntimeError,
|
495
|
+
'State condition not met',
|
496
|
+
msg,
|
497
|
+
_Args(v),
|
498
|
+
render_fmt='%s',
|
499
|
+
)
|