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
@@ -0,0 +1,671 @@
1
+ # ruff: noqa: UP006 UP007 UP045
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - TypedDict?
6
+ """
7
+ import abc
8
+ import collections.abc
9
+ import logging
10
+ import typing as ta
11
+
12
+ from ...lite.abstract import Abstract
13
+ from ..contexts import LoggingContext
14
+ from ..contexts import LoggingContextInfoT
15
+ from ..infos import LoggingContextInfo
16
+ from ..infos import LoggingContextInfos
17
+ from ..infos import LoggingExcInfoTuple
18
+ from ..warnings import LoggingSetupWarning
19
+
20
+
21
+ T = ta.TypeVar('T')
22
+
23
+
24
+ ##
25
+
26
+
27
+ class LoggingContextInfoRecordAdapters:
28
+ # Ref:
29
+ # - https://docs.python.org/3/library/logging.html#logrecord-attributes
30
+ #
31
+ # LogRecord:
32
+ # - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L276 (3.8) # noqa
33
+ # - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L286 (~3.14) # noqa
34
+ #
35
+
36
+ def __new__(cls, *args, **kwargs): # noqa
37
+ raise TypeError
38
+
39
+ class Adapter(Abstract, ta.Generic[T]):
40
+ @property
41
+ @abc.abstractmethod
42
+ def info_cls(self) -> ta.Type[LoggingContextInfo]:
43
+ raise NotImplementedError
44
+
45
+ #
46
+
47
+ @ta.final
48
+ class NOT_SET: # noqa
49
+ def __new__(cls, *args, **kwargs): # noqa
50
+ raise TypeError
51
+
52
+ class RecordAttr(ta.NamedTuple):
53
+ name: str
54
+ type: ta.Any
55
+ default: ta.Any
56
+
57
+ # @abc.abstractmethod
58
+ record_attrs: ta.ClassVar[ta.Mapping[str, RecordAttr]]
59
+
60
+ @property
61
+ @abc.abstractmethod
62
+ def _record_attrs(self) -> ta.Union[
63
+ ta.Mapping[str, ta.Any],
64
+ ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]],
65
+ ]:
66
+ raise NotImplementedError
67
+
68
+ #
69
+
70
+ @abc.abstractmethod
71
+ def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
72
+ raise NotImplementedError
73
+
74
+ #
75
+
76
+ @abc.abstractmethod
77
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[T]:
78
+ raise NotImplementedError
79
+
80
+ #
81
+
82
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
83
+ super().__init_subclass__(**kwargs)
84
+
85
+ if Abstract in cls.__bases__:
86
+ return
87
+
88
+ if 'record_attrs' in cls.__dict__:
89
+ raise TypeError(cls)
90
+ if not isinstance(ra := cls.__dict__['_record_attrs'], collections.abc.Mapping):
91
+ raise TypeError(ra)
92
+
93
+ rd: ta.Dict[str, LoggingContextInfoRecordAdapters.Adapter.RecordAttr] = {}
94
+ for n, v in ra.items():
95
+ if not n or not isinstance(n, str) or n in rd:
96
+ raise AttributeError(n)
97
+ if isinstance(v, tuple):
98
+ t, d = v
99
+ else:
100
+ t, d = v, cls.NOT_SET
101
+ rd[n] = cls.RecordAttr(
102
+ name=n,
103
+ type=t,
104
+ default=d,
105
+ )
106
+ cls.record_attrs = rd
107
+
108
+ class RequiredAdapter(Adapter[T], Abstract):
109
+ @property
110
+ @abc.abstractmethod
111
+ def _record_attrs(self) -> ta.Mapping[str, ta.Any]:
112
+ raise NotImplementedError
113
+
114
+ #
115
+
116
+ @ta.final
117
+ def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
118
+ if (info := ctx.get_info(self.info_cls)) is not None:
119
+ return self._info_to_record(info)
120
+ else:
121
+ raise TypeError # FIXME: fallback?
122
+
123
+ @abc.abstractmethod
124
+ def _info_to_record(self, info: T) -> ta.Mapping[str, ta.Any]:
125
+ raise NotImplementedError
126
+
127
+ #
128
+
129
+ @abc.abstractmethod
130
+ def record_to_info(self, rec: logging.LogRecord) -> T:
131
+ raise NotImplementedError
132
+
133
+ #
134
+
135
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
136
+ super().__init_subclass__(**kwargs)
137
+
138
+ if any(a.default is not cls.NOT_SET for a in cls.record_attrs.values()):
139
+ raise TypeError(cls.record_attrs)
140
+
141
+ class OptionalAdapter(Adapter[T], Abstract, ta.Generic[T]):
142
+ @property
143
+ @abc.abstractmethod
144
+ def _record_attrs(self) -> ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]:
145
+ raise NotImplementedError
146
+
147
+ record_defaults: ta.ClassVar[ta.Mapping[str, ta.Any]]
148
+
149
+ #
150
+
151
+ @ta.final
152
+ def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
153
+ if (info := ctx.get_info(self.info_cls)) is not None:
154
+ return self._info_to_record(info)
155
+ else:
156
+ return self.record_defaults
157
+
158
+ @abc.abstractmethod
159
+ def _info_to_record(self, info: T) -> ta.Mapping[str, ta.Any]:
160
+ raise NotImplementedError
161
+
162
+ #
163
+
164
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
165
+ super().__init_subclass__(**kwargs)
166
+
167
+ dd: ta.Dict[str, ta.Any] = {a.name: a.default for a in cls.record_attrs.values()}
168
+ if any(d is cls.NOT_SET for d in dd.values()):
169
+ raise TypeError(cls.record_attrs)
170
+ cls.record_defaults = dd
171
+
172
+ #
173
+
174
+ class Name(RequiredAdapter[LoggingContextInfos.Name]):
175
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Name]] = LoggingContextInfos.Name
176
+
177
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
178
+ # Name of the logger used to log the call. Unmodified by ctor.
179
+ name=str,
180
+ )
181
+
182
+ def _info_to_record(self, info: LoggingContextInfos.Name) -> ta.Mapping[str, ta.Any]:
183
+ return dict(
184
+ name=info.name,
185
+ )
186
+
187
+ def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Name:
188
+ return LoggingContextInfos.Name(
189
+ name=rec.name,
190
+ )
191
+
192
+ class Level(RequiredAdapter[LoggingContextInfos.Level]):
193
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Level]] = LoggingContextInfos.Level
194
+
195
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
196
+ # Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'). Set to
197
+ # `getLevelName(level)`.
198
+ levelname=str,
199
+
200
+ # Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL). Unmodified by ctor.
201
+ levelno=int,
202
+ )
203
+
204
+ def _info_to_record(self, info: LoggingContextInfos.Level) -> ta.Mapping[str, ta.Any]:
205
+ return dict(
206
+ levelname=info.name,
207
+ levelno=int(info.level),
208
+ )
209
+
210
+ def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Level:
211
+ return LoggingContextInfos.Level.build(rec.levelno)
212
+
213
+ class Msg(RequiredAdapter[LoggingContextInfos.Msg]):
214
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Msg]] = LoggingContextInfos.Msg
215
+
216
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
217
+ # The format string passed in the original logging call. Merged with args to produce message, or an
218
+ # arbitrary object (see Using arbitrary objects as messages). Unmodified by ctor.
219
+ msg=str,
220
+
221
+ # The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge
222
+ # (when there is only one argument, and it is a dictionary). Ctor will transform a 1-tuple containing a
223
+ # Mapping into just the mapping, but is otherwise unmodified.
224
+ args=ta.Union[tuple, dict, None],
225
+ )
226
+
227
+ def _info_to_record(self, info: LoggingContextInfos.Msg) -> ta.Mapping[str, ta.Any]:
228
+ return dict(
229
+ msg=info.msg,
230
+ args=info.args,
231
+ )
232
+
233
+ def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Msg:
234
+ return LoggingContextInfos.Msg(
235
+ msg=rec.msg,
236
+ args=rec.args,
237
+ )
238
+
239
+ class Time(RequiredAdapter[LoggingContextInfos.Time]):
240
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Time]] = LoggingContextInfos.Time
241
+
242
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
243
+ # Time when the LogRecord was created. Set to `time.time_ns() / 1e9` for >=3.13.0b1, otherwise simply
244
+ # `time.time()`.
245
+ #
246
+ # See:
247
+ # - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
248
+ # - https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
249
+ #
250
+ created=float,
251
+
252
+ # Millisecond portion of the time when the LogRecord was created.
253
+ msecs=float,
254
+
255
+ # Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
256
+ relativeCreated=float,
257
+ )
258
+
259
+ def _info_to_record(self, info: LoggingContextInfos.Time) -> ta.Mapping[str, ta.Any]:
260
+ return dict(
261
+ created=info.secs,
262
+ msecs=info.msecs,
263
+ relativeCreated=info.relative_secs,
264
+ )
265
+
266
+ def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Time:
267
+ return LoggingContextInfos.Time.build(
268
+ int(rec.created * 1e9),
269
+ )
270
+
271
+ class Exc(OptionalAdapter[LoggingContextInfos.Exc]):
272
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Exc]] = LoggingContextInfos.Exc
273
+
274
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
275
+ # Exception tuple (à la sys.exc_info) or, if no exception has occurred, None. Unmodified by ctor.
276
+ exc_info=(ta.Optional[LoggingExcInfoTuple], None),
277
+
278
+ # Used to cache the traceback text. Simply set to None by ctor, later set by Formatter.format.
279
+ exc_text=(ta.Optional[str], None),
280
+ )
281
+
282
+ def _info_to_record(self, info: LoggingContextInfos.Exc) -> ta.Mapping[str, ta.Any]:
283
+ return dict(
284
+ exc_info=info.info_tuple,
285
+ exc_text=None,
286
+ )
287
+
288
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Exc]:
289
+ # FIXME:
290
+ # error: Argument 1 to "build" of "Exc" has incompatible type
291
+ # "tuple[type[BaseException], BaseException, TracebackType | None] | tuple[None, None, None] | None"; expected # noqa
292
+ # "BaseException | tuple[type[BaseException], BaseException, TracebackType | None] | bool | None" [arg-type] # noqa
293
+ return LoggingContextInfos.Exc.build(rec.exc_info) # type: ignore[arg-type]
294
+
295
+ class Caller(OptionalAdapter[LoggingContextInfos.Caller]):
296
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Caller]] = LoggingContextInfos.Caller
297
+
298
+ _UNKNOWN_PATH_NAME: ta.ClassVar[str] = '(unknown file)'
299
+ _UNKNOWN_FUNC_NAME: ta.ClassVar[str] = '(unknown function)'
300
+
301
+ _STACK_INFO_PREFIX: ta.ClassVar[str] = 'Stack (most recent call last):\n'
302
+
303
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
304
+ # Full pathname of the source file where the logging call was issued (if available). Unmodified by ctor. May
305
+ # default to "(unknown file)" by Logger.findCaller / Logger._log.
306
+ pathname=(str, _UNKNOWN_PATH_NAME),
307
+
308
+ # Source line number where the logging call was issued (if available). Unmodified by ctor. May default to 0
309
+ # y Logger.findCaller / Logger._log.
310
+ lineno=(int, 0),
311
+
312
+ # Name of function containing the logging call. Set by ctor to `func` arg, unmodified. May default to
313
+ # "(unknown function)" by Logger.findCaller / Logger._log.
314
+ funcName=(str, _UNKNOWN_FUNC_NAME),
315
+
316
+ # Stack frame information (where available) from the bottom of the stack in the current thread, up to and
317
+ # including the stack frame of the logging call which resulted in the creation of this record. Set by ctor
318
+ # to `sinfo` arg, unmodified. Mostly set, if requested, by `Logger.findCaller`, to
319
+ # `traceback.print_stack(f)`, but prepended with the literal "Stack (most recent call last):\n", and
320
+ # stripped of exactly one trailing `\n` if present.
321
+ stack_info=(ta.Optional[str], None),
322
+ )
323
+
324
+ def _info_to_record(self, caller: LoggingContextInfos.Caller) -> ta.Mapping[str, ta.Any]:
325
+ if (sinfo := caller.stack_info) is not None:
326
+ stack_info: ta.Optional[str] = '\n'.join([
327
+ self._STACK_INFO_PREFIX,
328
+ sinfo[1:] if sinfo.endswith('\n') else sinfo,
329
+ ])
330
+ else:
331
+ stack_info = None
332
+
333
+ return dict(
334
+ pathname=caller.file_path,
335
+
336
+ lineno=caller.line_no,
337
+ funcName=caller.func_name,
338
+
339
+ stack_info=stack_info,
340
+ )
341
+
342
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Caller]:
343
+ # FIXME: piecemeal?
344
+ if (
345
+ rec.pathname != self._UNKNOWN_PATH_NAME and
346
+ rec.lineno != 0 and
347
+ rec.funcName != self._UNKNOWN_FUNC_NAME
348
+ ):
349
+ if (sinfo := rec.stack_info) is not None and sinfo.startswith(self._STACK_INFO_PREFIX):
350
+ sinfo = sinfo[len(self._STACK_INFO_PREFIX):]
351
+ return LoggingContextInfos.Caller(
352
+ file_path=rec.pathname,
353
+
354
+ line_no=rec.lineno,
355
+ func_name=rec.funcName,
356
+
357
+ stack_info=sinfo,
358
+ )
359
+
360
+ return None
361
+
362
+ class SourceFile(Adapter[LoggingContextInfos.SourceFile]):
363
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.SourceFile]] = LoggingContextInfos.SourceFile
364
+
365
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
366
+ # Filename portion of pathname. Set to `os.path.basename(pathname)` if successful, otherwise defaults to
367
+ # pathname.
368
+ filename=str,
369
+
370
+ # Module (name portion of filename). Set to `os.path.splitext(filename)[0]`, otherwise defaults to
371
+ # "Unknown module".
372
+ module=str,
373
+ )
374
+
375
+ _UNKNOWN_MODULE: ta.ClassVar[str] = 'Unknown module'
376
+
377
+ def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
378
+ if (info := ctx.get_info(LoggingContextInfos.SourceFile)) is not None:
379
+ return dict(
380
+ filename=info.file_name,
381
+ module=info.module,
382
+ )
383
+
384
+ if (caller := ctx.get_info(LoggingContextInfos.Caller)) is not None:
385
+ return dict(
386
+ filename=caller.file_path,
387
+ module=self._UNKNOWN_MODULE,
388
+ )
389
+
390
+ return dict(
391
+ filename=LoggingContextInfoRecordAdapters.Caller._UNKNOWN_PATH_NAME, # noqa
392
+ module=self._UNKNOWN_MODULE,
393
+ )
394
+
395
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.SourceFile]:
396
+ if (
397
+ rec.module is not None and
398
+ rec.module != self._UNKNOWN_MODULE
399
+ ):
400
+ return LoggingContextInfos.SourceFile(
401
+ file_name=rec.filename,
402
+ module=rec.module, # FIXME: piecemeal?
403
+ )
404
+
405
+ return None
406
+
407
+ class Thread(OptionalAdapter[LoggingContextInfos.Thread]):
408
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Thread]] = LoggingContextInfos.Thread
409
+
410
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
411
+ # Thread ID if available, and `logging.logThreads` is truthy.
412
+ thread=(ta.Optional[int], None),
413
+
414
+ # Thread name if available, and `logging.logThreads` is truthy.
415
+ threadName=(ta.Optional[str], None),
416
+ )
417
+
418
+ def _info_to_record(self, info: LoggingContextInfos.Thread) -> ta.Mapping[str, ta.Any]:
419
+ if logging.logThreads:
420
+ return dict(
421
+ thread=info.ident,
422
+ threadName=info.name,
423
+ )
424
+
425
+ return self.record_defaults
426
+
427
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Thread]:
428
+ if (
429
+ (ident := rec.thread) is not None and
430
+ (name := rec.threadName) is not None
431
+ ):
432
+ return LoggingContextInfos.Thread(
433
+ ident=ident,
434
+ native_id=None,
435
+ name=name,
436
+ )
437
+
438
+ return None
439
+
440
+ class Process(OptionalAdapter[LoggingContextInfos.Process]):
441
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Process]] = LoggingContextInfos.Process
442
+
443
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
444
+ # Process ID if available - that is, if `hasattr(os, 'getpid')` - and `logging.logProcesses` is truthy,
445
+ # otherwise None.
446
+ process=(ta.Optional[int], None),
447
+ )
448
+
449
+ def _info_to_record(self, info: LoggingContextInfos.Process) -> ta.Mapping[str, ta.Any]:
450
+ if logging.logProcesses:
451
+ return dict(
452
+ process=info.pid,
453
+ )
454
+
455
+ return self.record_defaults
456
+
457
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Process]:
458
+ if (
459
+ (pid := rec.process) is not None
460
+ ):
461
+ return LoggingContextInfos.Process(
462
+ pid=pid,
463
+ )
464
+
465
+ return None
466
+
467
+ class Multiprocessing(OptionalAdapter[LoggingContextInfos.Multiprocessing]):
468
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Multiprocessing]] = LoggingContextInfos.Multiprocessing
469
+
470
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
471
+ # Process name if available. Set to None if `logging.logMultiprocessing` is not truthy. Otherwise, set to
472
+ # 'MainProcess', then `sys.modules.get('multiprocessing').current_process().name` if that works, otherwise
473
+ # remains as 'MainProcess'.
474
+ #
475
+ # As noted by stdlib:
476
+ #
477
+ # Errors may occur if multiprocessing has not finished loading yet - e.g. if a custom import hook causes
478
+ # third-party code to run when multiprocessing calls import. See issue 8200 for an example
479
+ #
480
+ processName=(ta.Optional[str], None),
481
+ )
482
+
483
+ def _info_to_record(self, info: LoggingContextInfos.Multiprocessing) -> ta.Mapping[str, ta.Any]:
484
+ if logging.logMultiprocessing:
485
+ return dict(
486
+ processName=info.process_name,
487
+ )
488
+
489
+ return self.record_defaults
490
+
491
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Multiprocessing]:
492
+ if (
493
+ (process_name := rec.processName) is not None
494
+ ):
495
+ return LoggingContextInfos.Multiprocessing(
496
+ process_name=process_name,
497
+ )
498
+
499
+ return None
500
+
501
+ class AsyncioTask(OptionalAdapter[LoggingContextInfos.AsyncioTask]):
502
+ info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.AsyncioTask]] = LoggingContextInfos.AsyncioTask
503
+
504
+ _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Union[ta.Any, ta.Tuple[ta.Any, ta.Any]]]] = dict(
505
+ # Absent <3.12, otherwise asyncio.Task name if available, and `logging.logAsyncioTasks` is truthy. Set to
506
+ # `sys.modules.get('asyncio').current_task().get_name()`, otherwise None.
507
+ taskName=(ta.Optional[str], None),
508
+ )
509
+
510
+ def _info_to_record(self, info: LoggingContextInfos.AsyncioTask) -> ta.Mapping[str, ta.Any]:
511
+ if getattr(logging, 'logAsyncioTasks', None): # Absent <3.12
512
+ return dict(
513
+ taskName=info.name,
514
+ )
515
+
516
+ return self.record_defaults
517
+
518
+ def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.AsyncioTask]:
519
+ if (
520
+ (name := getattr(rec, 'taskName', None)) is not None
521
+ ):
522
+ return LoggingContextInfos.AsyncioTask(
523
+ name=name,
524
+ )
525
+
526
+ return None
527
+
528
+
529
+ _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_: ta.Sequence[LoggingContextInfoRecordAdapters.Adapter] = [ # noqa
530
+ LoggingContextInfoRecordAdapters.Name(),
531
+ LoggingContextInfoRecordAdapters.Level(),
532
+ LoggingContextInfoRecordAdapters.Msg(),
533
+ LoggingContextInfoRecordAdapters.Time(),
534
+ LoggingContextInfoRecordAdapters.Exc(),
535
+ LoggingContextInfoRecordAdapters.Caller(),
536
+ LoggingContextInfoRecordAdapters.SourceFile(),
537
+ LoggingContextInfoRecordAdapters.Thread(),
538
+ LoggingContextInfoRecordAdapters.Process(),
539
+ LoggingContextInfoRecordAdapters.Multiprocessing(),
540
+ LoggingContextInfoRecordAdapters.AsyncioTask(),
541
+ ]
542
+
543
+ _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS: ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfoRecordAdapters.Adapter] = { # noqa
544
+ ad.info_cls: ad for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_
545
+ }
546
+
547
+
548
+ ##
549
+
550
+
551
+ # Formatter:
552
+ # - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L514 (3.8)
553
+ # - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L554 (~3.14) # noqa
554
+ #
555
+ _KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
556
+ # The logged message, computed as msg % args. Set to `record.getMessage()`.
557
+ message=str,
558
+
559
+ # Human-readable time when the LogRecord was created. By default this is of the form '2003-07-08 16:49:45,896' (the
560
+ # numbers after the comma are millisecond portion of the time). Set to `self.formatTime(record, self.datefmt)` if
561
+ # `self.usesTime()`, otherwise unset.
562
+ asctime=str,
563
+
564
+ # Used to cache the traceback text. If unset (falsey) on the record and `exc_info` is truthy, set to
565
+ # `self.formatException(record.exc_info)` - otherwise unmodified.
566
+ exc_text=ta.Optional[str],
567
+ )
568
+
569
+
570
+ ##
571
+
572
+
573
+ _KNOWN_STD_LOGGING_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(
574
+ a for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS.values() for a in ad.record_attrs
575
+ )
576
+
577
+ _KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(_KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS)
578
+
579
+
580
+ class UnknownStdLoggingRecordAttrsWarning(LoggingSetupWarning):
581
+ pass
582
+
583
+
584
+ def _check_std_logging_record_attrs() -> None:
585
+ if (
586
+ len([a for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS.values() for a in ad.record_attrs]) !=
587
+ len(_KNOWN_STD_LOGGING_RECORD_ATTR_SET)
588
+ ):
589
+ raise RuntimeError('Duplicate LoggingContextInfoRecordAdapter record attrs')
590
+
591
+ rec_dct = dict(logging.makeLogRecord({}).__dict__)
592
+
593
+ if (unk_rec_fields := frozenset(rec_dct) - _KNOWN_STD_LOGGING_RECORD_ATTR_SET):
594
+ import warnings # noqa
595
+
596
+ warnings.warn(
597
+ f'Unknown log record attrs detected: {sorted(unk_rec_fields)!r}',
598
+ UnknownStdLoggingRecordAttrsWarning,
599
+ )
600
+
601
+
602
+ _check_std_logging_record_attrs()
603
+
604
+
605
+ ##
606
+
607
+
608
+ class LoggingContextLogRecord(logging.LogRecord):
609
+ # LogRecord.__init__ args:
610
+ # - name: str
611
+ # - level: int
612
+ # - pathname: str - Confusingly referred to as `fn` before the LogRecord ctor. May be empty or "(unknown file)".
613
+ # - lineno: int - May be 0.
614
+ # - msg: str
615
+ # - args: tuple | dict | 1-tuple[dict]
616
+ # - exc_info: LoggingExcInfoTuple | None
617
+ # - func: str | None = None -> funcName
618
+ # - sinfo: str | None = None -> stack_info
619
+ #
620
+
621
+ def __init__(self, *, _logging_context: LoggingContext) -> None: # noqa
622
+ self.__dict__.update(_logging_context=_logging_context)
623
+
624
+ for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_:
625
+ self.__dict__.update(ad.context_to_record(_logging_context))
626
+
627
+ _logging_context: LoggingContext
628
+
629
+ # FIXME: track extra
630
+ # def __setattr__(self, key, value):
631
+ # super().__setattr__(key, value)
632
+
633
+
634
+ ##
635
+
636
+
637
+ @ta.final
638
+ class LogRecordLoggingContext(LoggingContext):
639
+ def __init__(self, rec: logging.LogRecord) -> None:
640
+ if isinstance(rec, LoggingContextLogRecord):
641
+ raise TypeError(rec)
642
+
643
+ self._rec = rec
644
+
645
+ infos: ta.List[LoggingContextInfo] = [
646
+ info
647
+ for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_
648
+ if (info := ad.record_to_info(rec)) is not None
649
+ ]
650
+
651
+ # FIXME:
652
+ # if extra is not None:
653
+ # for key in extra:
654
+ # if (key in ["message", "asctime"]) or (key in rv.__dict__):
655
+ # raise KeyError("Attempt to overwrite %r in LogRecord" % key)
656
+ # rv.__dict__[key] = extra[key]
657
+
658
+ if (extra := {
659
+ a: v
660
+ for a, v in rec.__dict__.items()
661
+ if a not in _KNOWN_STD_LOGGING_RECORD_ATTR_SET
662
+ }):
663
+ infos.append(LoggingContextInfos.Extra(extra))
664
+
665
+ self._infos: ta.Dict[ta.Type[LoggingContextInfo], LoggingContextInfo] = {
666
+ type(info): info
667
+ for info in infos
668
+ }
669
+
670
+ def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
671
+ return self._infos.get(ty)