omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__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 (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +5 -3
  3. omlish/antlr/_runtime/__init__.py +0 -22
  4. omlish/antlr/_runtime/_all.py +24 -0
  5. omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
  6. omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
  7. omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
  8. omlish/antlr/_runtime/xpath/XPath.py +7 -1
  9. omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
  10. omlish/antlr/delimit.py +106 -0
  11. omlish/antlr/dot.py +31 -0
  12. omlish/antlr/errors.py +11 -0
  13. omlish/antlr/input.py +96 -0
  14. omlish/antlr/parsing.py +19 -0
  15. omlish/antlr/runtime.py +102 -0
  16. omlish/antlr/utils.py +38 -0
  17. omlish/argparse/all.py +45 -0
  18. omlish/{argparse.py → argparse/cli.py} +112 -107
  19. omlish/asyncs/__init__.py +0 -35
  20. omlish/asyncs/all.py +35 -0
  21. omlish/asyncs/asyncio/all.py +7 -0
  22. omlish/asyncs/asyncio/channels.py +40 -0
  23. omlish/asyncs/asyncio/streams.py +45 -0
  24. omlish/asyncs/asyncio/subprocesses.py +238 -0
  25. omlish/asyncs/asyncio/timeouts.py +16 -0
  26. omlish/asyncs/bluelet/LICENSE +6 -0
  27. omlish/asyncs/bluelet/all.py +67 -0
  28. omlish/asyncs/bluelet/api.py +23 -0
  29. omlish/asyncs/bluelet/core.py +178 -0
  30. omlish/asyncs/bluelet/events.py +78 -0
  31. omlish/asyncs/bluelet/files.py +80 -0
  32. omlish/asyncs/bluelet/runner.py +416 -0
  33. omlish/asyncs/bluelet/sockets.py +214 -0
  34. omlish/bootstrap/sys.py +3 -3
  35. omlish/cached.py +2 -2
  36. omlish/check.py +49 -460
  37. omlish/codecs/__init__.py +72 -0
  38. omlish/codecs/base.py +106 -0
  39. omlish/codecs/bytes.py +119 -0
  40. omlish/codecs/chain.py +23 -0
  41. omlish/codecs/funcs.py +39 -0
  42. omlish/codecs/registry.py +139 -0
  43. omlish/codecs/standard.py +4 -0
  44. omlish/codecs/text.py +217 -0
  45. omlish/collections/cache/impl.py +50 -57
  46. omlish/collections/coerce.py +1 -0
  47. omlish/collections/mappings.py +1 -1
  48. omlish/configs/flattening.py +1 -1
  49. omlish/defs.py +1 -1
  50. omlish/diag/_pycharm/runhack.py +8 -2
  51. omlish/diag/procfs.py +8 -8
  52. omlish/docker/__init__.py +0 -36
  53. omlish/docker/all.py +31 -0
  54. omlish/docker/consts.py +4 -0
  55. omlish/{lite/docker.py → docker/detect.py} +18 -0
  56. omlish/docker/{helpers.py → timebomb.py} +0 -21
  57. omlish/formats/cbor.py +31 -0
  58. omlish/formats/cloudpickle.py +31 -0
  59. omlish/formats/codecs.py +93 -0
  60. omlish/formats/json/codecs.py +29 -0
  61. omlish/formats/json/delimted.py +4 -0
  62. omlish/formats/json/stream/errors.py +2 -0
  63. omlish/formats/json/stream/lex.py +12 -6
  64. omlish/formats/json/stream/parse.py +38 -22
  65. omlish/formats/json5.py +31 -0
  66. omlish/formats/pickle.py +31 -0
  67. omlish/formats/repr.py +25 -0
  68. omlish/formats/toml.py +17 -0
  69. omlish/formats/yaml.py +25 -0
  70. omlish/funcs/__init__.py +0 -0
  71. omlish/{genmachine.py → funcs/genmachine.py} +5 -4
  72. omlish/{matchfns.py → funcs/match.py} +1 -1
  73. omlish/funcs/pairs.py +215 -0
  74. omlish/http/__init__.py +0 -48
  75. omlish/http/all.py +48 -0
  76. omlish/http/coro/__init__.py +0 -0
  77. omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
  78. omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
  79. omlish/{lite/http → http}/handlers.py +3 -2
  80. omlish/{lite/http → http}/parsing.py +1 -0
  81. omlish/http/sessions.py +1 -1
  82. omlish/{lite/http → http}/versions.py +1 -0
  83. omlish/inject/managed.py +2 -2
  84. omlish/io/__init__.py +0 -3
  85. omlish/{lite/io.py → io/buffers.py} +8 -9
  86. omlish/io/compress/__init__.py +9 -0
  87. omlish/io/compress/abc.py +104 -0
  88. omlish/io/compress/adapters.py +148 -0
  89. omlish/io/compress/base.py +24 -0
  90. omlish/io/compress/brotli.py +47 -0
  91. omlish/io/compress/bz2.py +61 -0
  92. omlish/io/compress/codecs.py +78 -0
  93. omlish/io/compress/gzip.py +350 -0
  94. omlish/io/compress/lz4.py +91 -0
  95. omlish/io/compress/lzma.py +81 -0
  96. omlish/io/compress/snappy.py +34 -0
  97. omlish/io/compress/zlib.py +74 -0
  98. omlish/io/compress/zstd.py +44 -0
  99. omlish/io/fdio/__init__.py +1 -0
  100. omlish/{lite → io}/fdio/handlers.py +5 -5
  101. omlish/{lite → io}/fdio/kqueue.py +8 -8
  102. omlish/{lite → io}/fdio/manager.py +7 -7
  103. omlish/{lite → io}/fdio/pollers.py +13 -13
  104. omlish/io/generators/__init__.py +56 -0
  105. omlish/io/generators/consts.py +1 -0
  106. omlish/io/generators/direct.py +13 -0
  107. omlish/io/generators/readers.py +189 -0
  108. omlish/io/generators/stepped.py +191 -0
  109. omlish/io/pyio.py +5 -2
  110. omlish/iterators/__init__.py +24 -0
  111. omlish/iterators/iterators.py +132 -0
  112. omlish/iterators/recipes.py +18 -0
  113. omlish/iterators/tools.py +96 -0
  114. omlish/iterators/unique.py +67 -0
  115. omlish/lang/__init__.py +13 -1
  116. omlish/lang/functions.py +11 -2
  117. omlish/lang/generators.py +243 -0
  118. omlish/lang/iterables.py +46 -49
  119. omlish/lang/maybes.py +4 -4
  120. omlish/lite/cached.py +39 -6
  121. omlish/lite/check.py +438 -75
  122. omlish/lite/contextmanagers.py +17 -4
  123. omlish/lite/dataclasses.py +42 -0
  124. omlish/lite/inject.py +28 -45
  125. omlish/lite/logs.py +0 -270
  126. omlish/lite/marshal.py +309 -144
  127. omlish/lite/pycharm.py +47 -0
  128. omlish/lite/reflect.py +33 -0
  129. omlish/lite/resources.py +8 -0
  130. omlish/lite/runtime.py +4 -4
  131. omlish/lite/shlex.py +12 -0
  132. omlish/lite/socketserver.py +2 -2
  133. omlish/lite/strings.py +31 -0
  134. omlish/logs/__init__.py +0 -32
  135. omlish/logs/{_abc.py → abc.py} +0 -1
  136. omlish/logs/all.py +37 -0
  137. omlish/logs/{formatters.py → color.py} +1 -2
  138. omlish/logs/configs.py +7 -38
  139. omlish/logs/filters.py +10 -0
  140. omlish/logs/handlers.py +4 -1
  141. omlish/logs/json.py +56 -0
  142. omlish/logs/proxy.py +99 -0
  143. omlish/logs/standard.py +128 -0
  144. omlish/logs/utils.py +2 -2
  145. omlish/manifests/__init__.py +2 -0
  146. omlish/manifests/load.py +209 -0
  147. omlish/manifests/types.py +17 -0
  148. omlish/marshal/base.py +1 -1
  149. omlish/marshal/factories.py +1 -1
  150. omlish/marshal/forbidden.py +1 -1
  151. omlish/marshal/iterables.py +1 -1
  152. omlish/marshal/literals.py +50 -0
  153. omlish/marshal/mappings.py +1 -1
  154. omlish/marshal/maybes.py +1 -1
  155. omlish/marshal/standard.py +5 -1
  156. omlish/marshal/unions.py +1 -1
  157. omlish/os/__init__.py +0 -0
  158. omlish/os/atomics.py +205 -0
  159. omlish/os/deathsig.py +23 -0
  160. omlish/{os.py → os/files.py} +0 -9
  161. omlish/{lite → os}/journald.py +2 -1
  162. omlish/os/linux.py +484 -0
  163. omlish/os/paths.py +36 -0
  164. omlish/{lite → os}/pidfile.py +1 -0
  165. omlish/os/sizes.py +9 -0
  166. omlish/reflect/__init__.py +3 -0
  167. omlish/reflect/subst.py +2 -1
  168. omlish/reflect/types.py +126 -44
  169. omlish/secrets/pwhash.py +1 -1
  170. omlish/secrets/subprocesses.py +3 -1
  171. omlish/specs/jsonrpc/marshal.py +1 -1
  172. omlish/specs/openapi/marshal.py +1 -1
  173. omlish/sql/alchemy/asyncs.py +1 -1
  174. omlish/sql/queries/__init__.py +9 -1
  175. omlish/sql/queries/building.py +3 -0
  176. omlish/sql/queries/exprs.py +10 -27
  177. omlish/sql/queries/idents.py +48 -10
  178. omlish/sql/queries/names.py +80 -13
  179. omlish/sql/queries/params.py +64 -0
  180. omlish/sql/queries/rendering.py +1 -1
  181. omlish/subprocesses.py +340 -0
  182. omlish/term.py +29 -14
  183. omlish/testing/pytest/marks.py +2 -2
  184. omlish/testing/pytest/plugins/asyncs.py +6 -1
  185. omlish/testing/pytest/plugins/logging.py +1 -1
  186. omlish/testing/pytest/plugins/switches.py +1 -1
  187. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
  188. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
  189. omlish/fnpairs.py +0 -496
  190. omlish/formats/json/cli/__main__.py +0 -11
  191. omlish/formats/json/cli/cli.py +0 -298
  192. omlish/formats/json/cli/formats.py +0 -71
  193. omlish/formats/json/cli/io.py +0 -74
  194. omlish/formats/json/cli/parsing.py +0 -82
  195. omlish/formats/json/cli/processing.py +0 -48
  196. omlish/formats/json/cli/rendering.py +0 -92
  197. omlish/iterators.py +0 -300
  198. omlish/lite/subprocesses.py +0 -130
  199. /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
  200. /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
  201. /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
  202. /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
  203. /omlish/collections/{_abc.py → abc.py} +0 -0
  204. /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
  205. /omlish/io/{_abc.py → abc.py} +0 -0
  206. /omlish/sql/{_abc.py → abc.py} +0 -0
  207. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,12 @@
1
+ import dataclasses as dc
1
2
  import typing as ta
2
3
 
3
4
  from .... import lang
4
- from ....genmachine import GenMachine
5
+ from ....funcs.genmachine import GenMachine
6
+ from .errors import JsonStreamError
5
7
  from .lex import SCALAR_VALUE_TYPES
6
8
  from .lex import VALUE_TOKEN_KINDS
9
+ from .lex import Position
7
10
  from .lex import ScalarValue
8
11
  from .lex import Token
9
12
 
@@ -79,6 +82,13 @@ def yield_parser_events(obj: ta.Any) -> ta.Generator[JsonStreamParserEvent, None
79
82
  ##
80
83
 
81
84
 
85
+ @dc.dataclass()
86
+ class JsonStreamParseError(JsonStreamError):
87
+ message: str
88
+
89
+ pos: Position | None = None
90
+
91
+
82
92
  class JsonStreamObject(list):
83
93
  def __repr__(self) -> str:
84
94
  return f'{self.__class__.__name__}({super().__repr__()})'
@@ -100,29 +110,29 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
100
110
  if tt == 'KEY':
101
111
  self._stack.pop()
102
112
  if not self._stack:
103
- raise self.StateError
113
+ raise JsonStreamParseError('Unexpected key')
104
114
 
105
115
  tt2 = self._stack[-1]
106
116
  if tt2 == 'OBJECT':
107
117
  return ((v,), self._do_after_pair())
108
118
 
109
119
  else:
110
- raise self.StateError
120
+ raise JsonStreamParseError('Unexpected key')
111
121
 
112
122
  elif tt == 'ARRAY':
113
123
  return ((v,), self._do_after_element())
114
124
 
115
125
  else:
116
- raise self.StateError
126
+ raise JsonStreamParseError(f'Unexpected value: {v!r}')
117
127
 
118
128
  #
119
129
 
120
- def _do_value(self):
130
+ def _do_value(self, *, must_be_present: bool = False):
121
131
  try:
122
132
  tok = yield None
123
133
  except GeneratorExit:
124
134
  if self._stack:
125
- raise self.StateError from None
135
+ raise JsonStreamParseError('Expected value') from None
126
136
  else:
127
137
  raise
128
138
 
@@ -141,13 +151,16 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
141
151
  yield y
142
152
  return r
143
153
 
154
+ elif must_be_present:
155
+ raise JsonStreamParseError('Expected value', tok.pos)
156
+
144
157
  elif tok.kind == 'RBRACKET':
145
158
  y, r = self._emit_end_array()
146
159
  yield y
147
160
  return r
148
161
 
149
162
  else:
150
- raise self.StateError
163
+ raise JsonStreamParseError('Expected value', tok.pos)
151
164
 
152
165
  #
153
166
 
@@ -157,19 +170,19 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
157
170
 
158
171
  def _emit_end_object(self):
159
172
  if not self._stack:
160
- raise self.StateError
173
+ raise JsonStreamParseError('Unexpected end object')
161
174
 
162
175
  tt = self._stack.pop()
163
176
  if tt != 'OBJECT':
164
- raise self.StateError
177
+ raise JsonStreamParseError('Unexpected end object')
165
178
 
166
179
  return self._emit_event(EndObject)
167
180
 
168
- def _do_object_body(self):
181
+ def _do_object_body(self, *, must_be_present: bool = False):
169
182
  try:
170
183
  tok = yield None
171
184
  except GeneratorExit:
172
- raise self.StateError from None
185
+ raise JsonStreamParseError('Expected object body') from None
173
186
 
174
187
  if tok.kind == 'STRING':
175
188
  k = tok.value
@@ -177,30 +190,33 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
177
190
  try:
178
191
  tok = yield None
179
192
  except GeneratorExit:
180
- raise self.StateError from None
193
+ raise JsonStreamParseError('Expected key') from None
181
194
  if tok.kind != 'COLON':
182
- raise self.StateError
195
+ raise JsonStreamParseError('Expected colon', tok.pos)
183
196
 
184
197
  yield (Key(k),)
185
198
  self._stack.append('KEY')
186
199
  return self._do_value()
187
200
 
201
+ elif must_be_present:
202
+ raise JsonStreamParseError('Expected value', tok.pos)
203
+
188
204
  elif tok.kind == 'RBRACE':
189
205
  y, r = self._emit_end_object()
190
206
  yield y
191
207
  return r
192
208
 
193
209
  else:
194
- raise self.StateError
210
+ raise JsonStreamParseError('Expected value', tok.pos)
195
211
 
196
212
  def _do_after_pair(self):
197
213
  try:
198
214
  tok = yield None
199
215
  except GeneratorExit:
200
- raise self.StateError from None
216
+ raise JsonStreamParseError('Expected continuation') from None
201
217
 
202
218
  if tok.kind == 'COMMA':
203
- return self._do_object_body()
219
+ return self._do_object_body(must_be_present=True)
204
220
 
205
221
  elif tok.kind == 'RBRACE':
206
222
  y, r = self._emit_end_object()
@@ -208,7 +224,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
208
224
  return r
209
225
 
210
226
  else:
211
- raise self.StateError
227
+ raise JsonStreamParseError('Expected continuation', tok.pos)
212
228
 
213
229
  #
214
230
 
@@ -218,11 +234,11 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
218
234
 
219
235
  def _emit_end_array(self):
220
236
  if not self._stack:
221
- raise self.StateError
237
+ raise JsonStreamParseError('Expected end array')
222
238
 
223
239
  tt = self._stack.pop()
224
240
  if tt != 'ARRAY':
225
- raise self.StateError
241
+ raise JsonStreamParseError('Unexpected end array')
226
242
 
227
243
  return self._emit_event(EndArray)
228
244
 
@@ -230,10 +246,10 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
230
246
  try:
231
247
  tok = yield None
232
248
  except GeneratorExit:
233
- raise self.StateError from None
249
+ raise JsonStreamParseError('Expected continuation') from None
234
250
 
235
251
  if tok.kind == 'COMMA':
236
- return self._do_value()
252
+ return self._do_value(must_be_present=True)
237
253
 
238
254
  elif tok.kind == 'RBRACKET':
239
255
  y, r = self._emit_end_array()
@@ -241,4 +257,4 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
241
257
  return r
242
258
 
243
259
  else:
244
- raise self.StateError
260
+ raise JsonStreamParseError('Expected continuation', tok.pos)
@@ -0,0 +1,31 @@
1
+ import typing as ta
2
+
3
+ from .. import lang
4
+ from .codecs import make_object_lazy_loaded_codec
5
+ from .codecs import make_str_object_codec
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import json5
10
+ else:
11
+ json5 = lang.proxy_import('json5')
12
+
13
+
14
+ ##
15
+
16
+
17
+ def dumps(obj: ta.Any) -> str:
18
+ return json5.dumps(obj)
19
+
20
+
21
+ def loads(s: str) -> ta.Any:
22
+ return json5.loads(s)
23
+
24
+
25
+ ##
26
+
27
+
28
+ JSON5_CODEC = make_str_object_codec('json5', dumps, loads)
29
+
30
+ # @omlish-manifest
31
+ _JSON5_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'JSON5_CODEC', JSON5_CODEC)
@@ -0,0 +1,31 @@
1
+ import typing as ta
2
+
3
+ from .. import lang
4
+ from .codecs import make_bytes_object_codec
5
+ from .codecs import make_object_lazy_loaded_codec
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import pickle
10
+ else:
11
+ pickle = lang.proxy_import('pickle')
12
+
13
+
14
+ ##
15
+
16
+
17
+ def dump(obj: ta.Any) -> bytes:
18
+ return pickle.dumps(obj)
19
+
20
+
21
+ def load(s: bytes) -> ta.Any:
22
+ return pickle.loads(s)
23
+
24
+
25
+ ##
26
+
27
+
28
+ PICKLE_CODEC = make_bytes_object_codec('pickle', dump, load)
29
+
30
+ # @omlish-manifest
31
+ _PICKLE_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'PICKLE_CODEC', PICKLE_CODEC)
omlish/formats/repr.py ADDED
@@ -0,0 +1,25 @@
1
+ import ast
2
+ import typing as ta
3
+
4
+ from .codecs import make_object_lazy_loaded_codec
5
+ from .codecs import make_str_object_codec
6
+
7
+
8
+ ##
9
+
10
+
11
+ def dumps(obj: ta.Any) -> str:
12
+ return repr(obj)
13
+
14
+
15
+ def loads(s: str) -> ta.Any:
16
+ return ast.literal_eval(s)
17
+
18
+
19
+ ##
20
+
21
+
22
+ REPR_CODEC = make_str_object_codec('repr', dumps, loads)
23
+
24
+ # @omlish-manifest
25
+ _REPR_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'REPR_CODEC', REPR_CODEC)
omlish/formats/toml.py ADDED
@@ -0,0 +1,17 @@
1
+ import tomllib
2
+
3
+ from .codecs import make_object_lazy_loaded_codec
4
+ from .codecs import make_str_object_codec
5
+
6
+
7
+ ##
8
+
9
+
10
+ def _dumps(obj):
11
+ raise TypeError('Unsupported')
12
+
13
+
14
+ TOML_CODEC = make_str_object_codec('toml', _dumps, tomllib.loads)
15
+
16
+ # @omlish-manifest
17
+ _TOML_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'TOML_CODEC', TOML_CODEC)
omlish/formats/yaml.py CHANGED
@@ -14,6 +14,8 @@ import typing as ta
14
14
  from .. import check
