omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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