omlish 0.0.0.dev424__py3-none-any.whl → 0.0.0.dev426__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.
Files changed (126) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/c3.py +4 -1
  3. omlish/configs/processing/flattening.py +1 -1
  4. omlish/configs/processing/merging.py +8 -6
  5. omlish/dataclasses/impl/concerns/doc.py +1 -1
  6. omlish/dataclasses/impl/configs.py +2 -1
  7. omlish/diag/_pycharm/runhack.py +1 -1
  8. omlish/diag/procfs.py +2 -2
  9. omlish/formats/json/stream/lexing.py +69 -14
  10. omlish/formats/json/stream/parsing.py +1 -1
  11. omlish/formats/json/stream/utils.py +3 -0
  12. omlish/formats/json5/streams.py +22 -0
  13. omlish/formats/logfmt.py +8 -2
  14. omlish/funcs/genmachine.py +1 -1
  15. omlish/http/sse.py +1 -1
  16. omlish/inject/impl/injector.py +1 -1
  17. omlish/inject/impl/multis.py +2 -2
  18. omlish/inject/impl/providers.py +0 -4
  19. omlish/inject/impl/proxy.py +0 -2
  20. omlish/inject/scopes.py +0 -4
  21. omlish/io/buffers.py +1 -1
  22. omlish/lang/__init__.py +26 -14
  23. omlish/lang/asyncs.py +12 -0
  24. omlish/lang/{attrs.py → attrstorage.py} +15 -15
  25. omlish/lang/cached/property.py +2 -2
  26. omlish/lang/classes/simple.py +26 -4
  27. omlish/lang/collections.py +1 -1
  28. omlish/lang/functions.py +0 -11
  29. omlish/lang/iterables.py +2 -2
  30. omlish/lang/lazyglobals.py +27 -5
  31. omlish/lang/maysync.py +2 -2
  32. omlish/lifecycles/contextmanagers.py +1 -2
  33. omlish/lifecycles/controller.py +1 -2
  34. omlish/lite/asyncs.py +20 -0
  35. omlish/lite/attrops.py +332 -0
  36. omlish/lite/cached.py +1 -1
  37. omlish/lite/maybes.py +2 -0
  38. omlish/lite/strings.py +0 -7
  39. omlish/lite/timing.py +6 -3
  40. omlish/logs/all.py +25 -32
  41. omlish/logs/base.py +248 -0
  42. omlish/logs/callers.py +21 -15
  43. omlish/logs/infos.py +105 -0
  44. omlish/logs/levels.py +64 -0
  45. omlish/logs/modules.py +10 -0
  46. omlish/logs/protocols.py +31 -0
  47. omlish/logs/standard.py +12 -11
  48. omlish/logs/std/adapters.py +41 -0
  49. omlish/logs/std/configs.py +29 -0
  50. omlish/logs/{filters.py → std/filters.py} +1 -1
  51. omlish/logs/{handlers.py → std/handlers.py} +1 -1
  52. omlish/logs/{json.py → std/json.py} +2 -2
  53. omlish/logs/{proxy.py → std/proxy.py} +3 -3
  54. omlish/logs/std/records.py +286 -0
  55. omlish/logs/times.py +86 -0
  56. omlish/logs/typed/bindings.py +24 -0
  57. omlish/logs/utils.py +60 -4
  58. omlish/logs/warnings.py +8 -0
  59. omlish/manifests/loading.py +1 -1
  60. omlish/os/atomics.py +1 -1
  61. omlish/os/journald.py +3 -3
  62. omlish/reflect/types.py +22 -0
  63. omlish/testing/pytest/plugins/skips.py +0 -4
  64. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/METADATA +2 -2
  65. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/RECORD +72 -114
  66. omlish/defs.py +0 -216
  67. omlish/dispatch/_dispatch2.py +0 -69
  68. omlish/dispatch/_dispatch3.py +0 -108
  69. omlish/dynamic.py +0 -219
  70. omlish/formats/json/Json.g4 +0 -77
  71. omlish/formats/json/_antlr/JsonLexer.py +0 -109
  72. omlish/formats/json/_antlr/JsonListener.py +0 -61
  73. omlish/formats/json/_antlr/JsonParser.py +0 -457
  74. omlish/formats/json/_antlr/JsonVisitor.py +0 -42
  75. omlish/io/trampoline.py +0 -289
  76. omlish/lite/logs.py +0 -4
  77. omlish/lite/reprs.py +0 -85
  78. omlish/logs/abc.py +0 -319
  79. omlish/logs/color.py +0 -27
  80. omlish/logs/configs.py +0 -29
  81. omlish/logs/protocol.py +0 -218
  82. omlish/logs/timing.py +0 -58
  83. omlish/specs/irc/__init__.py +0 -0
  84. omlish/specs/irc/messages/__init__.py +0 -0
  85. omlish/specs/irc/messages/base.py +0 -49
  86. omlish/specs/irc/messages/formats.py +0 -92
  87. omlish/specs/irc/messages/messages.py +0 -774
  88. omlish/specs/irc/messages/parsing.py +0 -98
  89. omlish/specs/irc/numerics/__init__.py +0 -0
  90. omlish/specs/irc/numerics/formats.py +0 -97
  91. omlish/specs/irc/numerics/numerics.py +0 -865
  92. omlish/specs/irc/numerics/types.py +0 -59
  93. omlish/specs/irc/protocol/LICENSE +0 -11
  94. omlish/specs/irc/protocol/__init__.py +0 -61
  95. omlish/specs/irc/protocol/consts.py +0 -6
  96. omlish/specs/irc/protocol/errors.py +0 -30
  97. omlish/specs/irc/protocol/message.py +0 -21
  98. omlish/specs/irc/protocol/nuh.py +0 -55
  99. omlish/specs/irc/protocol/parsing.py +0 -158
  100. omlish/specs/irc/protocol/rendering.py +0 -153
  101. omlish/specs/irc/protocol/tags.py +0 -102
  102. omlish/specs/irc/protocol/utils.py +0 -30
  103. omlish/specs/proto/Protobuf3.g4 +0 -396
  104. omlish/specs/proto/__init__.py +0 -0
  105. omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
  106. omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
  107. omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
  108. omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
  109. omlish/specs/proto/_antlr/__init__.py +0 -0
  110. omlish/specs/proto/nodes.py +0 -54
  111. omlish/specs/proto/parsing.py +0 -97
  112. omlish/sql/parsing/Minisql.g4 +0 -292
  113. omlish/sql/parsing/__init__.py +0 -0
  114. omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
  115. omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
  116. omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
  117. omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
  118. omlish/sql/parsing/_antlr/__init__.py +0 -0
  119. omlish/sql/parsing/parsing.py +0 -119
  120. /omlish/{.manifests.json → .omlish-manifests.json} +0 -0
  121. /omlish/{formats/json/_antlr → logs/std}/__init__.py +0 -0
  122. /omlish/logs/{noisy.py → std/noisy.py} +0 -0
  123. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/WHEEL +0 -0
  124. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
  125. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
  126. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/top_level.txt +0 -0