15
15
  from .. import dataclasses as dc
16
16
  from .. import lang
17
+ from .codecs import make_object_lazy_loaded_codec
18
+ from .codecs import make_str_object_codec
17
19
 
18
20
 
19
21
  if ta.TYPE_CHECKING:
@@ -239,3 +241,26 @@ def full_load(stream): # noqa
239
241
 
240
242
  def full_load_all(stream): # noqa # noqa
241
243
  return load_all(stream, yaml.FullLoader)
244
+
245
+
246
+ ##
247
+
248
+
249
+ def dump(obj, **kwargs):
250
+ return yaml.dump(obj, **kwargs)
251
+
252
+
253
+ ##
254
+
255
+
256
+ YAML_CODEC = make_str_object_codec('yaml', dump, safe_load, aliases=['yml'])
257
+
258
+ # @omlish-manifest
259
+ _YAML_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'YAML_CODEC', YAML_CODEC)
260
+
261
+ #
262
+
263
+ YAML_UNSAFE_CODEC = make_str_object_codec('yaml-unsafe', dump, full_load)
264
+
265
+ # @omlish-manifest
266
+ _YAML_UNSAFE_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'YAML_UNSAFE_CODEC', YAML_UNSAFE_CODEC)
File without changes
@@ -12,7 +12,7 @@ import typing as ta
12
12
  I = ta.TypeVar('I')
