omlish 0.0.0.dev423__py3-none-any.whl → 0.0.0.dev484__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.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (464) hide show
  1. omlish/{.manifests.json → .omlish-manifests.json} +12 -0
  2. omlish/__about__.py +21 -18
  3. omlish/argparse/all.py +17 -9
  4. omlish/argparse/cli.py +16 -3
  5. omlish/argparse/utils.py +21 -0
  6. omlish/asyncs/all.py +0 -13
  7. omlish/asyncs/asyncio/rlock.py +110 -0
  8. omlish/asyncs/asyncio/subprocesses.py +2 -2
  9. omlish/asyncs/asyncio/sync.py +43 -0
  10. omlish/asyncs/asyncio/utils.py +2 -0
  11. omlish/asyncs/ioproxy/proxy.py +1 -1
  12. omlish/asyncs/sync.py +25 -0
  13. omlish/bootstrap/_marshal.py +1 -1
  14. omlish/bootstrap/diag.py +12 -21
  15. omlish/bootstrap/main.py +2 -5
  16. omlish/bootstrap/sys.py +27 -28
  17. omlish/c3.py +4 -1
  18. omlish/cexts/include/omlish/omlish.hh +1 -0
  19. omlish/collections/__init__.py +13 -1
  20. omlish/collections/attrregistry.py +210 -0
  21. omlish/collections/cache/impl.py +3 -2
  22. omlish/collections/identity.py +1 -0
  23. omlish/collections/mappings.py +28 -0
  24. omlish/collections/trie.py +5 -1
  25. omlish/collections/utils.py +77 -0
  26. omlish/concurrent/__init__.py +0 -11
  27. omlish/concurrent/all.py +18 -0
  28. omlish/concurrent/futures.py +25 -0
  29. omlish/concurrent/threadlets.py +1 -1
  30. omlish/configs/processing/flattening.py +1 -1
  31. omlish/configs/processing/merging.py +8 -6
  32. omlish/configs/types.py +1 -1
  33. omlish/daemons/__init__.py +70 -0
  34. omlish/daemons/daemon.py +2 -2
  35. omlish/daemons/launching.py +2 -2
  36. omlish/daemons/reparent.py +2 -3
  37. omlish/daemons/spawning.py +2 -3
  38. omlish/dataclasses/__init__.py +5 -5
  39. omlish/dataclasses/errors.py +1 -1
  40. omlish/dataclasses/impl/api/classes/decorator.py +3 -0
  41. omlish/dataclasses/impl/api/classes/make.py +4 -1
  42. omlish/dataclasses/impl/concerns/doc.py +1 -1
  43. omlish/dataclasses/impl/concerns/repr.py +15 -2
  44. omlish/dataclasses/impl/configs.py +97 -36
  45. omlish/dataclasses/impl/generation/compilation.py +21 -19
  46. omlish/dataclasses/impl/generation/globals.py +1 -0
  47. omlish/dataclasses/impl/generation/ops.py +1 -0
  48. omlish/dataclasses/impl/generation/processor.py +105 -24
  49. omlish/dataclasses/impl/processing/base.py +8 -0
  50. omlish/dataclasses/impl/processing/driving.py +8 -8
  51. omlish/dataclasses/specs.py +34 -2
  52. omlish/dataclasses/tools/as_.py +0 -12
  53. omlish/dataclasses/tools/modifiers.py +5 -0
  54. omlish/dataclasses/tools/static.py +1 -1
  55. omlish/diag/_pycharm/runhack.py +1 -1
  56. omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
  57. omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
  58. omlish/diag/{ps.py → cmds/ps.py} +6 -6
  59. omlish/diag/procfs.py +4 -4
  60. omlish/diag/pycharm.py +16 -2
  61. omlish/diag/pydevd.py +58 -40
  62. omlish/diag/replserver/console.py +3 -3
  63. omlish/diag/replserver/server.py +2 -2
  64. omlish/dispatch/__init__.py +18 -12
  65. omlish/dispatch/methods.py +50 -140
  66. omlish/dom/rendering.py +1 -1
  67. omlish/formats/dotenv.py +8 -8
  68. omlish/formats/json/stream/__init__.py +18 -3
  69. omlish/formats/json/stream/building.py +2 -2
  70. omlish/formats/json/stream/lexing.py +401 -67
  71. omlish/formats/json/stream/parsing.py +32 -10
  72. omlish/formats/json/stream/rendering.py +6 -6
  73. omlish/formats/json/stream/utils.py +132 -30
  74. omlish/formats/json5/literals.py +7 -4
  75. omlish/formats/json5/parsing.py +33 -79
  76. omlish/formats/json5/stream.py +77 -0
  77. omlish/formats/logfmt.py +8 -2
  78. omlish/funcs/genmachine.py +2 -2
  79. omlish/funcs/guard.py +225 -0
  80. omlish/graphs/dot/rendering.py +1 -1
  81. omlish/http/all.py +122 -53
  82. omlish/http/asgi.py +2 -2
  83. omlish/http/clients/__init__.py +0 -34
  84. omlish/http/clients/asyncs.py +153 -0
  85. omlish/http/clients/base.py +63 -122
  86. omlish/http/clients/coro/sync.py +171 -0
  87. omlish/http/clients/default.py +209 -30
  88. omlish/http/clients/executor.py +56 -0
  89. omlish/http/clients/httpx.py +78 -13
  90. omlish/http/clients/middleware.py +181 -0
  91. omlish/http/clients/sync.py +151 -0
  92. omlish/http/clients/syncasync.py +49 -0
  93. omlish/http/clients/urllib.py +8 -5
  94. omlish/http/coro/client/{client.py → connection.py} +43 -37
  95. omlish/http/coro/client/headers.py +5 -5
  96. omlish/http/coro/client/response.py +37 -38
  97. omlish/http/coro/client/status.py +4 -4
  98. omlish/http/coro/{client/io.py → io.py} +19 -2
  99. omlish/http/coro/server/fdio.py +10 -9
  100. omlish/http/coro/server/server.py +14 -41
  101. omlish/http/coro/server/sockets.py +7 -6
  102. omlish/http/flasky/__init__.py +40 -0
  103. omlish/http/flasky/_compat.py +2 -0
  104. omlish/http/flasky/api.py +82 -0
  105. omlish/http/flasky/app.py +203 -0
  106. omlish/http/flasky/cvs.py +59 -0
  107. omlish/http/flasky/requests.py +20 -0
  108. omlish/http/flasky/responses.py +23 -0
  109. omlish/http/flasky/routes.py +23 -0
  110. omlish/http/flasky/types.py +15 -0
  111. omlish/http/handlers.py +3 -2
  112. omlish/http/headers.py +69 -35
  113. omlish/http/sse.py +1 -1
  114. omlish/http/urls.py +67 -0
  115. omlish/inject/__init__.py +173 -126
  116. omlish/inject/_dataclasses.py +4986 -0
  117. omlish/inject/binder.py +10 -49
  118. omlish/inject/elements.py +27 -0
  119. omlish/inject/{utils.py → helpers/constfn.py} +3 -3
  120. omlish/inject/{tags.py → helpers/id.py} +2 -2
  121. omlish/inject/helpers/multis.py +143 -0
  122. omlish/inject/helpers/wrappers.py +54 -0
  123. omlish/inject/impl/elements.py +52 -22
  124. omlish/inject/impl/injector.py +76 -49
  125. omlish/inject/impl/inspect.py +11 -1
  126. omlish/inject/impl/maysync.py +43 -0
  127. omlish/inject/impl/multis.py +10 -7
  128. omlish/inject/impl/privates.py +8 -8
  129. omlish/inject/impl/providers.py +23 -34
  130. omlish/inject/impl/providersmap.py +43 -0
  131. omlish/inject/impl/proxy.py +0 -2
  132. omlish/inject/impl/scopes.py +19 -23
  133. omlish/inject/impl/sync.py +41 -0
  134. omlish/inject/injector.py +37 -8
  135. omlish/inject/inspect.py +35 -0
  136. omlish/inject/listeners.py +4 -4
  137. omlish/inject/managed.py +54 -18
  138. omlish/inject/maysync.py +27 -0
  139. omlish/inject/multis.py +8 -0
  140. omlish/inject/overrides.py +3 -3
  141. omlish/inject/privates.py +6 -0
  142. omlish/inject/providers.py +8 -1
  143. omlish/inject/scopes.py +40 -12
  144. omlish/inject/sync.py +49 -0
  145. omlish/io/buffers.py +119 -1
  146. omlish/io/readers.py +29 -0
  147. omlish/iterators/__init__.py +28 -20
  148. omlish/iterators/transforms.py +204 -0
  149. omlish/lang/__init__.py +240 -129
  150. omlish/lang/_asyncs.cc +186 -0
  151. omlish/lang/asyncs.py +67 -43
  152. omlish/lang/{attrs.py → attrstorage.py} +15 -15
  153. omlish/lang/cached/property.py +2 -2
  154. omlish/lang/casing.py +11 -0
  155. omlish/lang/classes/bindable.py +2 -3
  156. omlish/lang/classes/restrict.py +8 -0
  157. omlish/lang/classes/simple.py +26 -4
  158. omlish/lang/collections.py +1 -1
  159. omlish/lang/contextmanagers.py +59 -9
  160. omlish/lang/functions.py +31 -33
  161. omlish/lang/imports/_capture.cc +103 -0
  162. omlish/lang/imports/capture.py +902 -0
  163. omlish/lang/imports/lazy.py +0 -25
  164. omlish/lang/imports/proxy.py +559 -0
  165. omlish/lang/iterables.py +2 -2
  166. omlish/lang/lazyglobals.py +49 -14
  167. omlish/lang/maybes.py +2 -1
  168. omlish/lang/maysync.py +2 -2
  169. omlish/lang/params.py +17 -0
  170. omlish/lang/recursion.py +0 -1
  171. omlish/lang/resources.py +1 -1
  172. omlish/lang/sequences.py +124 -0
  173. omlish/lifecycles/contextmanagers.py +1 -2
  174. omlish/lifecycles/controller.py +1 -2
  175. omlish/lite/abstract.py +54 -24
  176. omlish/lite/asyncs.py +146 -0
  177. omlish/lite/attrops.py +415 -0
  178. omlish/lite/cached.py +57 -1
  179. omlish/lite/contextmanagers.py +4 -4
  180. omlish/lite/dataclasses.py +55 -0
  181. omlish/lite/inject.py +5 -4
  182. omlish/lite/marshal.py +1 -0
  183. omlish/lite/maybes.py +10 -2
  184. omlish/lite/maysync.py +22 -5
  185. omlish/lite/pycharm.py +1 -1
  186. omlish/lite/strings.py +0 -7
  187. omlish/lite/timing.py +6 -3
  188. omlish/lite/typing.py +6 -0
  189. omlish/logs/_amalg.py +8 -0
  190. omlish/logs/all.py +59 -31
  191. omlish/logs/base.py +204 -0
  192. omlish/logs/contexts.py +171 -0
  193. omlish/logs/formatters.py +13 -0
  194. omlish/logs/infos.py +377 -0
  195. omlish/logs/levels.py +97 -0
  196. omlish/logs/modules.py +13 -0
  197. omlish/logs/protocols.py +32 -0
  198. omlish/logs/standard.py +20 -15
  199. omlish/logs/std/configs.py +29 -0
  200. omlish/logs/{filters.py → std/filters.py} +1 -1
  201. omlish/logs/std/formatters.py +25 -0
  202. omlish/logs/std/handlers.py +19 -0
  203. omlish/logs/{json.py → std/json.py} +2 -2
  204. omlish/logs/std/loggers.py +48 -0
  205. omlish/logs/{proxy.py → std/proxy.py} +3 -3
  206. omlish/logs/std/records.py +671 -0
  207. omlish/logs/typed/bindings.py +108 -37
  208. omlish/logs/typed/types.py +17 -1
  209. omlish/logs/typed/values.py +2 -2
  210. omlish/logs/utils.py +60 -4
  211. omlish/logs/warnings.py +8 -0
  212. omlish/manifests/loading.py +8 -1
  213. omlish/marshal/__init__.py +54 -22
  214. omlish/marshal/_dataclasses.py +2774 -0
  215. omlish/marshal/base/configs.py +12 -0
  216. omlish/marshal/base/contexts.py +36 -21
  217. omlish/marshal/base/funcs.py +8 -11
  218. omlish/marshal/base/options.py +8 -0
  219. omlish/marshal/base/registries.py +146 -44
  220. omlish/marshal/base/types.py +40 -16
  221. omlish/marshal/composite/iterables.py +33 -20
  222. omlish/marshal/composite/literals.py +20 -18
  223. omlish/marshal/composite/mappings.py +36 -23
  224. omlish/marshal/composite/maybes.py +29 -19
  225. omlish/marshal/composite/newtypes.py +16 -16
  226. omlish/marshal/composite/optionals.py +14 -14
  227. omlish/marshal/composite/special.py +15 -15
  228. omlish/marshal/composite/unions/literals.py +93 -0
  229. omlish/marshal/composite/unions/primitives.py +103 -0
  230. omlish/marshal/factories/invalidate.py +18 -68
  231. omlish/marshal/factories/method.py +26 -0
  232. omlish/marshal/factories/moduleimport/factories.py +22 -65
  233. omlish/marshal/factories/multi.py +13 -25
  234. omlish/marshal/factories/recursive.py +42 -56
  235. omlish/marshal/factories/typecache.py +29 -74
  236. omlish/marshal/factories/typemap.py +42 -43
  237. omlish/marshal/objects/dataclasses.py +129 -106
  238. omlish/marshal/objects/marshal.py +18 -14
  239. omlish/marshal/objects/namedtuples.py +48 -42
  240. omlish/marshal/objects/unmarshal.py +19 -15
  241. omlish/marshal/polymorphism/marshal.py +9 -11
  242. omlish/marshal/polymorphism/metadata.py +16 -5
  243. omlish/marshal/polymorphism/standard.py +13 -1
  244. omlish/marshal/polymorphism/unions.py +15 -105
  245. omlish/marshal/polymorphism/unmarshal.py +9 -10
  246. omlish/marshal/singular/enums.py +14 -18
  247. omlish/marshal/standard.py +10 -6
  248. omlish/marshal/trivial/any.py +1 -1
  249. omlish/marshal/trivial/forbidden.py +21 -26
  250. omlish/math/fixed.py +2 -2
  251. omlish/metadata.py +23 -1
  252. omlish/os/atomics.py +2 -2
  253. omlish/os/forkhooks.py +4 -0
  254. omlish/os/journald.py +3 -3
  255. omlish/os/pidfiles/pinning.py +2 -2
  256. omlish/reflect/ops.py +9 -0
  257. omlish/reflect/types.py +44 -8
  258. omlish/secrets/marshal.py +1 -1
  259. omlish/secrets/secrets.py +6 -3
  260. omlish/sockets/addresses.py +1 -1
  261. omlish/sockets/server/handlers.py +2 -2
  262. omlish/sockets/server/server.py +4 -3
  263. omlish/sockets/server/ssl.py +2 -2
  264. omlish/specs/jmespath/__init__.py +12 -3
  265. omlish/specs/jmespath/_dataclasses.py +2893 -0
  266. omlish/specs/jmespath/ast.py +1 -1
  267. omlish/specs/jsonrpc/__init__.py +13 -0
  268. omlish/specs/jsonrpc/_marshal.py +32 -23
  269. omlish/specs/jsonrpc/conns.py +10 -7
  270. omlish/specs/jsonschema/_marshal.py +1 -1
  271. omlish/specs/jsonschema/keywords/__init__.py +7 -0
  272. omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
  273. omlish/specs/openapi/_marshal.py +31 -22
  274. omlish/sql/__init__.py +15 -20
  275. omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
  276. omlish/sql/queries/_marshal.py +3 -3
  277. omlish/sql/queries/params.py +1 -1
  278. omlish/sql/queries/rendering.py +1 -1
  279. omlish/sql/tabledefs/_marshal.py +1 -1
  280. omlish/subprocesses/all.py +135 -0
  281. omlish/subprocesses/base.py +8 -3
  282. omlish/subprocesses/editor.py +1 -1
  283. omlish/sync.py +181 -20
  284. omlish/term/alt.py +60 -0
  285. omlish/term/confirm.py +8 -8
  286. omlish/term/pager.py +235 -0
  287. omlish/term/terminfo.py +935 -0
  288. omlish/term/termstate.py +67 -0
  289. omlish/term/vt100/terminal.py +0 -3
  290. omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
  291. omlish/testing/pytest/plugins/skips.py +2 -5
  292. omlish/testing/unittest/main.py +3 -3
  293. omlish/text/docwrap/__init__.py +3 -0
  294. omlish/text/docwrap/__main__.py +11 -0
  295. omlish/text/docwrap/api.py +83 -0
  296. omlish/text/docwrap/cli.py +86 -0
  297. omlish/text/docwrap/groups.py +84 -0
  298. omlish/text/docwrap/lists.py +167 -0
  299. omlish/text/docwrap/parts.py +146 -0
  300. omlish/text/docwrap/reflowing.py +106 -0
  301. omlish/text/docwrap/rendering.py +151 -0
  302. omlish/text/docwrap/utils.py +11 -0
  303. omlish/text/docwrap/wrapping.py +59 -0
  304. omlish/text/filecache.py +2 -2
  305. omlish/text/lorem.py +6 -0
  306. omlish/text/parts.py +2 -2
  307. omlish/text/textwrap.py +51 -0
  308. omlish/typedvalues/__init__.py +1 -1
  309. omlish/typedvalues/marshal.py +85 -59
  310. omlish/typedvalues/values.py +2 -1
  311. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/METADATA +36 -38
  312. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/RECORD +323 -385
  313. omlish/asyncs/bluelet/LICENSE +0 -6
  314. omlish/asyncs/bluelet/all.py +0 -67
  315. omlish/asyncs/bluelet/api.py +0 -23
  316. omlish/asyncs/bluelet/core.py +0 -178
  317. omlish/asyncs/bluelet/events.py +0 -79
  318. omlish/asyncs/bluelet/files.py +0 -80
  319. omlish/asyncs/bluelet/runner.py +0 -417
  320. omlish/asyncs/bluelet/sockets.py +0 -216
  321. omlish/asyncs/bridge.py +0 -359
  322. omlish/asyncs/utils.py +0 -18
  323. omlish/dataclasses/impl/generation/mangling.py +0 -18
  324. omlish/defs.py +0 -216
  325. omlish/dispatch/_dispatch2.py +0 -69
  326. omlish/dispatch/_dispatch3.py +0 -108
  327. omlish/dynamic.py +0 -219
  328. omlish/formats/json/Json.g4 +0 -77
  329. omlish/formats/json/_antlr/JsonLexer.py +0 -109
  330. omlish/formats/json/_antlr/JsonListener.py +0 -61
  331. omlish/formats/json/_antlr/JsonParser.py +0 -457
  332. omlish/formats/json/_antlr/JsonVisitor.py +0 -42
  333. omlish/formats/json5/Json5.g4 +0 -168
  334. omlish/formats/json5/_antlr/Json5Lexer.py +0 -354
  335. omlish/formats/json5/_antlr/Json5Listener.py +0 -79
  336. omlish/formats/json5/_antlr/Json5Parser.py +0 -617
  337. omlish/formats/json5/_antlr/Json5Visitor.py +0 -52
  338. omlish/funcs/match.py +0 -227
  339. omlish/io/trampoline.py +0 -289
  340. omlish/lang/imports/proxyinit.py +0 -665
  341. omlish/lite/logs.py +0 -4
  342. omlish/lite/reprs.py +0 -85
  343. omlish/logs/abc.py +0 -319
  344. omlish/logs/callers.py +0 -67
  345. omlish/logs/color.py +0 -27
  346. omlish/logs/configs.py +0 -29
  347. omlish/logs/handlers.py +0 -17
  348. omlish/logs/protocol.py +0 -218
  349. omlish/logs/timing.py +0 -58
  350. omlish/marshal/factories/match.py +0 -34
  351. omlish/marshal/factories/simple.py +0 -28
  352. omlish/specs/irc/messages/base.py +0 -49
  353. omlish/specs/irc/messages/formats.py +0 -92
  354. omlish/specs/irc/messages/messages.py +0 -774
  355. omlish/specs/irc/messages/parsing.py +0 -98
  356. omlish/specs/irc/numerics/formats.py +0 -97
  357. omlish/specs/irc/numerics/numerics.py +0 -865
  358. omlish/specs/irc/numerics/types.py +0 -59
  359. omlish/specs/irc/protocol/LICENSE +0 -11
  360. omlish/specs/irc/protocol/__init__.py +0 -61
  361. omlish/specs/irc/protocol/consts.py +0 -6
  362. omlish/specs/irc/protocol/errors.py +0 -30
  363. omlish/specs/irc/protocol/message.py +0 -21
  364. omlish/specs/irc/protocol/nuh.py +0 -55
  365. omlish/specs/irc/protocol/parsing.py +0 -158
  366. omlish/specs/irc/protocol/rendering.py +0 -153
  367. omlish/specs/irc/protocol/tags.py +0 -102
  368. omlish/specs/irc/protocol/utils.py +0 -30
  369. omlish/specs/proto/Protobuf3.g4 +0 -396
  370. omlish/specs/proto/__init__.py +0 -0
  371. omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
  372. omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
  373. omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
  374. omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
  375. omlish/specs/proto/_antlr/__init__.py +0 -0
  376. omlish/specs/proto/nodes.py +0 -54
  377. omlish/specs/proto/parsing.py +0 -97
  378. omlish/sql/parsing/Minisql.g4 +0 -292
  379. omlish/sql/parsing/__init__.py +0 -0
  380. omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
  381. omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
  382. omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
  383. omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
  384. omlish/sql/parsing/_antlr/__init__.py +0 -0
  385. omlish/sql/parsing/parsing.py +0 -119
  386. omlish/text/antlr/__init__.py +0 -3
  387. omlish/text/antlr/_runtime/BufferedTokenStream.py +0 -305
  388. omlish/text/antlr/_runtime/CommonTokenFactory.py +0 -64
  389. omlish/text/antlr/_runtime/CommonTokenStream.py +0 -90
  390. omlish/text/antlr/_runtime/FileStream.py +0 -30
  391. omlish/text/antlr/_runtime/InputStream.py +0 -90
  392. omlish/text/antlr/_runtime/IntervalSet.py +0 -183
  393. omlish/text/antlr/_runtime/LICENSE.txt +0 -28
  394. omlish/text/antlr/_runtime/LL1Analyzer.py +0 -176
  395. omlish/text/antlr/_runtime/Lexer.py +0 -332
  396. omlish/text/antlr/_runtime/ListTokenSource.py +0 -147
  397. omlish/text/antlr/_runtime/Parser.py +0 -583
  398. omlish/text/antlr/_runtime/ParserInterpreter.py +0 -173
  399. omlish/text/antlr/_runtime/ParserRuleContext.py +0 -189
  400. omlish/text/antlr/_runtime/PredictionContext.py +0 -632
  401. omlish/text/antlr/_runtime/Recognizer.py +0 -150
  402. omlish/text/antlr/_runtime/RuleContext.py +0 -230
  403. omlish/text/antlr/_runtime/StdinStream.py +0 -14
  404. omlish/text/antlr/_runtime/Token.py +0 -158
  405. omlish/text/antlr/_runtime/TokenStreamRewriter.py +0 -258
  406. omlish/text/antlr/_runtime/Utils.py +0 -36
  407. omlish/text/antlr/_runtime/__init__.py +0 -2
  408. omlish/text/antlr/_runtime/_all.py +0 -24
  409. omlish/text/antlr/_runtime/_pygrun.py +0 -174
  410. omlish/text/antlr/_runtime/atn/ATN.py +0 -135
  411. omlish/text/antlr/_runtime/atn/ATNConfig.py +0 -162
  412. omlish/text/antlr/_runtime/atn/ATNConfigSet.py +0 -215
  413. omlish/text/antlr/_runtime/atn/ATNDeserializationOptions.py +0 -27
  414. omlish/text/antlr/_runtime/atn/ATNDeserializer.py +0 -449
  415. omlish/text/antlr/_runtime/atn/ATNSimulator.py +0 -50
  416. omlish/text/antlr/_runtime/atn/ATNState.py +0 -267
  417. omlish/text/antlr/_runtime/atn/ATNType.py +0 -20
  418. omlish/text/antlr/_runtime/atn/LexerATNSimulator.py +0 -573
  419. omlish/text/antlr/_runtime/atn/LexerAction.py +0 -301
  420. omlish/text/antlr/_runtime/atn/LexerActionExecutor.py +0 -146
  421. omlish/text/antlr/_runtime/atn/ParserATNSimulator.py +0 -1664
  422. omlish/text/antlr/_runtime/atn/PredictionMode.py +0 -502
  423. omlish/text/antlr/_runtime/atn/SemanticContext.py +0 -333
  424. omlish/text/antlr/_runtime/atn/Transition.py +0 -271
  425. omlish/text/antlr/_runtime/atn/__init__.py +0 -4
  426. omlish/text/antlr/_runtime/dfa/DFA.py +0 -136
  427. omlish/text/antlr/_runtime/dfa/DFASerializer.py +0 -76
  428. omlish/text/antlr/_runtime/dfa/DFAState.py +0 -129
  429. omlish/text/antlr/_runtime/dfa/__init__.py +0 -4
  430. omlish/text/antlr/_runtime/error/DiagnosticErrorListener.py +0 -111
  431. omlish/text/antlr/_runtime/error/ErrorListener.py +0 -75
  432. omlish/text/antlr/_runtime/error/ErrorStrategy.py +0 -712
  433. omlish/text/antlr/_runtime/error/Errors.py +0 -176
  434. omlish/text/antlr/_runtime/error/__init__.py +0 -4
  435. omlish/text/antlr/_runtime/tree/Chunk.py +0 -33
  436. omlish/text/antlr/_runtime/tree/ParseTreeMatch.py +0 -121
  437. omlish/text/antlr/_runtime/tree/ParseTreePattern.py +0 -75
  438. omlish/text/antlr/_runtime/tree/ParseTreePatternMatcher.py +0 -377
  439. omlish/text/antlr/_runtime/tree/RuleTagToken.py +0 -53
  440. omlish/text/antlr/_runtime/tree/TokenTagToken.py +0 -50
  441. omlish/text/antlr/_runtime/tree/Tree.py +0 -194
  442. omlish/text/antlr/_runtime/tree/Trees.py +0 -114
  443. omlish/text/antlr/_runtime/tree/__init__.py +0 -2
  444. omlish/text/antlr/_runtime/xpath/XPath.py +0 -278
  445. omlish/text/antlr/_runtime/xpath/XPathLexer.py +0 -98
  446. omlish/text/antlr/_runtime/xpath/__init__.py +0 -4
  447. omlish/text/antlr/delimit.py +0 -109
  448. omlish/text/antlr/dot.py +0 -41
  449. omlish/text/antlr/errors.py +0 -14
  450. omlish/text/antlr/input.py +0 -96
  451. omlish/text/antlr/parsing.py +0 -54
  452. omlish/text/antlr/runtime.py +0 -102
  453. omlish/text/antlr/utils.py +0 -38
  454. /omlish/{asyncs/bluelet → cexts}/__init__.py +0 -0
  455. /omlish/{formats/json/_antlr → diag/cmds}/__init__.py +0 -0
  456. /omlish/{formats/json5/_antlr → http/clients/coro}/__init__.py +0 -0
  457. /omlish/{specs/irc → inject/helpers}/__init__.py +0 -0
  458. /omlish/{specs/irc/messages → logs/std}/__init__.py +0 -0
  459. /omlish/logs/{noisy.py → std/noisy.py} +0 -0
  460. /omlish/{specs/irc/numerics → marshal/composite/unions}/__init__.py +0 -0
  461. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/WHEEL +0 -0
  462. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/entry_points.txt +0 -0
  463. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/licenses/LICENSE +0 -0
  464. {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/top_level.txt +0 -0
@@ -1,417 +0,0 @@
1
- # ruff: noqa: UP006 UP007 UP045
2
- # @omlish-lite
3
- # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
- # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
- # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
- """
9
- TODO:
10
- - use fdio
11
- - wrap coros in Tasks :|
12
- - (unit)tests lol
13
- - * subprocesses
14
- - canceling
15
- - timeouts
16
- - task groups
17
- - gather
18
- - locks / semaphores / events / etc
19
- - rename Coro to Bluelet?
20
- - shutdown
21
- - ensure resource cleanup
22
- - run_thread? whatever?
23
-
24
- Subprocs:
25
- - https://github.com/python/cpython/issues/120804 - GH-120804: Remove get_child_watcher and set_child_watcher from
26
- asyncio
27
- - https://github.com/python/cpython/pull/17063/files bpo-38692: Add os.pidfd_open
28
- - clone PidfdChildWatcher + ThreadedChildWatcher
29
- """
30
- import collections
31
- import dataclasses as dc
32
- import errno
33
- import logging
34
- import select
35
- import sys
36
- import time
37
- import traceback
38
- import types
39
- import typing as ta
40
- import weakref
41
-
42
- from .core import BlueletCoro
43
- from .core import BlueletExcInfo
44
- from .core import CoreBlueletEvent
45
- from .core import DelegationBlueletEvent
46
- from .core import ExceptionBlueletEvent
47
- from .core import JoinBlueletEvent
48
- from .core import KillBlueletEvent
49
- from .core import ReturnBlueletEvent
50
- from .core import SleepBlueletEvent
51
- from .core import SpawnBlueletEvent
52
- from .core import ValueBlueletEvent
53
- from .core import _BlueletAwaitableDriver
54
- from .events import BlueletEvent
55
- from .events import BlueletWaitable
56
- from .events import WaitableBlueletEvent
57
-
58
-
59
- ##
60
-
61
-
62
- class BlueletCoroException(Exception): # noqa
63
- def __init__(self, coro: BlueletCoro, exc_info: BlueletExcInfo) -> None:
64
- super().__init__()
65
-
66
- self.coro = coro
67
- self.exc_info = exc_info
68
-
69
- @staticmethod
70
- def _exc_info() -> BlueletExcInfo:
71
- return sys.exc_info() # type: ignore
72
-
73
- @staticmethod
74
- def _reraise(typ: ta.Type[BaseException], exc: BaseException, tb: types.TracebackType) -> ta.NoReturn: # noqa
75
- raise exc.with_traceback(tb)
76
-
77
- def reraise(self) -> ta.NoReturn:
78
- self._reraise(self.exc_info[0], self.exc_info[1], self.exc_info[2])
79
-
80
-
81
- ##
82
-
83
-
84
- def _bluelet_event_select(
85
- events: ta.Iterable[BlueletEvent],
86
- *,
87
- log: ta.Optional[logging.Logger] = None,
88
- ) -> ta.Set[WaitableBlueletEvent]:
89
- """
90
- Perform a select() over all the Events provided, returning the ones ready to be fired. Only WaitableEvents
91
- (including SleepEvents) matter here; all other events are ignored (and thus postponed).
92
- """
93
-
94
- waitable_to_event: ta.Dict[ta.Tuple[str, BlueletWaitable], WaitableBlueletEvent] = {}
95
- rlist: ta.List[BlueletWaitable] = []
96
- wlist: ta.List[BlueletWaitable] = []
97
- xlist: ta.List[BlueletWaitable] = []
98
- earliest_wakeup: ta.Optional[float] = None
99
-
100
- # Gather waitables and wakeup times.
101
- for event in events:
102
- if isinstance(event, SleepBlueletEvent):
103
- if not earliest_wakeup:
104
- earliest_wakeup = event.wakeup_time
105
- else:
106
- earliest_wakeup = min(earliest_wakeup, event.wakeup_time)
107
-
108
- elif isinstance(event, WaitableBlueletEvent):
109
- ew = event.waitables()
110
- rlist.extend(ew.r)
111
- wlist.extend(ew.w)
112
- xlist.extend(ew.x)
113
- for waitable in ew.r:
114
- waitable_to_event[('r', waitable)] = event
115
- for waitable in ew.w:
116
- waitable_to_event[('w', waitable)] = event
117
- for waitable in ew.x:
118
- waitable_to_event[('x', waitable)] = event
119
-
120
- # If we have a any sleeping coros, determine how long to sleep.
121
- if earliest_wakeup:
122
- timeout = max(earliest_wakeup - time.time(), 0.)
123
- else:
124
- timeout = None
125
-
126
- # Perform select() if we have any waitables.
127
- if rlist or wlist or xlist:
128
- if log:
129
- log.debug('_bluelet_event_select: +select: %r %r %r %r', rlist, wlist, xlist, timeout)
130
- rready, wready, xready = select.select(rlist, wlist, xlist, timeout)
131
- if log:
132
- log.debug('_bluelet_event_select: -select: %r %r %r', rready, wready, xready)
133
-
134
- else:
135
- rready, wready, xready = [], [], []
136
- if timeout:
137
- if log:
138
- log.debug('_bluelet_event_select: sleep: %r', timeout)
139
- time.sleep(timeout)
140
-
141
- # Gather ready events corresponding to the ready waitables.
142
- ready_events: ta.Set[WaitableBlueletEvent] = set()
143
- for ready in rready:
144
- ready_events.add(waitable_to_event[('r', ready)])
145
- for ready in wready:
146
- ready_events.add(waitable_to_event[('w', ready)])
147
- for ready in xready:
148
- ready_events.add(waitable_to_event[('x', ready)])
149
-
150
- # Gather any finished sleeps.
151
- for event in events:
152
- if isinstance(event, SleepBlueletEvent) and not event.time_left():
153
- ready_events.add(event)
154
-
155
- return ready_events
156
-
157
-
158
- ##
159
-
160
-
161
- class _SuspendedBlueletEvent(CoreBlueletEvent):
162
- pass
163
-
164
-
165
- _BLUELET_SUSPENDED = _SuspendedBlueletEvent() # Special sentinel placeholder for suspended coros.
166
-
167
-
168
- @dc.dataclass(frozen=True, eq=False)
169
- class _DelegatedBlueletEvent(CoreBlueletEvent):
170
- """Placeholder indicating that a coro has delegated execution to a different coro."""
171
-
172
- child: BlueletCoro
173
-
174
-
175
- class _BlueletRunner:
176
- """
177
- Schedules a coroutine, running it to completion. This encapsulates the Bluelet scheduler, which the root coroutine
178
- can add to by spawning new coroutines.
179
- """
180
-
181
- def __init__(
182
- self,
183
- root_coro: BlueletCoro,
184
- *,
185
- log: ta.Optional[logging.Logger] = None,
186
- ) -> None:
187
- super().__init__()
188
-
189
- self._root_coro = root_coro
190
- self._log = log
191
-
192
- # The "coros" dictionary keeps track of all the currently-executing and suspended coroutines. It maps
193
- # coroutines to their currently "blocking" event. The event value may be SUSPENDED if the coroutine is waiting
194
- # on some other condition: namely, a delegated coroutine or a joined coroutine. In this case, the coroutine
195
- # should *also* appear as a value in one of the below dictionaries `delegators` or `joiners`.
196
- self._coros: ta.Dict[BlueletCoro, BlueletEvent] = {self._root_coro: ValueBlueletEvent(None)}
197
-
198
- # Maps child coroutines to delegating parents.
199
- self._delegators: ta.Dict[BlueletCoro, BlueletCoro] = {}
200
-
201
- # Maps child coroutines to joining (exit-waiting) parents.
202
- self._joiners: ta.MutableMapping[BlueletCoro, ta.List[BlueletCoro]] = collections.defaultdict(list)
203
-
204
- # History of spawned coroutines for joining of already completed coroutines.
205
- self._history: ta.MutableMapping[BlueletCoro, ta.Optional[BlueletEvent]] = \
206
- weakref.WeakKeyDictionary({self._root_coro: None})
207
-
208
- def _complete_coro(self, coro: BlueletCoro, return_value: ta.Any) -> None:
209
- """
210
- Remove a coroutine from the scheduling pool, awaking delegators and joiners as necessary and returning the
211
- specified value to any delegating parent.
212
- """
213
-
214
- del self._coros[coro]
215
-
216
- # Resume delegator.
217
- if coro in self._delegators:
218
- self._coros[self._delegators[coro]] = ValueBlueletEvent(return_value)
219
- del self._delegators[coro]
220
-
221
- # Resume joiners.
222
- if coro in self._joiners:
223
- for parent in self._joiners[coro]:
224
- self._coros[parent] = ValueBlueletEvent(None)
225
- del self._joiners[coro]
226
-
227
- def _advance_coro(self, coro: BlueletCoro, value: ta.Any, is_exc: bool = False) -> None:
228
- """
229
- After an event is fired, run a given coroutine associated with it in the coros dict until it yields again. If
230
- the coroutine exits, then the coro is removed from the pool. If the coroutine raises an exception, it is
231
- reraised in a CoroException. If is_exc is True, then the value must be an exc_info tuple and the exception is
232
- thrown into the coroutine.
233
- """
234
-
235
- try:
236
- if is_exc:
237
- next_event = coro.throw(value[0])
238
- else:
239
- next_event = coro.send(value)
240
-
241
- except StopIteration:
242
- # Coro is done.
243
- self._complete_coro(coro, None)
244
-
245
- except BaseException: # noqa
246
- # Coro raised some other exception.
247
- del self._coros[coro]
248
- # Note: Don't use `raise from` as this should support 3.8.
249
- raise BlueletCoroException(coro, BlueletCoroException._exc_info()) # noqa
250
-
251
- else:
252
- if isinstance(next_event, ta.Generator):
253
- # Automatically invoke sub-coroutines. (Shorthand for explicit bluelet.call().)
254
- next_event = DelegationBlueletEvent(next_event)
255
-
256
- if isinstance(next_event, types.CoroutineType): # type: ignore[unreachable]
257
- next_event = DelegationBlueletEvent(_BlueletAwaitableDriver(next_event)()) # type: ignore[unreachable]
258
-
259
- if not isinstance(next_event, BlueletEvent):
260
- raise TypeError(next_event)
261
-
262
- self._coros[coro] = next_event
263
-
264
- def _kill_coro(self, coro: BlueletCoro) -> None:
265
- """Unschedule this coro and its (recursive) delegates."""
266
-
267
- # Collect all coroutines in the delegation stack.
268
- coros = [coro]
269
- while isinstance((cur := self._coros[coro]), _DelegatedBlueletEvent):
270
- coro = cur.child # noqa
271
- coros.append(coro)
272
-
273
- # Complete each coroutine from the top to the bottom of the stack.
274
- for coro in reversed(coros):
275
- self._complete_coro(coro, None)
276
-
277
- def close(self) -> None:
278
- # If any coros still remain, kill them.
279
- for coro in self._coros:
280
- coro.close()
281
-
282
- self._coros.clear()
283
-
284
- def _handle_core_event(self, coro: BlueletCoro, event: CoreBlueletEvent) -> bool:
285
- if self._log:
286
- self._log.debug(f'{self.__class__.__name__}._handle_core_event: %r %r', coro, event)
287
-
288
- if isinstance(event, SpawnBlueletEvent):
289
- sc = ta.cast(BlueletCoro, event.spawned) # FIXME
290
- self._coros[sc] = ValueBlueletEvent(None) # Spawn.
291
- self._history[sc] = None # Record in history.
292
- self._advance_coro(coro, None)
293
- return True
294
-
295
- elif isinstance(event, ValueBlueletEvent):
296
- self._advance_coro(coro, event.value)
297
- return True
298
-
299
- elif isinstance(event, ExceptionBlueletEvent):
300
- self._advance_coro(coro, event.exc_info, True)
301
- return True
302
-
303
- elif isinstance(event, DelegationBlueletEvent):
304
- self._coros[coro] = _DelegatedBlueletEvent(event.spawned) # Suspend.
305
- self._coros[event.spawned] = ValueBlueletEvent(None) # Spawn.
306
- self._history[event.spawned] = None # Record in history.
307
- self._delegators[event.spawned] = coro
308
- return True
309
-
310
- elif isinstance(event, ReturnBlueletEvent):
311
- # Coro is done.
312
- self._complete_coro(coro, event.value)
313
- return True
314
-
315
- elif isinstance(event, JoinBlueletEvent):
316
- if event.child not in self._coros and event.child in self._history:
317
- self._coros[coro] = ValueBlueletEvent(None)
318
- else:
319
- self._coros[coro] = _BLUELET_SUSPENDED # Suspend.
320
- self._joiners[event.child].append(coro)
321
- return True
322
-
323
- elif isinstance(event, KillBlueletEvent):
324
- self._coros[coro] = ValueBlueletEvent(None)
325
- self._kill_coro(event.child)
326
- return True
327
-
328
- elif isinstance(event, (_DelegatedBlueletEvent, _SuspendedBlueletEvent)):
329
- return False
330
-
331
- else:
332
- raise TypeError(event)
333
-
334
- def _step(self) -> ta.Optional[BlueletCoroException]:
335
- if self._log:
336
- self._log.debug(f'{self.__class__.__name__}._step') # Noqa
337
-
338
- try:
339
- # Look for events that can be run immediately. Continue running immediate events until nothing is ready.
340
- while True:
341
- have_ready = False
342
- for coro, event in list(self._coros.items()):
343
- if isinstance(event, CoreBlueletEvent) and not isinstance(event, SleepBlueletEvent):
344
- have_ready |= self._handle_core_event(coro, event)
345
- elif isinstance(event, WaitableBlueletEvent):
346
- pass
347
- else:
348
- raise TypeError(f'Unknown event type: {event}') # noqa
349
-
350
- # Only start the select when nothing else is ready.
351
- if not have_ready:
352
- break
353
-
354
- # Wait and fire.
355
- event2coro = {v: k for k, v in self._coros.items()}
356
- for event in _bluelet_event_select(self._coros.values()):
357
- # Run the IO operation, but catch socket errors.
358
- try:
359
- value = event.fire()
360
- except OSError as exc:
361
- if isinstance(exc.args, tuple) and exc.args[0] == errno.EPIPE:
362
- # Broken pipe. Remote host disconnected.
363
- pass
364
- elif isinstance(exc.args, tuple) and exc.args[0] == errno.ECONNRESET:
365
- # Connection was reset by peer.
366
- pass
367
- else:
368
- traceback.print_exc()
369
- # Abort the coroutine.
370
- self._coros[event2coro[event]] = ReturnBlueletEvent(None)
371
- else:
372
- self._advance_coro(event2coro[event], value)
373
-
374
- except BlueletCoroException as te:
375
- if self._log and self._log.isEnabledFor(logging.DEBUG):
376
- self._log.exception(f'{self.__class__.__name__}._step')
377
-
378
- # Exception raised from inside a coro.
379
- event = ExceptionBlueletEvent(te.exc_info)
380
- if te.coro in self._delegators:
381
- # The coro is a delegate. Raise exception in its delegator.
382
- self._coros[self._delegators[te.coro]] = event
383
- del self._delegators[te.coro]
384
- else:
385
- # The coro is root-level. Raise in client code.
386
- return te
387
-
388
- except BaseException: # noqa
389
- ei = BlueletCoroException._exc_info() # noqa
390
-
391
- if self._log and self._log.isEnabledFor(logging.DEBUG):
392
- self._log.exception(f'{self.__class__.__name__}._step')
393
-
394
- # For instance, KeyboardInterrupt during select(). Raise into root coro and terminate others.
395
- self._coros = {self._root_coro: ExceptionBlueletEvent(ei)} # noqa
396
-
397
- return None
398
-
399
- def run(self) -> None:
400
- # Continue advancing coros until root coro exits.
401
- exit_ce: BlueletCoroException | None = None
402
- while self._coros:
403
- exit_ce = self._step()
404
-
405
- self.close()
406
-
407
- # If we're exiting with an exception, raise it in the client.
408
- if exit_ce:
409
- exit_ce.reraise()
410
-
411
-
412
- ##
413
-
414
-
415
- class _RunnerBlueletApi:
416
- def run(self, root_coro: BlueletCoro) -> None:
417
- _BlueletRunner(root_coro).run()
@@ -1,216 +0,0 @@
1
- # ruff: noqa: UP006 UP007 UP045
2
- # @omlish-lite
3
- # Based on bluelet ( https://github.com/sampsyo/bluelet ) by Adrian Sampson, original license:
4
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
5
- # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
6
- # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
7
- # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
- import dataclasses as dc
9
- import socket
10
- import typing as ta
11
-
12
- from ...lite.abstract import Abstract
13
- from .core import BlueletCoro
14
- from .core import ReturnBlueletEvent
15
- from .core import ValueBlueletEvent
16
- from .core import _CoreBlueletApi
17
- from .events import BlueletEvent
18
- from .events import BlueletWaitables
19
- from .events import WaitableBlueletEvent
20
-
21
-
22
- ##
23
-
24
-
25
- class SocketClosedBlueletError(Exception):
26
- pass
27
-
28
-
29
- class BlueletListener:
30
- """A socket wrapper object for listening sockets."""
31
-
32
- def __init__(self, host: str, port: int) -> None:
33
- """Create a listening socket on the given hostname and port."""
34
-
35
- super().__init__()
36
-
37
- self._closed = False
38
- self.host = host
39
- self.port = port
40
-
41
- self.sock = sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
42
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
43
- sock.bind((host, port))
44
- sock.listen(5)
45
-
46
- def accept(self) -> 'AcceptBlueletEvent':
47
- """
48
- An event that waits for a connection on the listening socket. When a connection is made, the event returns a
49
- Connection object.
50
- """
51
-
52
- if self._closed:
53
- raise SocketClosedBlueletError
54
- return AcceptBlueletEvent(self)
55
-
56
- def close(self) -> None:
57
- """Immediately close the listening socket. (Not an event.)"""
58
-
59
- self._closed = True
60
- self.sock.close()
61
-
62
-
63
- class BlueletConnection:
64
- """A socket wrapper object for connected sockets."""
65
-
66
- def __init__(self, sock: socket.socket, addr: ta.Tuple[str, int]) -> None:
67
- super().__init__()
68
-
69
- self.sock = sock
70
- self.addr = addr
71
- self._buf = bytearray()
72
- self._closed: bool = False
73
-
74
- def close(self) -> None:
75
- """Close the connection."""
76
-
77
- self._closed = True
78
- self.sock.close()
79
-
80
- def recv(self, size: int) -> BlueletEvent:
81
- """Read at most size bytes of data from the socket."""
82
-
83
- if self._closed:
84
- raise SocketClosedBlueletError
85
-
86
- if self._buf:
87
- # We already have data read previously.
88
- out = self._buf[:size]
89
- self._buf = self._buf[size:]
90
- return ValueBlueletEvent(bytes(out))
91
- else:
92
- return ReceiveBlueletEvent(self, size)
93
-
94
- def send(self, data: bytes) -> BlueletEvent:
95
- """Sends data on the socket, returning the number of bytes successfully sent."""
96
-
97
- if self._closed:
98
- raise SocketClosedBlueletError
99
- return SendBlueletEvent(self, data)
100
-
101
- def sendall(self, data: bytes) -> BlueletEvent:
102
- """Send all of data on the socket."""
103
-
104
- if self._closed:
105
- raise SocketClosedBlueletError
106
- return SendBlueletEvent(self, data, True)
107
-
108
- def readline(self, terminator: bytes = b'\n', bufsize: int = 1024) -> BlueletCoro:
109
- """Reads a line (delimited by terminator) from the socket."""
110
-
111
- if self._closed:
112
- raise SocketClosedBlueletError
113
-
114
- while True:
115
- if terminator in self._buf:
116
- line, self._buf = self._buf.split(terminator, 1)
117
- line += terminator
118
- yield ReturnBlueletEvent(bytes(line))
119
- break
120
-
121
- if (data := (yield ReceiveBlueletEvent(self, bufsize))):
122
- self._buf += data
123
- else:
124
- line = self._buf
125
- self._buf = bytearray()
126
- yield ReturnBlueletEvent(bytes(line))
127
- break
128
-
129
-
130
- ##
131
-
132
-
133
- class SocketBlueletEvent(BlueletEvent, Abstract):
134
- pass
135
-
136
-
137
- @dc.dataclass(frozen=True, eq=False)
138
- class AcceptBlueletEvent(WaitableBlueletEvent, SocketBlueletEvent):
139
- """An event for Listener objects (listening sockets) that suspends execution until the socket gets a connection."""
140
-
141
- listener: BlueletListener
142
-
143
- def waitables(self) -> BlueletWaitables:
144
- return BlueletWaitables(r=[self.listener.sock])
145
-
146
- def fire(self) -> BlueletConnection:
147
- sock, addr = self.listener.sock.accept()
148
- return BlueletConnection(sock, addr)
149
-
150
-
151
- @dc.dataclass(frozen=True, eq=False)
152
- class ReceiveBlueletEvent(WaitableBlueletEvent, SocketBlueletEvent):
153
- """An event for Connection objects (connected sockets) for asynchronously reading data."""
154
-
155
- conn: BlueletConnection
156
- bufsize: int
157
-
158
- def waitables(self) -> BlueletWaitables:
159
- return BlueletWaitables(r=[self.conn.sock])
160
-
161
- def fire(self) -> bytes:
162
- return self.conn.sock.recv(self.bufsize)
163
-
164
-
165
- @dc.dataclass(frozen=True, eq=False)
166
- class SendBlueletEvent(WaitableBlueletEvent, SocketBlueletEvent):
167
- """An event for Connection objects (connected sockets) for asynchronously writing data."""
168
-
169
- conn: BlueletConnection
170
- data: bytes
171
- sendall: bool = False
172
-
173
- def waitables(self) -> BlueletWaitables:
174
- return BlueletWaitables(w=[self.conn.sock])
175
-
176
- def fire(self) -> ta.Optional[int]:
177
- if self.sendall:
178
- self.conn.sock.sendall(self.data)
179
- return None
180
- else:
181
- return self.conn.sock.send(self.data)
182
-
183
-
184
- ##
185
-
186
-
187
- class _SocketsBlueletApi(_CoreBlueletApi):
188
- def connect(self, host: str, port: int) -> BlueletEvent:
189
- """Event: connect to a network address and return a Connection object for communicating on the socket."""
190
-
191
- addr = (host, port)
192
- sock = socket.create_connection(addr)
193
- return ValueBlueletEvent(BlueletConnection(sock, addr))
194
-
195
- def server(self, host: str, port: int, func) -> BlueletCoro:
196
- """
197
- A coroutine that runs a network server. Host and port specify the listening address. func should be a coroutine
198
- that takes a single parameter, a Connection object. The coroutine is invoked for every incoming connection on
199
- the listening socket.
200
- """
201
-
202
- def handler(conn):
203
- try:
204
- yield func(conn)
205
- finally:
206
- conn.close()
207
-
208
- listener = BlueletListener(host, port)
209
- try:
210
- while True:
211
- conn = yield listener.accept()
212
- yield self.spawn(handler(conn))
213
- except KeyboardInterrupt:
214
- pass
215
- finally:
216
- listener.close()