omlish/logs/color.py DELETED
@@ -1,27 +0,0 @@
1
- # ruff: noqa: ANN201 N802
2
- import logging
3
- import typing as ta
4
-
5
- from ..term import codes as tc
6
- from .standard import StandardLogFormatter
7
-
8
-
9
- ##
10
-
11
-
12
- class ColorLogFormatter(StandardLogFormatter):
13
- LEVEL_COLORS: ta.Mapping[int, tc.SGRs.FG] = {
14
- logging.WARNING: tc.SGRs.FG.BRIGHT_YELLOW,
15
- logging.ERROR: tc.SGRs.FG.BRIGHT_RED,
16
- logging.CRITICAL: tc.SGRs.FG.BRIGHT_RED,
17
- }
18
-
19
- def formatMessage(self, record):
20
- buf = super().formatMessage(record)
21
- try:
22
- c = self.LEVEL_COLORS[record.levelno]
23
- except KeyError:
24
- pass
25
- else:
26
- buf = tc.SGR(c) + buf + tc.SGR(tc.SGRs.RESET)
27
- return buf
omlish/logs/configs.py DELETED
@@ -1,29 +0,0 @@
1
- # ruff: noqa: UP006 UP045
2
- # @omlish-lite
3
- """
4
- https://docs.python.org/3/howto/logging.html#configuring-logging
5
- https://docs.python.org/3/library/logging.config.html#logging-config-dictschema
6
- """
7
- import dataclasses as dc
8
- import typing as ta
9
-
10
-
11
- FilterConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
12
- FormatterConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
13
- HandlerConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
14
- LoggerConfig = ta.Dict[str, ta.Any] # ta.TypeAlias
15
-
16
-
17
- ##
18
-
19
-
20
- @dc.dataclass()
21
- class DictConfig:
22
- version: int = 1
23
- incremental: bool = False
24
- disable_existing_loggers: bool = False
25
- filters: ta.Dict[str, FilterConfig] = dc.field(default_factory=dict)
26
- formatters: ta.Dict[str, FormatterConfig] = dc.field(default_factory=dict)
27
- handlers: ta.Dict[str, HandlerConfig] = dc.field(default_factory=dict)
28
- loggers: ta.Dict[str, LoggerConfig] = dc.field(default_factory=dict)
29
- root: ta.Optional[LoggerConfig] = None
omlish/logs/protocol.py DELETED
@@ -1,218 +0,0 @@
1
- # ruff: noqa: UP006 UP007 UP045
2
- # @omlish-lite
3
- import abc
4
- import logging
5
- import sys
6
- import typing as ta
7
-
8
- from .callers import LoggingCaller
9
- from .levels import LogLevel
10
-
11
-
12
- T = ta.TypeVar('T')
13
- T_co = ta.TypeVar('T_co', covariant=True)
14
-
15
-
16
- ##
17
-
18
-
19
- class AnyLogging(ta.Protocol[T_co]):
20
- def isEnabledFor(self, level: LogLevel) -> bool: ... # noqa
21
-
22
- def getEffectiveLevel(self) -> LogLevel: ... # noqa
23
-
24
- #
25
-
26
- def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
27
-
28
- def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
29
-
30
- def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
31
-
32
- def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
33
-
34
- def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, **kwargs: ta.Any) -> T_co: ...
35
-
36
- def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
37
-
38
- def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T_co: ...
39
-
40
-
41
- class Logging(AnyLogging[None], ta.Protocol):
42
- pass
43
-
44
-
45
- class AsyncLogging(AnyLogging[ta.Awaitable[None]], ta.Protocol):
46
- pass
47
-
48
-
49
- ##
50
-
51
-
52
- class AnyAbstractLogging(abc.ABC, ta.Generic[T]):
53
- @ta.final
54
- def isEnabledFor(self, level: LogLevel) -> bool: # noqa
55
- return self.is_enabled_for(level)
56
-
57
- def is_enabled_for(self, level: LogLevel) -> bool: # noqa
58
- return level >= self.getEffectiveLevel()
59
-
60
- @ta.final
61
- def getEffectiveLevel(self) -> LogLevel: # noqa
62
- return self.get_effective_level()
63
-
64
- @abc.abstractmethod
65
- def get_effective_level(self) -> LogLevel: # noqa
66
- raise NotImplementedError
67
-
68
- #
69
-
70
- def debug(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
71
- return self.log(logging.DEBUG, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
72
-
73
- def info(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
74
- return self.log(logging.INFO, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
75
-
76
- def warning(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
77
- return self.log(logging.WARNING, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
78
-
79
- def error(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
80
- return self.log(logging.ERROR, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
81
-
82
- def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T: # noqa
83
- return self.error(msg, *args, exc_info=exc_info, _logging_stack_offset=_logging_stack_offset + 1, **kwargs) # noqa
84
-
85
- def critical(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
86
- return self.log(logging.CRITICAL, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
87
-
88
- @abc.abstractmethod
89
- def log(
90
- self,
91
- level: int,
92
- msg: str,
93
- *args: ta.Any,
94
- exc_info: ta.Any = None,
95
- extra: ta.Any = None,
96
- stack_info: bool = False,
97
- _logging_stack_offset: int = 0,
98
- ) -> T:
99
- raise NotImplementedError
100
-
101
-
102
- class AbstractLogging(AnyAbstractLogging[None], abc.ABC):
103
- def log(self, level: LogLevel, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> None:
104
- if not isinstance(level, int):
105
- raise TypeError('Level must be an integer.')
106
- if self.is_enabled_for(level):
107
- self._log(level, msg, args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
108
-
109
- @abc.abstractmethod
110
- def _log(
111
- self,
112
- level: int,
113
- msg: str,
114
- args: ta.Any,
115
- *,
116
- exc_info: ta.Any = None,
117
- extra: ta.Any = None,
118
- stack_info: bool = False,
119
- _logging_stack_offset: int = 0,
120
- ) -> None:
121
- raise NotImplementedError
122
-
123
-
124
- class AbstractAsyncLogging(AnyAbstractLogging[ta.Awaitable[None]], abc.ABC):
125
- async def log(self, level: LogLevel, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> None: # noqa
126
- if not isinstance(level, int):
127
- raise TypeError('Level must be an integer.')
128
- if self.is_enabled_for(level):
129
- await self._log(level, msg, args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
130
-
131
- @abc.abstractmethod
132
- def _log(
133
- self,
134
- level: int,
135
- msg: str,
136
- args: ta.Any,
137
- *,
138
- exc_info: ta.Any = None,
139
- extra: ta.Any = None,
140
- stack_info: bool = False,
141
- _logging_stack_offset: int = 0,
142
- ) -> ta.Awaitable[None]:
143
- raise NotImplementedError
144
-
145
-
146
- ##
147
-
148
-
149
- class AnyNopLogging(AnyAbstractLogging[T], abc.ABC):
150
- def get_effective_level(self) -> LogLevel:
151
- return logging.CRITICAL + 1
152
-
153
-
154
- class NopLogging(AnyNopLogging[None], AbstractLogging):
155
- def _log(self, *args: ta.Any, **kwargs: ta.Any) -> None:
156
- pass
157
-
158
-
159
- class NopAsyncLogging(AnyNopLogging[ta.Awaitable[None]], AbstractAsyncLogging):
160
- async def _log(self, *args: ta.Any, **kwargs: ta.Any) -> None:
161
- pass
162
-
163
-
164
- ##
165
-
166
-
167
- class StdlibLogging(AbstractLogging):
168
- def __init__(self, underlying: logging.Logger) -> None:
169
- super().__init__()
170
-
171
- if not isinstance(underlying, logging.Logger):
172
- raise TypeError(underlying)
173
-
174
- self._underlying = underlying
175
-
176
- #
177
-
178
- def is_enabled_for(self, level: int) -> bool: # noqa
179
- return self._underlying.isEnabledFor(level)
180
-
181
- def get_effective_level(self) -> int: # noqa
182
- return self._underlying.getEffectiveLevel()
183
-
184
- #
185
-
186
- def _log(
187
- self,
188
- level: int,
189
- msg: str,
190
- args: ta.Any,
191
- *,
192
- exc_info: ta.Any = None,
193
- extra: ta.Any = None,
194
- stack_info: bool = False,
195
- _logging_stack_offset: int = 0,
196
- ) -> None:
197
- caller = LoggingCaller.find(_logging_stack_offset, stack_info=stack_info)
198
-
199
- if exc_info:
200
- if isinstance(exc_info, BaseException):
201
- exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
202
- elif not isinstance(exc_info, tuple):
203
- exc_info = sys.exc_info()
204
-
205
- record = self._underlying.makeRecord(
206
- name=self._underlying.name,
207
- level=level,
208
- fn=caller.filename,
209
- lno=caller.lineno,
210
- msg=msg,
211
- args=args,
212
- exc_info=exc_info,
213
- func=caller.func,
214
- extra=extra,
215
- sinfo=caller.sinfo,
216
- )
217
-
218
- self._underlying.handle(record)
omlish/logs/timing.py DELETED
@@ -1,58 +0,0 @@
1
- # ruff: noqa: UP006 UP007 UP045
2
- # @omlish-lite
3
- import logging
4
- import time
5
- import typing as ta
6
-
7
-
8
- ##
9
-
10
-
11
- class LogTimingContext:
12
- DEFAULT_LOG: ta.ClassVar[ta.Optional[logging.Logger]] = None
13
-
14
- class _NOT_SPECIFIED: # noqa
15
- def __new__(cls, *args, **kwargs): # noqa
16
- raise TypeError
17
-
18
- def __init__(
19
- self,
20
- description: str,
21
- *,
22
- log: ta.Union[logging.Logger, ta.Type[_NOT_SPECIFIED], None] = _NOT_SPECIFIED, # noqa
23
- level: int = logging.DEBUG,
24
- ) -> None:
25
- super().__init__()
26
-
27
- self._description = description
28
- if log is self._NOT_SPECIFIED:
29
- log = self.DEFAULT_LOG # noqa
30
- self._log: ta.Optional[logging.Logger] = log # type: ignore
31
- self._level = level
32
-
33
- def set_description(self, description: str) -> 'LogTimingContext':
34
- self._description = description
35
- return self
36
-
37
- _begin_time: float
38
- _end_time: float
39
-
40
- def __enter__(self) -> 'LogTimingContext':
41
- self._begin_time = time.time()
42
-
43
- if self._log is not None:
44
- self._log.log(self._level, f'Begin : {self._description}') # noqa
45
-
46
- return self
47
-
48
- def __exit__(self, exc_type, exc_val, exc_tb):
49
- self._end_time = time.time()
50
-
51
- if self._log is not None:
52
- self._log.log(
53
- self._level,
54
- f'End : {self._description} - {self._end_time - self._begin_time:0.2f} s elapsed',
55
- )
56
-
57
-
58
- log_timing_context = LogTimingContext
File without changes
File without changes
@@ -1,49 +0,0 @@
1
- import typing as ta
2
-
3
- from .... import check
4
- from .... import dataclasses as dc
5
- from ....funcs import pairs as fps
6
- from ..numerics import numerics as nr
7
- from .formats import MessageFormat
8
- from .formats import MessageParamsUnpacker
9
-
10
-
11
- ##
12
-
13
-
14
- class Message(dc.Case):
15
- FORMAT: ta.ClassVar[MessageFormat]
16
- REPLIES: ta.ClassVar[ta.Collection[nr.NumericReply]] = ()
17
-
18
-
19
- ##
20
-
21
-
22
- def list_pair_params_unpacker(
23
- kwarg: str,
24
- key_param: str,
25
- value_param: str,
26
- ) -> MessageParamsUnpacker:
27
- def forward(params: ta.Mapping[str, str]) -> ta.Mapping[str, ta.Any]:
28
- out: dict = dict(params)
29
- ks = out.pop(key_param)
30
- vs = out.pop(value_param, None)
31
- if vs is not None:
32
- out[kwarg] = list(zip(ks, vs, strict=True))
33
- else:
34
- out[kwarg] = ks
35
- return out
36
-
37
- def backward(kwargs: ta.Mapping[str, ta.Any]) -> ta.Mapping[str, str]:
38
- out: dict = dict(kwargs)
39
- ts = out.pop(kwarg)
40
- is_ts = check.single({isinstance(e, tuple) for e in ts})
41
- if is_ts:
42
- ks, vs = zip(*ts)
43
- out[key_param] = ks
44
- out[value_param] = vs
45
- else:
46
- out[key_param] = ts
47
- return out
48
-
49
- return fps.of(forward, backward)
@@ -1,92 +0,0 @@
1
- import enum
2
- import typing as ta
3
-
4
- from .... import check
5
- from .... import dataclasses as dc
6
- from .... import lang
7
- from ....funcs import pairs as fps
8
-
9
-
10
- MessageParamsUnpacker: ta.TypeAlias = fps.FnPair[
11
- ta.Mapping[str, str], # params
12
- ta.Mapping[str, ta.Any], # kwargs
13
- ]
14
-
15
-
16
- ##
17
-
18
-
19
- class MessageFormat(dc.Frozen, final=True):
20
- name: str
21
-
22
- class Param(dc.Case):
23
- @classmethod
24
- def of(cls, obj: ta.Any) -> 'MessageFormat.Param':
25
- if isinstance(obj, MessageFormat.Param):
26
- return obj
27
-
28
- elif isinstance(obj, str):
29
- s = check.non_empty_str(obj)
30
-
31
- optional = False
32
- if s.startswith('?'):
33
- optional = True
34
- s = s[1:]
35
-
36
- arity = MessageFormat.KwargParam.Arity.SINGLE
37
- if s.startswith('*'):
38
- arity = MessageFormat.KwargParam.Arity.VARIADIC
39
- s = s[1:]
40
-
41
- elif s.startswith(','):
42
- arity = MessageFormat.KwargParam.Arity.COMMA_LIST
43
- s = s[1:]
44
-
45
- return MessageFormat.KwargParam(
46
- s,
47
- optional=optional,
48
- arity=arity,
49
- )
50
-
51
- else:
52
- raise TypeError(obj)
53
-
54
- class KwargParam(Param):
55
- name: str = dc.xfield(validate=lang.is_ident)
56
-
57
- optional: bool = False
58
-
59
- class Arity(enum.Enum):
60
- SINGLE = enum.auto() # <foo>
61
- VARIADIC = enum.auto() # <foo>{ <foo>}
62
- COMMA_LIST = enum.auto() # <foo>{,<foo>}
63
-
64
- arity: Arity = Arity.SINGLE
65
-
66
- class LiteralParam(Param):
67
- text: str
68
-
69
- params: ta.Sequence[Param]
70
-
71
- _: dc.KW_ONLY
72
-
73
- unpack_params: MessageParamsUnpacker | None = None
74
-
75
- @dc.init
76
- def _validate_params(self) -> None:
77
- kws = [p for p in self.params if isinstance(p, MessageFormat.KwargParam)]
78
- check.unique(p.name for p in kws)
79
- check.state(all(p.arity is not MessageFormat.KwargParam.Arity.VARIADIC for p in kws[:-1]))
80
-
81
- @classmethod
82
- def of(
83
- cls,
84
- name: str,
85
- *params: ta.Any,
86
- **kwargs: ta.Any,
87
- ) -> 'MessageFormat':
88
- return cls(
89
- name,
90
- [MessageFormat.Param.of(p) for p in params],
91
- **kwargs,
92
- )