13
13
  O = ta.TypeVar('O')
14
14
 
15
- # MachineGen: ta.TypeAlias = ta.Generator[ta.Iterable[O] | None, I, ta.Optional[MachineGen[I, O]]]
15
+ # MachineGen: ta.TypeAlias = ta.Generator[ta.Iterable[O] | None, I | None, ta.Optional[MachineGen[I, O]]]
16
16
  MachineGen: ta.TypeAlias = ta.Generator[ta.Any, ta.Any, ta.Any]
17
17
 
18
18
 
@@ -67,8 +67,7 @@ class GenMachine(ta.Generic[I, O]):
67
67
  return self
68
68
 
69
69
  def __exit__(self, exc_type, exc_val, exc_tb):
70
- if exc_type is None:
71
- self.close()
70
+ self.close()
72
71
 
73
72
  #
74
73
 
@@ -93,8 +92,10 @@ class GenMachine(ta.Generic[I, O]):
93
92
  if self._gen is None:
94
93
  raise GenMachine.ClosedError
95
94
 
95
+ gi: I | None = i
96
96
  try:
97
- while (o := self._gen.send(i)) is not None:
97
+ while (o := self._gen.send(gi)) is not None:
98
+ gi = None
98
99
  yield from o
99
100
 
100
101
  except StopIteration as s:
@@ -8,7 +8,7 @@ import abc
8
8
  import dataclasses as dc
9
9
  import typing as ta
10
10
 
11
- from . import lang
11
+ from .. import lang
12
12
 
13
13
 
14
14
  T = ta.TypeVar('T')
omlish/funcs/pairs.py ADDED
@@ -0,0 +1,215 @@
1
+ import abc
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+ from .. import lang
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import struct as _struct
10
+ else:
11
+ _struct = lang.proxy_import('struct')
12
+
13
+
14
+ ##
15
+
16
+
17
+ F = ta.TypeVar('F')
18
+ T = ta.TypeVar('T')
19
+ U = ta.TypeVar('U')
20
+
21
+
22
+ class FnPair(ta.Generic[F, T], abc.ABC):
23
+ @abc.abstractmethod
24
+ def forward(self, f: F) -> T:
25
+ raise NotImplementedError
26
+
27
+ @abc.abstractmethod
28
+ def backward(self, t: T) -> F:
29
+ raise NotImplementedError
30
+
31
+ ##
32
+
33
+ def __call__(self, f: F) -> T:
34
+ return self.forward(f)
35
+
36
+ def invert(self) -> 'FnPair[T, F]':
37
+ if isinstance(self, Inverted):
38
+ return self.fp
39
+ return Inverted(self)
40
+
41
+ def compose(self, nxt: 'FnPair[T, U]') -> 'FnPair[F, U]':
42
+ return Composite((self, nxt))
43
+
44
+
45
+ ##
46
+
47
+
48
+ @lang.unabstract_class(['forward', 'backward'])
49
+ @dc.dataclass(frozen=True)
50
+ class Simple(FnPair[F, T]):
51
+ forward: ta.Callable[[F], T] # type: ignore
52
+ backward: ta.Callable[[T], F] # type: ignore
53
+
54
+
55
+ of = Simple
56
+
57
+ NOP: FnPair[ta.Any, ta.Any] = of(lang.identity, lang.identity)
58
+
59
+
60
+ ##
61
+
62
+
63
+ @dc.dataclass(frozen=True)
64
+ class Inverted(FnPair[F, T]):
65
+ fp: FnPair[T, F]
66
+
67
+ def forward(self, f: F) -> T:
68
+ return self.fp.backward(f)
69
+
70
+ def backward(self, t: T) -> F:
71
+ return self.fp.forward(t)
72
+
73
+
74
+ ##
75
+
76
+
77
+ @dc.dataclass(frozen=True)
78
+ class Composite(FnPair[F, T]):
79
+ children: ta.Sequence[FnPair]
80
+
81
+ def forward(self, f: F) -> T:
82
+ for c in self.children:
83
+ f = c.forward(f)
84
+ return ta.cast(T, f)
85
+
86
+ def backward(self, t: T) -> F:
87
+ for c in reversed(self.children):
88
+ t = c.backward(t)
89
+ return ta.cast(F, t)
90
+
91
+
92
+ I0 = ta.TypeVar('I0')
93
+ I1 = ta.TypeVar('I1')
94
+ I2 = ta.TypeVar('I2')
95
+ I3 = ta.TypeVar('I3')
96
+ I4 = ta.TypeVar('I4')
97
+
98
+
99
+ @ta.overload
100
+ def compose(
101
+ fp0: FnPair[F, I0],
102
+ f01: FnPair[I0, T],
103
+ ) -> FnPair[F, T]:
104
+ ...
105
+
106
+
107
+ @ta.overload
108
+ def compose(
109
+ fp0: FnPair[F, I0],
110
+ f01: FnPair[I0, I1],
111
+ fp2: FnPair[I1, T],
112
+ ) -> FnPair[F, T]:
113
+ ...
114
+
115
+
116
+ @ta.overload
117
+ def compose(
118
+ fp0: FnPair[F, I0],
119
+ f01: FnPair[I0, I1],
120
+ fp2: FnPair[I1, I2],
121
+ fp3: FnPair[I2, T],
122
+ ) -> FnPair[F, T]:
123
+ ...
124
+
125
+
126
+ @ta.overload
127
+ def compose(
128
+ fp0: FnPair[F, I0],
129
+ f01: FnPair[I0, I1],
130
+ fp2: FnPair[I1, I2],
131
+ fp3: FnPair[I2, I3],
132
+ fp4: FnPair[I3, T],
133
+ ) -> FnPair[F, T]:
134
+ ...
135
+
136
+
137
+ @ta.overload
138
+ def compose(
139
+ fp0: FnPair[F, I0],
140
+ f01: FnPair[I0, I1],
141
+ fp2: FnPair[I1, I2],
142
+ fp3: FnPair[I2, I3],
143
+ fp4: FnPair[I3, I4],
144
+ fp5: FnPair[I4, T],
145
+ ) -> FnPair[F, T]:
146
+ ...
147
+
148
+
149
+ @ta.overload
150
+ def compose(*ps: FnPair) -> FnPair:
151
+ ...
152
+
153
+
154
+ def compose(*ps):
155
+ if not ps:
156
+ return NOP
157
+ if len(ps) == 1:
158
+ return ps[0]
159
+ return Composite(ps)
160
+
161
+
162
+ ##
163
+
164
+
165
+ @dc.dataclass(frozen=True)
166
+ class Optional(FnPair[F | None, T | None]):
167
+ fp: FnPair[F, T]
168
+
169
+ def forward(self, f: F | None) -> T | None:
170
+ return None if f is None else self.fp.forward(f)
171
+
172
+ def backward(self, t: T | None) -> F | None:
173
+ return None if t is None else self.fp.backward(t)
174
+
175
+
176
+ class Lines(FnPair[ta.Sequence[str], str]):
177
+ def forward(self, f: ta.Sequence[str]) -> str:
178
+ return '\n'.join(f)
179
+
180
+ def backward(self, t: str) -> ta.Sequence[str]:
181
+ return t.splitlines()
182
+
183
+
184
+ ##
185
+
186
+
187
+ @dc.dataclass(frozen=True)
188
+ class Struct(FnPair[tuple, bytes]):
189
+ fmt: str
190
+
191
+ def forward(self, f: tuple) -> bytes:
192
+ return _struct.pack(self.fmt, *f)
193
+
194
+ def backward(self, t: bytes) -> tuple:
195
+ return _struct.unpack(self.fmt, t)
196
+
197
+
198
+ ##
199
+
200
+
201
+ Object: ta.TypeAlias = FnPair[ta.Any, T]
202
+ ObjectStr: ta.TypeAlias = Object[str]
203
+ ObjectBytes: ta.TypeAlias = Object[bytes]
204
+
205
+
206
+ class Object_(FnPair[ta.Any, T], lang.Abstract): # noqa
207
+ pass
208
+
209
+
210
+ class ObjectStr_(Object_[str], lang.Abstract): # noqa
211
+ pass
212
+
213
+
214
+ class ObjectBytes_(Object_[bytes], lang.Abstract): # noqa
215
+ pass
omlish/http/__init__.py CHANGED
@@ -1,48 +0,0 @@
1
- from . import consts # noqa
2
-
3
- from .clients import ( # noqa
4
- HttpClient,
5
- HttpClientError,
6
- HttpRequest,
7
- HttpResponse,
8
- HttpxHttpClient,
9
- UrllibHttpClient,
10
- client,
11
- request,
12
- )
13
-
14
- from .cookies import ( # noqa
15
- CookieTooBigError,
16
- dump_cookie,
17
- parse_cookie,
18
- )
19
-
20
- from .dates import ( # noqa
21
- http_date,
22
- parse_date,
23
- )
24
-
25
- from .encodings import ( # noqa
26
- latin1_decode,
27
- latin1_encode,
28
- )
29
-
30
- from .headers import ( # noqa
31
- CanHttpHeaders,
32
- HttpHeaders,
33
- headers,
34
- )
35
-
36
- from .json import ( # noqa
37
- JSON_TAGGER,
38
- JsonTag,
39
- JsonTagger,
40
- json_dumps,
41
- json_loads,
42
- )
43
-
44
- from .multipart import ( # noqa
45
- MultipartData,
46
- MultipartEncoder,
47
- MultipartField,
48
- )
omlish/http/all.py ADDED
@@ -0,0 +1,48 @@
1
+ from . import consts # noqa
2
+
3
+ from .clients import ( # noqa
4
+ HttpClient,
5
+ HttpClientError,
6
+ HttpRequest,
7
+ HttpResponse,
8
+ HttpxHttpClient,
9
+ UrllibHttpClient,
10
+ client,
11
+ request,
12
+ )
13
+
14
+ from .cookies import ( # noqa
15
+ CookieTooBigError,
16
+ dump_cookie,
17
+ parse_cookie,
18
+ )
19
+
20
+ from .dates import ( # noqa
21
+ http_date,
22
+ parse_date,
23
+ )
24
+
25
+ from .encodings import ( # noqa
26
+ latin1_decode,
27
+ latin1_encode,
28
+ )
29
+
30
+ from .headers import ( # noqa
31
+ CanHttpHeaders,
32
+ HttpHeaders,
33
+ headers,
34
+ )
35
+
36
+ from .json import ( # noqa
37
+ JSON_TAGGER,
38
+ JsonTag,
39
+ JsonTagger,
40
+ json_dumps,
41
+ json_loads,
42
+ )
43
+
44
+ from .multipart import ( # noqa
45
+ MultipartData,
46
+ MultipartEncoder,
47
+ MultipartField,
48
+ )
File without changes