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.
- omlish/{.manifests.json → .omlish-manifests.json} +12 -0
- omlish/__about__.py +21 -18
- omlish/argparse/all.py +17 -9
- omlish/argparse/cli.py +16 -3
- omlish/argparse/utils.py +21 -0
- omlish/asyncs/all.py +0 -13
- omlish/asyncs/asyncio/rlock.py +110 -0
- omlish/asyncs/asyncio/subprocesses.py +2 -2
- omlish/asyncs/asyncio/sync.py +43 -0
- omlish/asyncs/asyncio/utils.py +2 -0
- omlish/asyncs/ioproxy/proxy.py +1 -1
- omlish/asyncs/sync.py +25 -0
- omlish/bootstrap/_marshal.py +1 -1
- omlish/bootstrap/diag.py +12 -21
- omlish/bootstrap/main.py +2 -5
- omlish/bootstrap/sys.py +27 -28
- omlish/c3.py +4 -1
- omlish/cexts/include/omlish/omlish.hh +1 -0
- omlish/collections/__init__.py +13 -1
- omlish/collections/attrregistry.py +210 -0
- omlish/collections/cache/impl.py +3 -2
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +28 -0
- omlish/collections/trie.py +5 -1
- omlish/collections/utils.py +77 -0
- omlish/concurrent/__init__.py +0 -11
- omlish/concurrent/all.py +18 -0
- omlish/concurrent/futures.py +25 -0
- omlish/concurrent/threadlets.py +1 -1
- omlish/configs/processing/flattening.py +1 -1
- omlish/configs/processing/merging.py +8 -6
- omlish/configs/types.py +1 -1
- omlish/daemons/__init__.py +70 -0
- omlish/daemons/daemon.py +2 -2
- omlish/daemons/launching.py +2 -2
- omlish/daemons/reparent.py +2 -3
- omlish/daemons/spawning.py +2 -3
- omlish/dataclasses/__init__.py +5 -5
- omlish/dataclasses/errors.py +1 -1
- omlish/dataclasses/impl/api/classes/decorator.py +3 -0
- omlish/dataclasses/impl/api/classes/make.py +4 -1
- omlish/dataclasses/impl/concerns/doc.py +1 -1
- omlish/dataclasses/impl/concerns/repr.py +15 -2
- omlish/dataclasses/impl/configs.py +97 -36
- omlish/dataclasses/impl/generation/compilation.py +21 -19
- omlish/dataclasses/impl/generation/globals.py +1 -0
- omlish/dataclasses/impl/generation/ops.py +1 -0
- omlish/dataclasses/impl/generation/processor.py +105 -24
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +8 -8
- omlish/dataclasses/specs.py +34 -2
- omlish/dataclasses/tools/as_.py +0 -12
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/dataclasses/tools/static.py +1 -1
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
- omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
- omlish/diag/{ps.py → cmds/ps.py} +6 -6
- omlish/diag/procfs.py +4 -4
- omlish/diag/pycharm.py +16 -2
- omlish/diag/pydevd.py +58 -40
- omlish/diag/replserver/console.py +3 -3
- omlish/diag/replserver/server.py +2 -2
- omlish/dispatch/__init__.py +18 -12
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/formats/dotenv.py +8 -8
- omlish/formats/json/stream/__init__.py +18 -3
- omlish/formats/json/stream/building.py +2 -2
- omlish/formats/json/stream/lexing.py +401 -67
- omlish/formats/json/stream/parsing.py +32 -10
- omlish/formats/json/stream/rendering.py +6 -6
- omlish/formats/json/stream/utils.py +132 -30
- omlish/formats/json5/literals.py +7 -4
- omlish/formats/json5/parsing.py +33 -79
- omlish/formats/json5/stream.py +77 -0
- omlish/formats/logfmt.py +8 -2
- omlish/funcs/genmachine.py +2 -2
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/http/all.py +122 -53
- omlish/http/asgi.py +2 -2
- omlish/http/clients/__init__.py +0 -34
- omlish/http/clients/asyncs.py +153 -0
- omlish/http/clients/base.py +63 -122
- omlish/http/clients/coro/sync.py +171 -0
- omlish/http/clients/default.py +209 -30
- omlish/http/clients/executor.py +56 -0
- omlish/http/clients/httpx.py +78 -13
- omlish/http/clients/middleware.py +181 -0
- omlish/http/clients/sync.py +151 -0
- omlish/http/clients/syncasync.py +49 -0
- omlish/http/clients/urllib.py +8 -5
- omlish/http/coro/client/{client.py → connection.py} +43 -37
- omlish/http/coro/client/headers.py +5 -5
- omlish/http/coro/client/response.py +37 -38
- omlish/http/coro/client/status.py +4 -4
- omlish/http/coro/{client/io.py → io.py} +19 -2
- omlish/http/coro/server/fdio.py +10 -9
- omlish/http/coro/server/server.py +14 -41
- omlish/http/coro/server/sockets.py +7 -6
- omlish/http/flasky/__init__.py +40 -0
- omlish/http/flasky/_compat.py +2 -0
- omlish/http/flasky/api.py +82 -0
- omlish/http/flasky/app.py +203 -0
- omlish/http/flasky/cvs.py +59 -0
- omlish/http/flasky/requests.py +20 -0
- omlish/http/flasky/responses.py +23 -0
- omlish/http/flasky/routes.py +23 -0
- omlish/http/flasky/types.py +15 -0
- omlish/http/handlers.py +3 -2
- omlish/http/headers.py +69 -35
- omlish/http/sse.py +1 -1
- omlish/http/urls.py +67 -0
- omlish/inject/__init__.py +173 -126
- omlish/inject/_dataclasses.py +4986 -0
- omlish/inject/binder.py +10 -49
- omlish/inject/elements.py +27 -0
- omlish/inject/{utils.py → helpers/constfn.py} +3 -3
- omlish/inject/{tags.py → helpers/id.py} +2 -2
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +52 -22
- omlish/inject/impl/injector.py +76 -49
- omlish/inject/impl/inspect.py +11 -1
- omlish/inject/impl/maysync.py +43 -0
- omlish/inject/impl/multis.py +10 -7
- omlish/inject/impl/privates.py +8 -8
- omlish/inject/impl/providers.py +23 -34
- omlish/inject/impl/providersmap.py +43 -0
- omlish/inject/impl/proxy.py +0 -2
- omlish/inject/impl/scopes.py +19 -23
- omlish/inject/impl/sync.py +41 -0
- omlish/inject/injector.py +37 -8
- omlish/inject/inspect.py +35 -0
- omlish/inject/listeners.py +4 -4
- omlish/inject/managed.py +54 -18
- omlish/inject/maysync.py +27 -0
- omlish/inject/multis.py +8 -0
- omlish/inject/overrides.py +3 -3
- omlish/inject/privates.py +6 -0
- omlish/inject/providers.py +8 -1
- omlish/inject/scopes.py +40 -12
- omlish/inject/sync.py +49 -0
- omlish/io/buffers.py +119 -1
- omlish/io/readers.py +29 -0
- omlish/iterators/__init__.py +28 -20
- omlish/iterators/transforms.py +204 -0
- omlish/lang/__init__.py +240 -129
- omlish/lang/_asyncs.cc +186 -0
- omlish/lang/asyncs.py +67 -43
- omlish/lang/{attrs.py → attrstorage.py} +15 -15
- omlish/lang/cached/property.py +2 -2
- omlish/lang/casing.py +11 -0
- omlish/lang/classes/bindable.py +2 -3
- omlish/lang/classes/restrict.py +8 -0
- omlish/lang/classes/simple.py +26 -4
- omlish/lang/collections.py +1 -1
- omlish/lang/contextmanagers.py +59 -9
- omlish/lang/functions.py +31 -33
- omlish/lang/imports/_capture.cc +103 -0
- omlish/lang/imports/capture.py +902 -0
- omlish/lang/imports/lazy.py +0 -25
- omlish/lang/imports/proxy.py +559 -0
- omlish/lang/iterables.py +2 -2
- omlish/lang/lazyglobals.py +49 -14
- omlish/lang/maybes.py +2 -1
- omlish/lang/maysync.py +2 -2
- omlish/lang/params.py +17 -0
- omlish/lang/recursion.py +0 -1
- omlish/lang/resources.py +1 -1
- omlish/lang/sequences.py +124 -0
- omlish/lifecycles/contextmanagers.py +1 -2
- omlish/lifecycles/controller.py +1 -2
- omlish/lite/abstract.py +54 -24
- omlish/lite/asyncs.py +146 -0
- omlish/lite/attrops.py +415 -0
- omlish/lite/cached.py +57 -1
- omlish/lite/contextmanagers.py +4 -4
- omlish/lite/dataclasses.py +55 -0
- omlish/lite/inject.py +5 -4
- omlish/lite/marshal.py +1 -0
- omlish/lite/maybes.py +10 -2
- omlish/lite/maysync.py +22 -5
- omlish/lite/pycharm.py +1 -1
- omlish/lite/strings.py +0 -7
- omlish/lite/timing.py +6 -3
- omlish/lite/typing.py +6 -0
- omlish/logs/_amalg.py +8 -0
- omlish/logs/all.py +59 -31
- omlish/logs/base.py +204 -0
- omlish/logs/contexts.py +171 -0
- omlish/logs/formatters.py +13 -0
- omlish/logs/infos.py +377 -0
- omlish/logs/levels.py +97 -0
- omlish/logs/modules.py +13 -0
- omlish/logs/protocols.py +32 -0
- omlish/logs/standard.py +20 -15
- omlish/logs/std/configs.py +29 -0
- omlish/logs/{filters.py → std/filters.py} +1 -1
- omlish/logs/std/formatters.py +25 -0
- omlish/logs/std/handlers.py +19 -0
- omlish/logs/{json.py → std/json.py} +2 -2
- omlish/logs/std/loggers.py +48 -0
- omlish/logs/{proxy.py → std/proxy.py} +3 -3
- omlish/logs/std/records.py +671 -0
- omlish/logs/typed/bindings.py +108 -37
- omlish/logs/typed/types.py +17 -1
- omlish/logs/typed/values.py +2 -2
- omlish/logs/utils.py +60 -4
- omlish/logs/warnings.py +8 -0
- omlish/manifests/loading.py +8 -1
- omlish/marshal/__init__.py +54 -22
- omlish/marshal/_dataclasses.py +2774 -0
- omlish/marshal/base/configs.py +12 -0
- omlish/marshal/base/contexts.py +36 -21
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/registries.py +146 -44
- omlish/marshal/base/types.py +40 -16
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +20 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +22 -65
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +29 -74
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/metadata.py +16 -5
- omlish/marshal/polymorphism/standard.py +13 -1
- omlish/marshal/polymorphism/unions.py +15 -105
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +10 -6
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/math/fixed.py +2 -2
- omlish/metadata.py +23 -1
- omlish/os/atomics.py +2 -2
- omlish/os/forkhooks.py +4 -0
- omlish/os/journald.py +3 -3
- omlish/os/pidfiles/pinning.py +2 -2
- omlish/reflect/ops.py +9 -0
- omlish/reflect/types.py +44 -8
- omlish/secrets/marshal.py +1 -1
- omlish/secrets/secrets.py +6 -3
- omlish/sockets/addresses.py +1 -1
- omlish/sockets/server/handlers.py +2 -2
- omlish/sockets/server/server.py +4 -3
- omlish/sockets/server/ssl.py +2 -2
- omlish/specs/jmespath/__init__.py +12 -3
- omlish/specs/jmespath/_dataclasses.py +2893 -0
- omlish/specs/jmespath/ast.py +1 -1
- omlish/specs/jsonrpc/__init__.py +13 -0
- omlish/specs/jsonrpc/_marshal.py +32 -23
- omlish/specs/jsonrpc/conns.py +10 -7
- omlish/specs/jsonschema/_marshal.py +1 -1
- omlish/specs/jsonschema/keywords/__init__.py +7 -0
- omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
- omlish/specs/openapi/_marshal.py +31 -22
- omlish/sql/__init__.py +15 -20
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- omlish/sql/queries/_marshal.py +3 -3
- omlish/sql/queries/params.py +1 -1
- omlish/sql/queries/rendering.py +1 -1
- omlish/sql/tabledefs/_marshal.py +1 -1
- omlish/subprocesses/all.py +135 -0
- omlish/subprocesses/base.py +8 -3
- omlish/subprocesses/editor.py +1 -1
- omlish/sync.py +181 -20
- omlish/term/alt.py +60 -0
- omlish/term/confirm.py +8 -8
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- omlish/term/vt100/terminal.py +0 -3
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- omlish/testing/pytest/plugins/skips.py +2 -5
- omlish/testing/unittest/main.py +3 -3
- omlish/text/docwrap/__init__.py +3 -0
- omlish/text/docwrap/__main__.py +11 -0
- omlish/text/docwrap/api.py +83 -0
- omlish/text/docwrap/cli.py +86 -0
- omlish/text/docwrap/groups.py +84 -0
- omlish/text/docwrap/lists.py +167 -0
- omlish/text/docwrap/parts.py +146 -0
- omlish/text/docwrap/reflowing.py +106 -0
- omlish/text/docwrap/rendering.py +151 -0
- omlish/text/docwrap/utils.py +11 -0
- omlish/text/docwrap/wrapping.py +59 -0
- omlish/text/filecache.py +2 -2
- omlish/text/lorem.py +6 -0
- omlish/text/parts.py +2 -2
- omlish/text/textwrap.py +51 -0
- omlish/typedvalues/__init__.py +1 -1
- omlish/typedvalues/marshal.py +85 -59
- omlish/typedvalues/values.py +2 -1
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/METADATA +36 -38
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/RECORD +323 -385
- omlish/asyncs/bluelet/LICENSE +0 -6
- omlish/asyncs/bluelet/all.py +0 -67
- omlish/asyncs/bluelet/api.py +0 -23
- omlish/asyncs/bluelet/core.py +0 -178
- omlish/asyncs/bluelet/events.py +0 -79
- omlish/asyncs/bluelet/files.py +0 -80
- omlish/asyncs/bluelet/runner.py +0 -417
- omlish/asyncs/bluelet/sockets.py +0 -216
- omlish/asyncs/bridge.py +0 -359
- omlish/asyncs/utils.py +0 -18
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/defs.py +0 -216
- omlish/dispatch/_dispatch2.py +0 -69
- omlish/dispatch/_dispatch3.py +0 -108
- omlish/dynamic.py +0 -219
- omlish/formats/json/Json.g4 +0 -77
- omlish/formats/json/_antlr/JsonLexer.py +0 -109
- omlish/formats/json/_antlr/JsonListener.py +0 -61
- omlish/formats/json/_antlr/JsonParser.py +0 -457
- omlish/formats/json/_antlr/JsonVisitor.py +0 -42
- omlish/formats/json5/Json5.g4 +0 -168
- omlish/formats/json5/_antlr/Json5Lexer.py +0 -354
- omlish/formats/json5/_antlr/Json5Listener.py +0 -79
- omlish/formats/json5/_antlr/Json5Parser.py +0 -617
- omlish/formats/json5/_antlr/Json5Visitor.py +0 -52
- omlish/funcs/match.py +0 -227
- omlish/io/trampoline.py +0 -289
- omlish/lang/imports/proxyinit.py +0 -665
- omlish/lite/logs.py +0 -4
- omlish/lite/reprs.py +0 -85
- omlish/logs/abc.py +0 -319
- omlish/logs/callers.py +0 -67
- omlish/logs/color.py +0 -27
- omlish/logs/configs.py +0 -29
- omlish/logs/handlers.py +0 -17
- omlish/logs/protocol.py +0 -218
- omlish/logs/timing.py +0 -58
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- omlish/specs/irc/messages/base.py +0 -49
- omlish/specs/irc/messages/formats.py +0 -92
- omlish/specs/irc/messages/messages.py +0 -774
- omlish/specs/irc/messages/parsing.py +0 -98
- omlish/specs/irc/numerics/formats.py +0 -97
- omlish/specs/irc/numerics/numerics.py +0 -865
- omlish/specs/irc/numerics/types.py +0 -59
- omlish/specs/irc/protocol/LICENSE +0 -11
- omlish/specs/irc/protocol/__init__.py +0 -61
- omlish/specs/irc/protocol/consts.py +0 -6
- omlish/specs/irc/protocol/errors.py +0 -30
- omlish/specs/irc/protocol/message.py +0 -21
- omlish/specs/irc/protocol/nuh.py +0 -55
- omlish/specs/irc/protocol/parsing.py +0 -158
- omlish/specs/irc/protocol/rendering.py +0 -153
- omlish/specs/irc/protocol/tags.py +0 -102
- omlish/specs/irc/protocol/utils.py +0 -30
- omlish/specs/proto/Protobuf3.g4 +0 -396
- omlish/specs/proto/__init__.py +0 -0
- omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
- omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
- omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
- omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
- omlish/specs/proto/_antlr/__init__.py +0 -0
- omlish/specs/proto/nodes.py +0 -54
- omlish/specs/proto/parsing.py +0 -97
- omlish/sql/parsing/Minisql.g4 +0 -292
- omlish/sql/parsing/__init__.py +0 -0
- omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
- omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
- omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
- omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
- omlish/sql/parsing/_antlr/__init__.py +0 -0
- omlish/sql/parsing/parsing.py +0 -119
- omlish/text/antlr/__init__.py +0 -3
- omlish/text/antlr/_runtime/BufferedTokenStream.py +0 -305
- omlish/text/antlr/_runtime/CommonTokenFactory.py +0 -64
- omlish/text/antlr/_runtime/CommonTokenStream.py +0 -90
- omlish/text/antlr/_runtime/FileStream.py +0 -30
- omlish/text/antlr/_runtime/InputStream.py +0 -90
- omlish/text/antlr/_runtime/IntervalSet.py +0 -183
- omlish/text/antlr/_runtime/LICENSE.txt +0 -28
- omlish/text/antlr/_runtime/LL1Analyzer.py +0 -176
- omlish/text/antlr/_runtime/Lexer.py +0 -332
- omlish/text/antlr/_runtime/ListTokenSource.py +0 -147
- omlish/text/antlr/_runtime/Parser.py +0 -583
- omlish/text/antlr/_runtime/ParserInterpreter.py +0 -173
- omlish/text/antlr/_runtime/ParserRuleContext.py +0 -189
- omlish/text/antlr/_runtime/PredictionContext.py +0 -632
- omlish/text/antlr/_runtime/Recognizer.py +0 -150
- omlish/text/antlr/_runtime/RuleContext.py +0 -230
- omlish/text/antlr/_runtime/StdinStream.py +0 -14
- omlish/text/antlr/_runtime/Token.py +0 -158
- omlish/text/antlr/_runtime/TokenStreamRewriter.py +0 -258
- omlish/text/antlr/_runtime/Utils.py +0 -36
- omlish/text/antlr/_runtime/__init__.py +0 -2
- omlish/text/antlr/_runtime/_all.py +0 -24
- omlish/text/antlr/_runtime/_pygrun.py +0 -174
- omlish/text/antlr/_runtime/atn/ATN.py +0 -135
- omlish/text/antlr/_runtime/atn/ATNConfig.py +0 -162
- omlish/text/antlr/_runtime/atn/ATNConfigSet.py +0 -215
- omlish/text/antlr/_runtime/atn/ATNDeserializationOptions.py +0 -27
- omlish/text/antlr/_runtime/atn/ATNDeserializer.py +0 -449
- omlish/text/antlr/_runtime/atn/ATNSimulator.py +0 -50
- omlish/text/antlr/_runtime/atn/ATNState.py +0 -267
- omlish/text/antlr/_runtime/atn/ATNType.py +0 -20
- omlish/text/antlr/_runtime/atn/LexerATNSimulator.py +0 -573
- omlish/text/antlr/_runtime/atn/LexerAction.py +0 -301
- omlish/text/antlr/_runtime/atn/LexerActionExecutor.py +0 -146
- omlish/text/antlr/_runtime/atn/ParserATNSimulator.py +0 -1664
- omlish/text/antlr/_runtime/atn/PredictionMode.py +0 -502
- omlish/text/antlr/_runtime/atn/SemanticContext.py +0 -333
- omlish/text/antlr/_runtime/atn/Transition.py +0 -271
- omlish/text/antlr/_runtime/atn/__init__.py +0 -4
- omlish/text/antlr/_runtime/dfa/DFA.py +0 -136
- omlish/text/antlr/_runtime/dfa/DFASerializer.py +0 -76
- omlish/text/antlr/_runtime/dfa/DFAState.py +0 -129
- omlish/text/antlr/_runtime/dfa/__init__.py +0 -4
- omlish/text/antlr/_runtime/error/DiagnosticErrorListener.py +0 -111
- omlish/text/antlr/_runtime/error/ErrorListener.py +0 -75
- omlish/text/antlr/_runtime/error/ErrorStrategy.py +0 -712
- omlish/text/antlr/_runtime/error/Errors.py +0 -176
- omlish/text/antlr/_runtime/error/__init__.py +0 -4
- omlish/text/antlr/_runtime/tree/Chunk.py +0 -33
- omlish/text/antlr/_runtime/tree/ParseTreeMatch.py +0 -121
- omlish/text/antlr/_runtime/tree/ParseTreePattern.py +0 -75
- omlish/text/antlr/_runtime/tree/ParseTreePatternMatcher.py +0 -377
- omlish/text/antlr/_runtime/tree/RuleTagToken.py +0 -53
- omlish/text/antlr/_runtime/tree/TokenTagToken.py +0 -50
- omlish/text/antlr/_runtime/tree/Tree.py +0 -194
- omlish/text/antlr/_runtime/tree/Trees.py +0 -114
- omlish/text/antlr/_runtime/tree/__init__.py +0 -2
- omlish/text/antlr/_runtime/xpath/XPath.py +0 -278
- omlish/text/antlr/_runtime/xpath/XPathLexer.py +0 -98
- omlish/text/antlr/_runtime/xpath/__init__.py +0 -4
- omlish/text/antlr/delimit.py +0 -109
- omlish/text/antlr/dot.py +0 -41
- omlish/text/antlr/errors.py +0 -14
- omlish/text/antlr/input.py +0 -96
- omlish/text/antlr/parsing.py +0 -54
- omlish/text/antlr/runtime.py +0 -102
- omlish/text/antlr/utils.py +0 -38
- /omlish/{asyncs/bluelet → cexts}/__init__.py +0 -0
- /omlish/{formats/json/_antlr → diag/cmds}/__init__.py +0 -0
- /omlish/{formats/json5/_antlr → http/clients/coro}/__init__.py +0 -0
- /omlish/{specs/irc → inject/helpers}/__init__.py +0 -0
- /omlish/{specs/irc/messages → logs/std}/__init__.py +0 -0
- /omlish/logs/{noisy.py → std/noisy.py} +0 -0
- /omlish/{specs/irc/numerics → marshal/composite/unions}/__init__.py +0 -0
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev423.dist-info → omlish-0.0.0.dev484.dist-info}/top_level.txt +0 -0
|
@@ -47,9 +47,9 @@ import typing as ta
|
|
|
47
47
|
import urllib.parse
|
|
48
48
|
|
|
49
49
|
from ....lite.check import check
|
|
50
|
+
from ..io import CoroHttpIo
|
|
50
51
|
from .errors import CoroHttpClientErrors
|
|
51
52
|
from .headers import CoroHttpClientHeaders
|
|
52
|
-
from .io import CoroHttpClientIo
|
|
53
53
|
from .response import CoroHttpClientResponse
|
|
54
54
|
from .status import CoroHttpClientStatusLine
|
|
55
55
|
from .validation import CoroHttpClientValidation
|
|
@@ -58,10 +58,7 @@ from .validation import CoroHttpClientValidation
|
|
|
58
58
|
##
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
class CoroHttpClientConnection
|
|
62
|
-
CoroHttpClientErrors,
|
|
63
|
-
CoroHttpClientIo,
|
|
64
|
-
):
|
|
61
|
+
class CoroHttpClientConnection:
|
|
65
62
|
"""
|
|
66
63
|
HTTPConnection goes through a number of "states", which define when a client may legally make another request or
|
|
67
64
|
fetch the response for a particular request. This diagram details these state transitions:
|
|
@@ -119,10 +116,10 @@ class CoroHttpClientConnection(
|
|
|
119
116
|
_http_version = 11
|
|
120
117
|
_http_version_str = 'HTTP/1.1'
|
|
121
118
|
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
HTTP_PORT: ta.ClassVar[int] = 80
|
|
120
|
+
HTTPS_PORT: ta.ClassVar[int] = 443
|
|
124
121
|
|
|
125
|
-
|
|
122
|
+
DEFAULT_PORT: ta.ClassVar[int] = HTTP_PORT
|
|
126
123
|
|
|
127
124
|
class _NOT_SET: # noqa
|
|
128
125
|
def __new__(cls, *args, **kwargs): # noqa
|
|
@@ -142,6 +139,7 @@ class CoroHttpClientConnection(
|
|
|
142
139
|
source_address: ta.Optional[str] = None,
|
|
143
140
|
block_size: int = 8192,
|
|
144
141
|
auto_open: bool = True,
|
|
142
|
+
default_port: ta.Optional[int] = None,
|
|
145
143
|
) -> None:
|
|
146
144
|
super().__init__()
|
|
147
145
|
|
|
@@ -149,6 +147,9 @@ class CoroHttpClientConnection(
|
|
|
149
147
|
self._source_address = source_address
|
|
150
148
|
self._block_size = block_size
|
|
151
149
|
self._auto_open = auto_open
|
|
150
|
+
if default_port is None:
|
|
151
|
+
default_port = self.DEFAULT_PORT
|
|
152
|
+
self._default_port = default_port
|
|
152
153
|
|
|
153
154
|
self._connected = False
|
|
154
155
|
self._buffer: ta.List[bytes] = []
|
|
@@ -165,6 +166,10 @@ class CoroHttpClientConnection(
|
|
|
165
166
|
|
|
166
167
|
CoroHttpClientValidation.validate_host(self._host)
|
|
167
168
|
|
|
169
|
+
@property
|
|
170
|
+
def http_version(self) -> int:
|
|
171
|
+
return self._http_version
|
|
172
|
+
|
|
168
173
|
#
|
|
169
174
|
|
|
170
175
|
def _get_hostport(self, host: str, port: ta.Optional[int]) -> ta.Tuple[str, int]:
|
|
@@ -176,12 +181,12 @@ class CoroHttpClientConnection(
|
|
|
176
181
|
port = int(host[i + 1:])
|
|
177
182
|
except ValueError:
|
|
178
183
|
if host[i + 1:] == '': # http://foo.com:/ == http://foo.com/
|
|
179
|
-
port = self.
|
|
184
|
+
port = self._default_port
|
|
180
185
|
else:
|
|
181
|
-
raise
|
|
186
|
+
raise CoroHttpClientErrors.InvalidUrlError(f"non-numeric port: '{host[i + 1:]}'") from None
|
|
182
187
|
host = host[:i]
|
|
183
188
|
else:
|
|
184
|
-
port = self.
|
|
189
|
+
port = self._default_port
|
|
185
190
|
|
|
186
191
|
if host and host[0] == '[' and host[-1] == ']':
|
|
187
192
|
host = host[1:-1]
|
|
@@ -232,7 +237,7 @@ class CoroHttpClientConnection(
|
|
|
232
237
|
encoded_host = self._tunnel_host.encode('idna').decode('ascii')
|
|
233
238
|
self._tunnel_headers['Host'] = f'{encoded_host}:{self._tunnel_port:d}'
|
|
234
239
|
|
|
235
|
-
def _tunnel(self) -> ta.Generator[
|
|
240
|
+
def _tunnel(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
236
241
|
connect = b'CONNECT %s:%d %s\r\n' % (
|
|
237
242
|
self._wrap_ipv6(check.not_none(self._tunnel_host).encode('idna')),
|
|
238
243
|
check.not_none(self._tunnel_port),
|
|
@@ -251,7 +256,7 @@ class CoroHttpClientConnection(
|
|
|
251
256
|
|
|
252
257
|
try:
|
|
253
258
|
(version, code, message) = (yield from CoroHttpClientStatusLine.read())
|
|
254
|
-
except
|
|
259
|
+
except CoroHttpClientErrors.BadStatusLineError: # noqa
|
|
255
260
|
# self._close_conn()
|
|
256
261
|
raise
|
|
257
262
|
|
|
@@ -277,18 +282,19 @@ class CoroHttpClientConnection(
|
|
|
277
282
|
|
|
278
283
|
#
|
|
279
284
|
|
|
280
|
-
def connect(self) -> ta.Generator[
|
|
285
|
+
def connect(self) -> ta.Generator[CoroHttpIo.Io, None, None]:
|
|
281
286
|
"""Connect to the host and port specified in __init__."""
|
|
282
287
|
|
|
283
288
|
if self._connected:
|
|
284
289
|
return
|
|
285
290
|
|
|
286
|
-
check.none((yield
|
|
291
|
+
check.none((yield CoroHttpIo.ConnectIo(
|
|
287
292
|
((self._host, self._port),),
|
|
288
293
|
dict(
|
|
289
294
|
source_address=self._source_address,
|
|
290
295
|
**(dict(timeout=self._timeout) if self._timeout is not self._NOT_SET else {}),
|
|
291
296
|
),
|
|
297
|
+
server_hostname=self._tunnel_host if self._tunnel_host else self._host,
|
|
292
298
|
)))
|
|
293
299
|
|
|
294
300
|
self._connected = True
|
|
@@ -298,14 +304,14 @@ class CoroHttpClientConnection(
|
|
|
298
304
|
|
|
299
305
|
#
|
|
300
306
|
|
|
301
|
-
def close(self) -> ta.Generator[
|
|
307
|
+
def close(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
302
308
|
"""Close the connection to the HTTP server."""
|
|
303
309
|
|
|
304
310
|
self._state = self._State.IDLE
|
|
305
311
|
|
|
306
312
|
try:
|
|
307
313
|
if self._connected:
|
|
308
|
-
yield
|
|
314
|
+
yield CoroHttpIo.CloseIo() # Close it manually... there may be other refs
|
|
309
315
|
self._connected = False
|
|
310
316
|
|
|
311
317
|
finally:
|
|
@@ -322,9 +328,9 @@ class CoroHttpClientConnection(
|
|
|
322
328
|
|
|
323
329
|
return isinstance(stream, io.TextIOBase)
|
|
324
330
|
|
|
325
|
-
def send(self, data: ta.Any) -> ta.Generator[
|
|
331
|
+
def send(self, data: ta.Any) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
326
332
|
"""
|
|
327
|
-
Send
|
|
333
|
+
Send 'data' to the server. ``data`` can be a string object, a bytes object, an array object, a file-like object
|
|
328
334
|
that supports a .read() method, or an iterable object.
|
|
329
335
|
"""
|
|
330
336
|
|
|
@@ -332,7 +338,7 @@ class CoroHttpClientConnection(
|
|
|
332
338
|
if self._auto_open:
|
|
333
339
|
yield from self.connect()
|
|
334
340
|
else:
|
|
335
|
-
raise
|
|
341
|
+
raise CoroHttpClientErrors.NotConnectedError
|
|
336
342
|
|
|
337
343
|
check.state(self._connected)
|
|
338
344
|
|
|
@@ -341,15 +347,15 @@ class CoroHttpClientConnection(
|
|
|
341
347
|
while data_block := data.read(self._block_size):
|
|
342
348
|
if encode:
|
|
343
349
|
data_block = data_block.encode('iso-8859-1')
|
|
344
|
-
check.none((yield
|
|
350
|
+
check.none((yield CoroHttpIo.WriteIo(data_block)))
|
|
345
351
|
return
|
|
346
352
|
|
|
347
353
|
if isinstance(data, (bytes, bytearray)):
|
|
348
|
-
check.none((yield
|
|
354
|
+
check.none((yield CoroHttpIo.WriteIo(data)))
|
|
349
355
|
|
|
350
356
|
elif isinstance(data, collections.abc.Iterable):
|
|
351
357
|
for d in data:
|
|
352
|
-
check.none((yield
|
|
358
|
+
check.none((yield CoroHttpIo.WriteIo(d)))
|
|
353
359
|
|
|
354
360
|
else:
|
|
355
361
|
raise TypeError(f'data should be a bytes-like object or an iterable, got {type(data)!r}') from None
|
|
@@ -374,7 +380,7 @@ class CoroHttpClientConnection(
|
|
|
374
380
|
self,
|
|
375
381
|
message_body: ta.Optional[ta.Any] = None,
|
|
376
382
|
encode_chunked: bool = False,
|
|
377
|
-
) -> ta.Generator[
|
|
383
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
378
384
|
"""
|
|
379
385
|
Send the currently buffered request and clear the buffer.
|
|
380
386
|
|
|
@@ -448,10 +454,10 @@ class CoroHttpClientConnection(
|
|
|
448
454
|
"""
|
|
449
455
|
Send a request to the server.
|
|
450
456
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
457
|
+
'method' specifies an HTTP request method, e.g. 'GET'.
|
|
458
|
+
'url' specifies the object being requested, e.g. '/index.html'.
|
|
459
|
+
'skip_host' if True does not add automatically a 'Host:' header
|
|
460
|
+
'skip_accept_encoding' if True does not add automatically an 'Accept-Encoding:' header
|
|
455
461
|
"""
|
|
456
462
|
|
|
457
463
|
# If a prior response has been completed, then forget about it.
|
|
@@ -476,7 +482,7 @@ class CoroHttpClientConnection(
|
|
|
476
482
|
if self._state == self._State.IDLE:
|
|
477
483
|
self._state = self._State.REQ_STARTED
|
|
478
484
|
else:
|
|
479
|
-
raise
|
|
485
|
+
raise CoroHttpClientErrors.CannotSendRequestError(self._state)
|
|
480
486
|
|
|
481
487
|
CoroHttpClientValidation.validate_method(method)
|
|
482
488
|
|
|
@@ -529,7 +535,7 @@ class CoroHttpClientConnection(
|
|
|
529
535
|
if ':' in host:
|
|
530
536
|
host_enc = self._strip_ipv6_iface(host_enc)
|
|
531
537
|
|
|
532
|
-
if port == self.
|
|
538
|
+
if port == self._default_port:
|
|
533
539
|
self.put_header('Host', host_enc)
|
|
534
540
|
else:
|
|
535
541
|
self.put_header('Host', f"{host_enc.decode('ascii')}:{port}")
|
|
@@ -568,7 +574,7 @@ class CoroHttpClientConnection(
|
|
|
568
574
|
"""
|
|
569
575
|
|
|
570
576
|
if self._state != self._State.REQ_STARTED:
|
|
571
|
-
raise
|
|
577
|
+
raise CoroHttpClientErrors.CannotSendHeaderError
|
|
572
578
|
|
|
573
579
|
if hasattr(header, 'encode'):
|
|
574
580
|
bh = header.encode('ascii')
|
|
@@ -598,7 +604,7 @@ class CoroHttpClientConnection(
|
|
|
598
604
|
message_body: ta.Optional[ta.Any] = None,
|
|
599
605
|
*,
|
|
600
606
|
encode_chunked: bool = False,
|
|
601
|
-
) -> ta.Generator[
|
|
607
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
602
608
|
"""
|
|
603
609
|
Indicate that the last header line has been sent to the server.
|
|
604
610
|
|
|
@@ -609,7 +615,7 @@ class CoroHttpClientConnection(
|
|
|
609
615
|
if self._state == self._State.REQ_STARTED:
|
|
610
616
|
self._state = self._State.REQ_SENT
|
|
611
617
|
else:
|
|
612
|
-
raise
|
|
618
|
+
raise CoroHttpClientErrors.CannotSendHeaderError
|
|
613
619
|
|
|
614
620
|
yield from self._send_output(message_body, encode_chunked=encode_chunked)
|
|
615
621
|
|
|
@@ -623,7 +629,7 @@ class CoroHttpClientConnection(
|
|
|
623
629
|
headers: ta.Optional[ta.Mapping[str, str]] = None,
|
|
624
630
|
*,
|
|
625
631
|
encode_chunked: bool = False,
|
|
626
|
-
) -> ta.Generator[
|
|
632
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
627
633
|
"""Send a complete request to the server."""
|
|
628
634
|
|
|
629
635
|
yield from self._send_request(method, url, body, dict(headers or {}), encode_chunked)
|
|
@@ -693,7 +699,7 @@ class CoroHttpClientConnection(
|
|
|
693
699
|
body: ta.Optional[ta.Any],
|
|
694
700
|
headers: ta.Mapping[str, str],
|
|
695
701
|
encode_chunked: bool,
|
|
696
|
-
) -> ta.Generator[
|
|
702
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
697
703
|
# Honor explicitly requested Host: and Accept-Encoding: headers.
|
|
698
704
|
header_names = frozenset(k.lower() for k in headers)
|
|
699
705
|
skips = {}
|
|
@@ -740,7 +746,7 @@ class CoroHttpClientConnection(
|
|
|
740
746
|
def _new_response(self) -> CoroHttpClientResponse:
|
|
741
747
|
return CoroHttpClientResponse(check.not_none(self._method))
|
|
742
748
|
|
|
743
|
-
def get_response(self) -> ta.Generator[
|
|
749
|
+
def get_response(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHttpClientResponse]:
|
|
744
750
|
"""
|
|
745
751
|
Get the response from the server.
|
|
746
752
|
|
|
@@ -766,7 +772,7 @@ class CoroHttpClientConnection(
|
|
|
766
772
|
# 1) will_close: this connection was reset and the prior socket and response operate independently
|
|
767
773
|
# 2) persistent: the response was retained and we await its is_closed() status to become true.
|
|
768
774
|
if self._state != self._State.REQ_SENT or self._response:
|
|
769
|
-
raise
|
|
775
|
+
raise CoroHttpClientErrors.ResponseNotReadyError(self._state)
|
|
770
776
|
|
|
771
777
|
resp = self._new_response()
|
|
772
778
|
resp_state = resp._state # noqa
|
|
@@ -40,8 +40,8 @@ import email.parser
|
|
|
40
40
|
import typing as ta
|
|
41
41
|
|
|
42
42
|
from ....lite.check import check
|
|
43
|
+
from ..io import CoroHttpIo
|
|
43
44
|
from .errors import CoroHttpClientErrors
|
|
44
|
-
from .io import CoroHttpClientIo
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
##
|
|
@@ -56,7 +56,7 @@ class CoroHttpClientHeaders:
|
|
|
56
56
|
MAX_HEADERS: ta.ClassVar[int] = 100
|
|
57
57
|
|
|
58
58
|
@classmethod
|
|
59
|
-
def read_headers(cls) -> ta.Generator[
|
|
59
|
+
def read_headers(cls) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], ta.List[bytes]]:
|
|
60
60
|
"""
|
|
61
61
|
Reads potential header lines into a list from a file pointer.
|
|
62
62
|
|
|
@@ -65,8 +65,8 @@ class CoroHttpClientHeaders:
|
|
|
65
65
|
|
|
66
66
|
headers = []
|
|
67
67
|
while True:
|
|
68
|
-
line = check.isinstance((yield
|
|
69
|
-
if len(line) >
|
|
68
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(CoroHttpIo.MAX_LINE + 1)), bytes)
|
|
69
|
+
if len(line) > CoroHttpIo.MAX_LINE:
|
|
70
70
|
raise CoroHttpClientErrors.LineTooLongError(CoroHttpClientErrors.LineTooLongError.LineType.HEADER)
|
|
71
71
|
|
|
72
72
|
headers.append(line)
|
|
@@ -92,7 +92,7 @@ class CoroHttpClientHeaders:
|
|
|
92
92
|
return email.parser.Parser().parsestr(text)
|
|
93
93
|
|
|
94
94
|
@classmethod
|
|
95
|
-
def parse_headers(cls) -> ta.Generator[
|
|
95
|
+
def parse_headers(cls) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], email.message.Message]:
|
|
96
96
|
"""Parses only RFC2822 headers from a file pointer."""
|
|
97
97
|
|
|
98
98
|
headers = yield from cls.read_headers()
|
|
@@ -40,19 +40,16 @@ import http
|
|
|
40
40
|
import typing as ta
|
|
41
41
|
|
|
42
42
|
from ....lite.check import check
|
|
43
|
+
from ..io import CoroHttpIo
|
|
43
44
|
from .errors import CoroHttpClientErrors
|
|
44
45
|
from .headers import CoroHttpClientHeaders
|
|
45
|
-
from .io import CoroHttpClientIo
|
|
46
46
|
from .status import CoroHttpClientStatusLine
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
##
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
class CoroHttpClientResponse
|
|
53
|
-
CoroHttpClientErrors,
|
|
54
|
-
CoroHttpClientIo,
|
|
55
|
-
):
|
|
52
|
+
class CoroHttpClientResponse:
|
|
56
53
|
# See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details.
|
|
57
54
|
|
|
58
55
|
# The bytes from the socket object are iso-8859-1 strings. See RFC 2616 sec 2.2 which notes an exception for
|
|
@@ -91,14 +88,14 @@ class CoroHttpClientResponse(
|
|
|
91
88
|
|
|
92
89
|
#
|
|
93
90
|
|
|
94
|
-
def _read_status(self) -> ta.Generator[
|
|
91
|
+
def _read_status(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], CoroHttpClientStatusLine]:
|
|
95
92
|
try:
|
|
96
93
|
return (yield from CoroHttpClientStatusLine.read())
|
|
97
|
-
except
|
|
94
|
+
except CoroHttpClientErrors.BadStatusLineError:
|
|
98
95
|
self._close_conn()
|
|
99
96
|
raise
|
|
100
97
|
|
|
101
|
-
def _begin(self) -> ta.Generator[
|
|
98
|
+
def _begin(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
102
99
|
state = self._state
|
|
103
100
|
|
|
104
101
|
check.state(not hasattr(state, 'headers'))
|
|
@@ -123,7 +120,7 @@ class CoroHttpClientResponse(
|
|
|
123
120
|
# Use HTTP/1.1 code for HTTP/1.x where x>=1
|
|
124
121
|
state.version = 11
|
|
125
122
|
else:
|
|
126
|
-
raise
|
|
123
|
+
raise CoroHttpClientErrors.UnknownProtocolError(version)
|
|
127
124
|
|
|
128
125
|
state.headers = yield from CoroHttpClientHeaders.parse_headers()
|
|
129
126
|
|
|
@@ -217,7 +214,7 @@ class CoroHttpClientResponse(
|
|
|
217
214
|
|
|
218
215
|
#
|
|
219
216
|
|
|
220
|
-
def read(self, amt: ta.Optional[int] = None) -> ta.Generator[
|
|
217
|
+
def read(self, amt: ta.Optional[int] = None) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
221
218
|
"""Read and return the response body, or up to the next amt bytes."""
|
|
222
219
|
|
|
223
220
|
if self._state.closed:
|
|
@@ -230,12 +227,12 @@ class CoroHttpClientResponse(
|
|
|
230
227
|
if self._state.chunked:
|
|
231
228
|
return (yield from self._read_chunked(amt))
|
|
232
229
|
|
|
233
|
-
if amt is not None:
|
|
230
|
+
if amt is not None and amt >= 0:
|
|
234
231
|
if self._state.length is not None and amt > self._state.length:
|
|
235
232
|
# Clip the read to the "end of response"
|
|
236
233
|
amt = self._state.length
|
|
237
234
|
|
|
238
|
-
s = check.isinstance((yield
|
|
235
|
+
s = check.isinstance((yield CoroHttpIo.ReadIo(amt)), bytes)
|
|
239
236
|
|
|
240
237
|
if not s and amt:
|
|
241
238
|
# Ideally, we would raise IncompleteRead if the content-length wasn't satisfied, but it might break
|
|
@@ -252,12 +249,12 @@ class CoroHttpClientResponse(
|
|
|
252
249
|
else:
|
|
253
250
|
# Amount is not given (unbounded read) so we must check self.length
|
|
254
251
|
if self._state.length is None:
|
|
255
|
-
s = check.isinstance((yield
|
|
252
|
+
s = check.isinstance((yield CoroHttpIo.ReadIo(None)), bytes)
|
|
256
253
|
|
|
257
254
|
else:
|
|
258
255
|
try:
|
|
259
256
|
s = yield from self._safe_read(self._state.length)
|
|
260
|
-
except
|
|
257
|
+
except CoroHttpClientErrors.IncompleteReadError:
|
|
261
258
|
self._close_conn()
|
|
262
259
|
raise
|
|
263
260
|
|
|
@@ -266,11 +263,11 @@ class CoroHttpClientResponse(
|
|
|
266
263
|
self._close_conn() # We read everything
|
|
267
264
|
return s
|
|
268
265
|
|
|
269
|
-
def _read_next_chunk_size(self) -> ta.Generator[
|
|
266
|
+
def _read_next_chunk_size(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], int]:
|
|
270
267
|
# Read the next chunk size from the file
|
|
271
|
-
line = check.isinstance((yield
|
|
272
|
-
if len(line) >
|
|
273
|
-
raise
|
|
268
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(CoroHttpIo.MAX_LINE + 1)), bytes)
|
|
269
|
+
if len(line) > CoroHttpIo.MAX_LINE:
|
|
270
|
+
raise CoroHttpClientErrors.LineTooLongError(CoroHttpClientErrors.LineTooLongError.LineType.CHUNK_SIZE)
|
|
274
271
|
|
|
275
272
|
i = line.find(b';')
|
|
276
273
|
if i >= 0:
|
|
@@ -283,13 +280,13 @@ class CoroHttpClientResponse(
|
|
|
283
280
|
self._close_conn()
|
|
284
281
|
raise
|
|
285
282
|
|
|
286
|
-
def _read_and_discard_trailer(self) -> ta.Generator[
|
|
283
|
+
def _read_and_discard_trailer(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], None]:
|
|
287
284
|
# Read and discard trailer up to the CRLF terminator
|
|
288
285
|
# NOTE: we shouldn't have any trailers!
|
|
289
286
|
while True:
|
|
290
|
-
line = check.isinstance((yield
|
|
291
|
-
if len(line) >
|
|
292
|
-
raise
|
|
287
|
+
line = check.isinstance((yield CoroHttpIo.ReadLineIo(CoroHttpIo.MAX_LINE + 1)), bytes)
|
|
288
|
+
if len(line) > CoroHttpIo.MAX_LINE:
|
|
289
|
+
raise CoroHttpClientErrors.LineTooLongError(CoroHttpClientErrors.LineTooLongError.LineType.TRAILER)
|
|
293
290
|
|
|
294
291
|
if not line:
|
|
295
292
|
# A vanishingly small number of sites EOF without sending the trailer
|
|
@@ -298,7 +295,7 @@ class CoroHttpClientResponse(
|
|
|
298
295
|
if line in (b'\r\n', b'\n', b''):
|
|
299
296
|
break
|
|
300
297
|
|
|
301
|
-
def _get_chunk_left(self) -> ta.Generator[
|
|
298
|
+
def _get_chunk_left(self) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], ta.Optional[int]]:
|
|
302
299
|
# Return self.chunk_left, reading a new chunk if necessary. chunk_left == 0: at the end of the current chunk,
|
|
303
300
|
# need to close it chunk_left == None: No current chunk, should read next. This function returns non-zero or
|
|
304
301
|
# None if the last chunk has been read.
|
|
@@ -311,7 +308,7 @@ class CoroHttpClientResponse(
|
|
|
311
308
|
try:
|
|
312
309
|
chunk_left = yield from self._read_next_chunk_size()
|
|
313
310
|
except ValueError:
|
|
314
|
-
raise
|
|
311
|
+
raise CoroHttpClientErrors.IncompleteReadError(b'') from None
|
|
315
312
|
|
|
316
313
|
if chunk_left == 0:
|
|
317
314
|
# Last chunk: 1*('0') [ chunk-extension ] CRLF
|
|
@@ -329,8 +326,10 @@ class CoroHttpClientResponse(
|
|
|
329
326
|
def _read_chunked(
|
|
330
327
|
self,
|
|
331
328
|
amt: ta.Optional[int] = None,
|
|
332
|
-
) -> ta.Generator[
|
|
329
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
333
330
|
check.state(hasattr(self._state, 'chunked'))
|
|
331
|
+
if amt is not None and amt < 0:
|
|
332
|
+
amt = None
|
|
334
333
|
value = []
|
|
335
334
|
try:
|
|
336
335
|
while (chunk_left := (yield from self._get_chunk_left())) is not None:
|
|
@@ -346,10 +345,10 @@ class CoroHttpClientResponse(
|
|
|
346
345
|
|
|
347
346
|
return b''.join(value)
|
|
348
347
|
|
|
349
|
-
except
|
|
350
|
-
raise
|
|
348
|
+
except CoroHttpClientErrors.IncompleteReadError as exc:
|
|
349
|
+
raise CoroHttpClientErrors.IncompleteReadError(b''.join(value)) from exc
|
|
351
350
|
|
|
352
|
-
def _safe_read(self, amt: int) -> ta.Generator[
|
|
351
|
+
def _safe_read(self, amt: int) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
353
352
|
"""
|
|
354
353
|
Read the number of bytes requested.
|
|
355
354
|
|
|
@@ -357,12 +356,12 @@ class CoroHttpClientResponse(
|
|
|
357
356
|
available (due to EOF), then the IncompleteRead exception can be used to detect the problem.
|
|
358
357
|
"""
|
|
359
358
|
|
|
360
|
-
data = check.isinstance((yield
|
|
359
|
+
data = check.isinstance((yield CoroHttpIo.ReadIo(amt)), bytes)
|
|
361
360
|
if len(data) < amt:
|
|
362
|
-
raise
|
|
361
|
+
raise CoroHttpClientErrors.IncompleteReadError(data, amt - len(data))
|
|
363
362
|
return data
|
|
364
363
|
|
|
365
|
-
def peek(self, n: int = -1) -> ta.Generator[
|
|
364
|
+
def peek(self, n: int = -1) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
366
365
|
# Having this enables IOBase.readline() to read more than one byte at a time
|
|
367
366
|
if self._state.closed or self._state.method == 'HEAD':
|
|
368
367
|
return b''
|
|
@@ -370,12 +369,12 @@ class CoroHttpClientResponse(
|
|
|
370
369
|
if self._state.chunked:
|
|
371
370
|
return (yield from self._peek_chunked(n))
|
|
372
371
|
|
|
373
|
-
return check.isinstance((yield
|
|
372
|
+
return check.isinstance((yield CoroHttpIo.PeekIo(n)), bytes)
|
|
374
373
|
|
|
375
374
|
def _readline(
|
|
376
375
|
self,
|
|
377
376
|
size: ta.Optional[int] = -1,
|
|
378
|
-
) -> ta.Generator[
|
|
377
|
+
) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
379
378
|
if size is None:
|
|
380
379
|
size = -1
|
|
381
380
|
else:
|
|
@@ -407,7 +406,7 @@ class CoroHttpClientResponse(
|
|
|
407
406
|
|
|
408
407
|
return bytes(res)
|
|
409
408
|
|
|
410
|
-
def readline(self, limit: int = -1) -> ta.Generator[
|
|
409
|
+
def readline(self, limit: int = -1) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
411
410
|
if self._state.closed or self._state.method == 'HEAD':
|
|
412
411
|
return b''
|
|
413
412
|
|
|
@@ -418,7 +417,7 @@ class CoroHttpClientResponse(
|
|
|
418
417
|
if self._state.length is not None and (limit < 0 or limit > self._state.length):
|
|
419
418
|
limit = self._state.length
|
|
420
419
|
|
|
421
|
-
result = check.isinstance((yield
|
|
420
|
+
result = check.isinstance((yield CoroHttpIo.ReadLineIo(limit)), bytes)
|
|
422
421
|
|
|
423
422
|
if not result and limit:
|
|
424
423
|
self._close_conn()
|
|
@@ -430,16 +429,16 @@ class CoroHttpClientResponse(
|
|
|
430
429
|
|
|
431
430
|
return result
|
|
432
431
|
|
|
433
|
-
def _peek_chunked(self, n: int) -> ta.Generator[
|
|
432
|
+
def _peek_chunked(self, n: int) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], bytes]:
|
|
434
433
|
# Strictly speaking, _get_chunk_left() may cause more than one read, but that is ok, since that is to satisfy
|
|
435
434
|
# the chunked protocol.
|
|
436
435
|
try:
|
|
437
436
|
chunk_left = yield from self._get_chunk_left()
|
|
438
|
-
except
|
|
437
|
+
except CoroHttpClientErrors.IncompleteReadError:
|
|
439
438
|
return b'' # Peek doesn't worry about protocol
|
|
440
439
|
|
|
441
440
|
if chunk_left is None:
|
|
442
441
|
return b'' # Eof
|
|
443
442
|
|
|
444
443
|
# Peek is allowed to return more than requested. Just request the entire chunk, and truncate what we get.
|
|
445
|
-
return check.isinstance((yield
|
|
444
|
+
return check.isinstance((yield CoroHttpIo.PeekIo(chunk_left)), bytes)[:chunk_left]
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
import typing as ta
|
|
39
39
|
|
|
40
40
|
from ....lite.check import check
|
|
41
|
+
from ..io import CoroHttpIo
|
|
41
42
|
from .errors import CoroHttpClientErrors
|
|
42
|
-
from .io import CoroHttpClientIo
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
#
|
|
@@ -51,9 +51,9 @@ class CoroHttpClientStatusLine(ta.NamedTuple):
|
|
|
51
51
|
reason: str
|
|
52
52
|
|
|
53
53
|
@classmethod
|
|
54
|
-
def read(cls) -> ta.Generator[
|
|
55
|
-
line = str(check.isinstance((yield
|
|
56
|
-
if len(line) >
|
|
54
|
+
def read(cls) -> ta.Generator[CoroHttpIo.Io, ta.Optional[bytes], 'CoroHttpClientStatusLine']:
|
|
55
|
+
line = str(check.isinstance((yield CoroHttpIo.ReadLineIo(CoroHttpIo.MAX_LINE + 1)), bytes), 'iso-8859-1')
|
|
56
|
+
if len(line) > CoroHttpIo.MAX_LINE:
|
|
57
57
|
raise CoroHttpClientErrors.LineTooLongError(CoroHttpClientErrors.LineTooLongError.LineType.STATUS)
|
|
58
58
|
if not line:
|
|
59
59
|
# Presumably, the server closed the connection before sending a valid response.
|
|
@@ -3,13 +3,21 @@
|
|
|
3
3
|
import dataclasses as dc
|
|
4
4
|
import typing as ta
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from ...lite.abstract import Abstract
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
##
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class CoroHttpIo:
|
|
13
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
14
|
+
raise TypeError
|
|
15
|
+
|
|
16
|
+
def __init_subclass__(cls, **kwargs): # noqa
|
|
17
|
+
raise TypeError
|
|
18
|
+
|
|
19
|
+
#
|
|
20
|
+
|
|
13
21
|
MAX_LINE: ta.ClassVar[int] = 65536
|
|
14
22
|
|
|
15
23
|
#
|
|
@@ -19,11 +27,20 @@ class CoroHttpClientIo:
|
|
|
19
27
|
|
|
20
28
|
#
|
|
21
29
|
|
|
30
|
+
class AnyLogIo(Io, Abstract):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
|
|
22
35
|
@dc.dataclass(frozen=True)
|
|
23
36
|
class ConnectIo(Io):
|
|
24
37
|
args: ta.Tuple[ta.Any, ...]
|
|
25
38
|
kwargs: ta.Optional[ta.Dict[str, ta.Any]] = None
|
|
26
39
|
|
|
40
|
+
server_hostname: ta.Optional[str] = None
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
|
|
27
44
|
class CloseIo(Io):
|
|
28
45
|
pass
|
|
29
46
|
|