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
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Insufficient alt impls:
|
|
3
|
+
- `sys.meta_path`:
|
|
4
|
+
- need access to the `fromlist` and `level` arguments passed to `__import__`
|
|
5
|
+
- need to return fake modules to the import operation which are not added to `sys.modules`
|
|
6
|
+
- `sys.addaudithook`: cannot prevent import or inject result
|
|
7
|
+
- `sys.settrace` / bytecode tracing: same
|
|
8
|
+
- jit bytecode rewriting: slower than just importing everything
|
|
9
|
+
|
|
10
|
+
Possible alt impls:
|
|
11
|
+
- aot static analysis, codegen, compare, if valid skip ctxmgr body and inject proxies, otherwise warn and run
|
|
12
|
+
- or just gen code inline, if ta.TYPE_CHECKING: .... else: # @omlish-generate-auto-proxy-import/init
|
|
13
|
+
- generate classic `foo = _lang.proxy_import('.foo', __package__)` blocks
|
|
14
|
+
"""
|
|
15
|
+
import builtins
|
|
16
|
+
import contextlib
|
|
17
|
+
import functools
|
|
18
|
+
import importlib.util
|
|
19
|
+
import sys
|
|
20
|
+
import threading
|
|
21
|
+
import types
|
|
22
|
+
import typing as ta
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ImportCaptureError(Exception):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ImportCaptureErrors:
|
|
33
|
+
def __new__(cls, *args, **kwargs): # noqa
|
|
34
|
+
raise TypeError
|
|
35
|
+
|
|
36
|
+
class HookError(ImportCaptureError):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
class AttrError(ImportCaptureError):
|
|
40
|
+
def __init__(self, module: str | None, name: str) -> None:
|
|
41
|
+
super().__init__()
|
|
42
|
+
|
|
43
|
+
self.module = module
|
|
44
|
+
self.name = name
|
|
45
|
+
|
|
46
|
+
def __repr__(self) -> str:
|
|
47
|
+
return f'{self.__class__.__qualname__}(module={self.module!r}, name={self.name!r})'
|
|
48
|
+
|
|
49
|
+
class ImportError(ImportCaptureError): # noqa
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
name: str,
|
|
53
|
+
*,
|
|
54
|
+
level: int | None = None,
|
|
55
|
+
from_list: ta.Sequence[str] | None,
|
|
56
|
+
) -> None:
|
|
57
|
+
super().__init__()
|
|
58
|
+
|
|
59
|
+
self.name = name
|
|
60
|
+
self.level = level
|
|
61
|
+
self.from_list = from_list
|
|
62
|
+
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
return ''.join([
|
|
65
|
+
f'{self.__class__.__qualname__}(',
|
|
66
|
+
f'name={self.name!r}',
|
|
67
|
+
*([f', level={self.level!r}'] if self.level is not None else []),
|
|
68
|
+
*([f', from_list={self.from_list!r}'] if self.from_list is not None else []),
|
|
69
|
+
')',
|
|
70
|
+
])
|
|
71
|
+
|
|
72
|
+
class ImportStarForbiddenError(ImportError):
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
class UncapturedImportForbiddenError(ImportError):
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
class UnreferencedImportsError(ImportCaptureError):
|
|
79
|
+
def __init__(self, unreferenced: ta.Sequence[str]) -> None:
|
|
80
|
+
super().__init__()
|
|
81
|
+
|
|
82
|
+
self.unreferenced = unreferenced
|
|
83
|
+
|
|
84
|
+
def __repr__(self) -> str:
|
|
85
|
+
return f'{self.__class__.__qualname__}(unreferenced={self.unreferenced!r})'
|
|
86
|
+
|
|
87
|
+
class CaptureInProgressError(ImportCaptureError):
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _ImportCaptureHook:
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
*,
|
|
98
|
+
package: str | None = None,
|
|
99
|
+
forbid_uncaptured_imports: bool = False,
|
|
100
|
+
) -> None:
|
|
101
|
+
super().__init__()
|
|
102
|
+
|
|
103
|
+
self._package = package
|
|
104
|
+
self._forbid_uncaptured_imports = forbid_uncaptured_imports
|
|
105
|
+
|
|
106
|
+
self._modules_by_name: dict[str, _ImportCaptureHook._Module] = {}
|
|
107
|
+
self._modules_by_module_obj: dict[types.ModuleType, _ImportCaptureHook._Module] = {}
|
|
108
|
+
|
|
109
|
+
#
|
|
110
|
+
|
|
111
|
+
class _Module:
|
|
112
|
+
def __init__(
|
|
113
|
+
self,
|
|
114
|
+
name: str,
|
|
115
|
+
getattr_handler: ta.Callable[['_ImportCaptureHook._Module', str], ta.Any],
|
|
116
|
+
*,
|
|
117
|
+
parent: ta.Optional['_ImportCaptureHook._Module'] = None,
|
|
118
|
+
) -> None:
|
|
119
|
+
super().__init__()
|
|
120
|
+
|
|
121
|
+
if name.startswith('.'):
|
|
122
|
+
raise ImportCaptureError
|
|
123
|
+
|
|
124
|
+
self.name = name
|
|
125
|
+
self.parent = parent
|
|
126
|
+
|
|
127
|
+
self.base_name = name.rpartition('.')[2]
|
|
128
|
+
self.root: _ImportCaptureHook._Module = parent.root if parent is not None else self # noqa
|
|
129
|
+
|
|
130
|
+
self.children: dict[str, _ImportCaptureHook._Module] = {}
|
|
131
|
+
self.descendants: set[_ImportCaptureHook._Module] = set()
|
|
132
|
+
|
|
133
|
+
self.module_obj = types.ModuleType(f'<{self.__class__.__qualname__}: {name}>')
|
|
134
|
+
self.module_obj.__file__ = None
|
|
135
|
+
self.module_obj.__getattr__ = functools.partial(getattr_handler, self) # type: ignore[method-assign] # noqa
|
|
136
|
+
self.initial_module_dict = dict(self.module_obj.__dict__)
|
|
137
|
+
|
|
138
|
+
self.explicit = False
|
|
139
|
+
self.immediate = False
|
|
140
|
+
|
|
141
|
+
def __repr__(self) -> str:
|
|
142
|
+
return f'{self.__class__.__name__}<{self.name}{"!" if self.immediate else "+" if self.explicit else ""}>'
|
|
143
|
+
|
|
144
|
+
def set_explicit(self) -> None:
|
|
145
|
+
cur: _ImportCaptureHook._Module | None = self
|
|
146
|
+
while cur is not None and not cur.explicit:
|
|
147
|
+
cur.explicit = True
|
|
148
|
+
cur = cur.parent
|
|
149
|
+
|
|
150
|
+
#
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def _modules(self) -> ta.Sequence[_Module]:
|
|
154
|
+
return sorted(self._modules_by_name.values(), key=lambda m: m.name)
|
|
155
|
+
|
|
156
|
+
def _get_or_make_module(self, name: str) -> _Module:
|
|
157
|
+
try:
|
|
158
|
+
return self._modules_by_name[name]
|
|
159
|
+
except KeyError:
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
parent: _ImportCaptureHook._Module | None = None
|
|
163
|
+
if '.' in name:
|
|
164
|
+
rest, _, attr = name.rpartition('.')
|
|
165
|
+
parent = self._get_or_make_module(rest)
|
|
166
|
+
if attr in parent.children:
|
|
167
|
+
raise ImportCaptureErrors.AttrError(rest, attr)
|
|
168
|
+
|
|
169
|
+
module = _ImportCaptureHook._Module(
|
|
170
|
+
name,
|
|
171
|
+
self._handle_module_getattr,
|
|
172
|
+
parent=parent,
|
|
173
|
+
)
|
|
174
|
+
self._modules_by_name[name] = module
|
|
175
|
+
self._modules_by_module_obj[module.module_obj] = module
|
|
176
|
+
|
|
177
|
+
if parent is not None:
|
|
178
|
+
parent.children[module.base_name] = module
|
|
179
|
+
setattr(parent.module_obj, module.base_name, module.module_obj)
|
|
180
|
+
parent.root.descendants.add(module)
|
|
181
|
+
|
|
182
|
+
return module
|
|
183
|
+
|
|
184
|
+
def _make_child_module(self, module: _Module, attr: str) -> _Module:
|
|
185
|
+
if attr in module.children:
|
|
186
|
+
raise ImportCaptureErrors.AttrError(module.name, attr)
|
|
187
|
+
|
|
188
|
+
return self._get_or_make_module(f'{module.name}.{attr}')
|
|
189
|
+
|
|
190
|
+
#
|
|
191
|
+
|
|
192
|
+
def _handle_module_getattr(self, module: _Module, attr: str) -> ta.Any:
|
|
193
|
+
if not module.explicit:
|
|
194
|
+
raise ImportCaptureErrors.AttrError(module.name, attr)
|
|
195
|
+
|
|
196
|
+
return self._make_child_module(module, attr).module_obj
|
|
197
|
+
|
|
198
|
+
def _handle_import(
|
|
199
|
+
self,
|
|
200
|
+
name: str,
|
|
201
|
+
*,
|
|
202
|
+
from_list: ta.Sequence[str] | None,
|
|
203
|
+
) -> types.ModuleType:
|
|
204
|
+
module = self._get_or_make_module(name)
|
|
205
|
+
|
|
206
|
+
if from_list is None:
|
|
207
|
+
module.set_explicit()
|
|
208
|
+
module.root.immediate = True
|
|
209
|
+
return module.root.module_obj
|
|
210
|
+
|
|
211
|
+
else:
|
|
212
|
+
for attr in from_list:
|
|
213
|
+
if attr == '*':
|
|
214
|
+
raise ImportCaptureErrors.ImportStarForbiddenError(module.name, from_list=from_list)
|
|
215
|
+
|
|
216
|
+
if (cm := module.children.get(attr)) is None:
|
|
217
|
+
cm = self._make_child_module(module, attr)
|
|
218
|
+
cm.set_explicit()
|
|
219
|
+
cm.immediate = True
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
x = getattr(module.module_obj, attr)
|
|
223
|
+
if x is not cm.module_obj or x not in self._modules_by_module_obj:
|
|
224
|
+
raise ImportCaptureErrors.AttrError(module.name, attr)
|
|
225
|
+
|
|
226
|
+
return module.module_obj
|
|
227
|
+
|
|
228
|
+
#
|
|
229
|
+
|
|
230
|
+
_MOD_SELF_ATTR: ta.ClassVar[str] = '__import_capture__'
|
|
231
|
+
|
|
232
|
+
def _intercept_import(
|
|
233
|
+
self,
|
|
234
|
+
name: str,
|
|
235
|
+
*,
|
|
236
|
+
globals: ta.Mapping[str, ta.Any] | None = None, # noqa
|
|
237
|
+
from_list: ta.Sequence[str] | None = None,
|
|
238
|
+
level: int = 0,
|
|
239
|
+
) -> types.ModuleType | None:
|
|
240
|
+
if not (
|
|
241
|
+
globals is not None and
|
|
242
|
+
globals.get(self._MOD_SELF_ATTR) is self
|
|
243
|
+
):
|
|
244
|
+
return None
|
|
245
|
+
|
|
246
|
+
if level:
|
|
247
|
+
if not self._package:
|
|
248
|
+
raise ImportCaptureError
|
|
249
|
+
name = importlib.util.resolve_name(('.' * level) + name, self._package)
|
|
250
|
+
|
|
251
|
+
return self._handle_import(
|
|
252
|
+
name,
|
|
253
|
+
from_list=from_list,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
@ta.final
|
|
257
|
+
@contextlib.contextmanager
|
|
258
|
+
def hook_context(
|
|
259
|
+
self,
|
|
260
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
261
|
+
) -> ta.Iterator[None]:
|
|
262
|
+
if self._MOD_SELF_ATTR in mod_globals:
|
|
263
|
+
raise ImportCaptureErrors.HookError
|
|
264
|
+
|
|
265
|
+
mod_globals[self._MOD_SELF_ATTR] = self
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
with self._hook_context(mod_globals):
|
|
269
|
+
yield
|
|
270
|
+
|
|
271
|
+
finally:
|
|
272
|
+
if mod_globals[self._MOD_SELF_ATTR] is not self:
|
|
273
|
+
raise ImportCaptureErrors.HookError
|
|
274
|
+
|
|
275
|
+
del mod_globals[self._MOD_SELF_ATTR]
|
|
276
|
+
|
|
277
|
+
# @abc.abstractmethod
|
|
278
|
+
def _hook_context(
|
|
279
|
+
self,
|
|
280
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
281
|
+
) -> ta.ContextManager[None]:
|
|
282
|
+
raise NotImplementedError
|
|
283
|
+
|
|
284
|
+
#
|
|
285
|
+
|
|
286
|
+
def verify_state(
|
|
287
|
+
self,
|
|
288
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
289
|
+
) -> None:
|
|
290
|
+
for m in self._modules_by_name.values():
|
|
291
|
+
if m.immediate and not m.explicit:
|
|
292
|
+
raise ImportCaptureError
|
|
293
|
+
|
|
294
|
+
if not m.explicit and m.children:
|
|
295
|
+
raise ImportCaptureError
|
|
296
|
+
|
|
297
|
+
for a, o in m.module_obj.__dict__.items():
|
|
298
|
+
try:
|
|
299
|
+
i = m.initial_module_dict[a]
|
|
300
|
+
|
|
301
|
+
except KeyError:
|
|
302
|
+
if o is not m.children[a].module_obj:
|
|
303
|
+
raise ImportCaptureErrors.AttrError(m.name, a) from None
|
|
304
|
+
|
|
305
|
+
else:
|
|
306
|
+
if o != i:
|
|
307
|
+
raise ImportCaptureErrors.AttrError(m.name, a)
|
|
308
|
+
|
|
309
|
+
#
|
|
310
|
+
|
|
311
|
+
def build_captured(
|
|
312
|
+
self,
|
|
313
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
314
|
+
*,
|
|
315
|
+
collect_unreferenced: bool = False,
|
|
316
|
+
) -> 'ImportCapture.Captured':
|
|
317
|
+
rem_explicit_mods: set[_ImportCaptureHook._Module] = set()
|
|
318
|
+
if collect_unreferenced:
|
|
319
|
+
rem_explicit_mods.update(
|
|
320
|
+
m for m in self._modules_by_name.values()
|
|
321
|
+
if m.immediate
|
|
322
|
+
and m.parent is not None # No good way to tell if user did `import a.b.c` or `import a.b.c as c`
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
#
|
|
326
|
+
|
|
327
|
+
dct: dict[_ImportCaptureHook._Module, list[tuple[str | None, str]]] = {}
|
|
328
|
+
|
|
329
|
+
for attr, obj in mod_globals.items():
|
|
330
|
+
if isinstance(obj, _ImportCaptureHook._Module):
|
|
331
|
+
raise ImportCaptureErrors.AttrError(None, attr) from None
|
|
332
|
+
|
|
333
|
+
elif isinstance(obj, types.ModuleType):
|
|
334
|
+
try:
|
|
335
|
+
m = self._modules_by_module_obj[obj]
|
|
336
|
+
except KeyError:
|
|
337
|
+
continue
|
|
338
|
+
|
|
339
|
+
if m.explicit:
|
|
340
|
+
dct.setdefault(m, []).append((None, attr))
|
|
341
|
+
if m in rem_explicit_mods:
|
|
342
|
+
# Remove everything reachable from this root *except* items imported immediately, such as
|
|
343
|
+
# `from x import y` - those still need to be immediately reachable.
|
|
344
|
+
rem_explicit_mods -= {dm for dm in m.descendants if not dm.immediate}
|
|
345
|
+
rem_explicit_mods.remove(m)
|
|
346
|
+
|
|
347
|
+
else:
|
|
348
|
+
p = m.parent
|
|
349
|
+
if p is None or not p.explicit:
|
|
350
|
+
raise ImportCaptureError
|
|
351
|
+
dct.setdefault(p, []).append((m.base_name, attr))
|
|
352
|
+
|
|
353
|
+
#
|
|
354
|
+
|
|
355
|
+
mods: dict[str, ImportCapture.Module] = {}
|
|
356
|
+
|
|
357
|
+
def build_import_module(m: _ImportCaptureHook._Module) -> ImportCapture.Module:
|
|
358
|
+
children: dict[str, ImportCapture.Module] = {}
|
|
359
|
+
attrs: list[str] = []
|
|
360
|
+
for cm in sorted(m.children.values(), key=lambda cm: cm.name):
|
|
361
|
+
if not cm.explicit:
|
|
362
|
+
attrs.append(cm.base_name)
|
|
363
|
+
else:
|
|
364
|
+
children[cm.base_name] = build_import_module(cm)
|
|
365
|
+
|
|
366
|
+
mod = ImportCapture.Module(
|
|
367
|
+
m.name,
|
|
368
|
+
children or None,
|
|
369
|
+
attrs or None,
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
if m.parent is None:
|
|
373
|
+
mod.parent = None
|
|
374
|
+
for c in children.values():
|
|
375
|
+
c.parent = mod
|
|
376
|
+
|
|
377
|
+
mods[mod.name] = mod
|
|
378
|
+
return mod
|
|
379
|
+
|
|
380
|
+
root_mods: dict[str, ImportCapture.Module] = {
|
|
381
|
+
m.base_name: build_import_module(m)
|
|
382
|
+
for m in self._modules_by_name.values()
|
|
383
|
+
if m.parent is None
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
mods = dict(sorted(mods.items(), key=lambda t: t[0]))
|
|
387
|
+
root_mods = dict(sorted(root_mods.items(), key=lambda t: t[0]))
|
|
388
|
+
|
|
389
|
+
#
|
|
390
|
+
|
|
391
|
+
imps: list[ImportCapture.Import] = []
|
|
392
|
+
|
|
393
|
+
for m, ts in sorted(dct.items(), key=lambda t: t[0].name):
|
|
394
|
+
imps.append(ImportCapture.Import(
|
|
395
|
+
mods[m.name],
|
|
396
|
+
[r for l, r in ts if l is None] or None,
|
|
397
|
+
[(l, r) for l, r in ts if l is not None] or None,
|
|
398
|
+
))
|
|
399
|
+
|
|
400
|
+
#
|
|
401
|
+
|
|
402
|
+
unreferenced: list[str] | None = None
|
|
403
|
+
if collect_unreferenced and rem_explicit_mods:
|
|
404
|
+
unreferenced = sorted(m.name for m in rem_explicit_mods)
|
|
405
|
+
|
|
406
|
+
return ImportCapture.Captured(
|
|
407
|
+
{i.module.name: i for i in imps},
|
|
408
|
+
|
|
409
|
+
mods,
|
|
410
|
+
root_mods,
|
|
411
|
+
|
|
412
|
+
unreferenced,
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
#
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
class _AbstractBuiltinsImportCaptureHook(_ImportCaptureHook):
|
|
420
|
+
def __init__(
|
|
421
|
+
self,
|
|
422
|
+
*,
|
|
423
|
+
_frame: types.FrameType | None = None,
|
|
424
|
+
**kwargs: ta.Any,
|
|
425
|
+
) -> None:
|
|
426
|
+
super().__init__(**kwargs)
|
|
427
|
+
|
|
428
|
+
def _new_import(
|
|
429
|
+
self,
|
|
430
|
+
old_import,
|
|
431
|
+
name,
|
|
432
|
+
globals=None, # noqa
|
|
433
|
+
locals=None, # noqa
|
|
434
|
+
fromlist=None,
|
|
435
|
+
level=0,
|
|
436
|
+
):
|
|
437
|
+
if (im := self._intercept_import(
|
|
438
|
+
name,
|
|
439
|
+
globals=globals,
|
|
440
|
+
from_list=fromlist,
|
|
441
|
+
level=level,
|
|
442
|
+
)) is not None:
|
|
443
|
+
return im
|
|
444
|
+
|
|
445
|
+
if self._forbid_uncaptured_imports:
|
|
446
|
+
raise ImportCaptureErrors.UncapturedImportForbiddenError(
|
|
447
|
+
name,
|
|
448
|
+
level=level,
|
|
449
|
+
from_list=fromlist,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
return old_import(
|
|
453
|
+
name,
|
|
454
|
+
globals=globals,
|
|
455
|
+
locals=locals,
|
|
456
|
+
fromlist=fromlist,
|
|
457
|
+
level=level,
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
#
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class _UnsafeGlobalBuiltinsImportCaptureHook(_AbstractBuiltinsImportCaptureHook):
|
|
465
|
+
@contextlib.contextmanager
|
|
466
|
+
def _hook_context(
|
|
467
|
+
self,
|
|
468
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
469
|
+
) -> ta.Iterator[None]:
|
|
470
|
+
old_import = builtins.__import__
|
|
471
|
+
new_import = functools.partial(self._new_import, old_import)
|
|
472
|
+
|
|
473
|
+
builtins.__import__ = new_import
|
|
474
|
+
|
|
475
|
+
try:
|
|
476
|
+
yield
|
|
477
|
+
|
|
478
|
+
finally:
|
|
479
|
+
if builtins.__import__ is not new_import:
|
|
480
|
+
raise ImportCaptureErrors.HookError
|
|
481
|
+
|
|
482
|
+
builtins.__import__ = old_import
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook(_AbstractBuiltinsImportCaptureHook):
|
|
486
|
+
class _AlreadyPatchedError(Exception):
|
|
487
|
+
pass
|
|
488
|
+
|
|
489
|
+
@ta.final
|
|
490
|
+
class _Patch:
|
|
491
|
+
__lock: ta.ClassVar[threading.Lock] = threading.Lock()
|
|
492
|
+
|
|
493
|
+
def __init__(self, old_import):
|
|
494
|
+
self.__old_import = old_import
|
|
495
|
+
self.__hooks = {}
|
|
496
|
+
self.__uninstalled = False
|
|
497
|
+
|
|
498
|
+
@classmethod
|
|
499
|
+
def _add_hook(cls, mod_globals, new_import) -> '_SomewhatThreadSafeGlobalBuiltinsImportCaptureHook._Patch':
|
|
500
|
+
gi = id(mod_globals)
|
|
501
|
+
for _ in range(1_000):
|
|
502
|
+
try:
|
|
503
|
+
with cls.__lock:
|
|
504
|
+
x: ta.Any = builtins.__import__
|
|
505
|
+
p: _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook._Patch
|
|
506
|
+
if x.__class__ is cls:
|
|
507
|
+
p = x
|
|
508
|
+
if p.__uninstalled: # noqa
|
|
509
|
+
raise _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook._AlreadyPatchedError # noqa
|
|
510
|
+
else:
|
|
511
|
+
p = cls(x)
|
|
512
|
+
builtins.__import__ = p
|
|
513
|
+
p.__hooks[gi] = (mod_globals, new_import)
|
|
514
|
+
return p
|
|
515
|
+
except _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook._AlreadyPatchedError:
|
|
516
|
+
pass
|
|
517
|
+
raise ImportCaptureErrors.HookError('Failed to install builtins hook')
|
|
518
|
+
|
|
519
|
+
def _remove_hook(self, mod_globals, *, no_raise=False):
|
|
520
|
+
gi = id(mod_globals)
|
|
521
|
+
with self.__lock:
|
|
522
|
+
tg, _ = self.__hooks[gi]
|
|
523
|
+
del self.__hooks[gi]
|
|
524
|
+
if not self.__uninstalled and not self.__hooks:
|
|
525
|
+
self.__uninstalled = True
|
|
526
|
+
if builtins.__import__ is not self:
|
|
527
|
+
if not no_raise:
|
|
528
|
+
# TODO: warn?
|
|
529
|
+
raise ImportCaptureErrors.HookError('Unexpected builtins hook')
|
|
530
|
+
else:
|
|
531
|
+
builtins.__import__ = self.__old_import
|
|
532
|
+
if tg is not mod_globals:
|
|
533
|
+
if not no_raise:
|
|
534
|
+
# TODO: warn?
|
|
535
|
+
raise ImportCaptureErrors.HookError('Mismatched globals')
|
|
536
|
+
|
|
537
|
+
def __call__(
|
|
538
|
+
self,
|
|
539
|
+
name,
|
|
540
|
+
globals=None, # noqa
|
|
541
|
+
locals=None, # noqa
|
|
542
|
+
fromlist=None,
|
|
543
|
+
level=0,
|
|
544
|
+
):
|
|
545
|
+
if globals is not None and (tup := self.__hooks.get(id(globals))) is not None:
|
|
546
|
+
tg, tf = tup
|
|
547
|
+
if tg is globals:
|
|
548
|
+
return tf(
|
|
549
|
+
self.__old_import,
|
|
550
|
+
name,
|
|
551
|
+
globals=globals,
|
|
552
|
+
locals=locals,
|
|
553
|
+
fromlist=fromlist,
|
|
554
|
+
level=level,
|
|
555
|
+
)
|
|
556
|
+
else:
|
|
557
|
+
self._remove_hook(tg, no_raise=True)
|
|
558
|
+
|
|
559
|
+
return self.__old_import(
|
|
560
|
+
name,
|
|
561
|
+
globals=globals,
|
|
562
|
+
locals=locals,
|
|
563
|
+
fromlist=fromlist,
|
|
564
|
+
level=level,
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
@contextlib.contextmanager
|
|
568
|
+
def _hook_context(
|
|
569
|
+
self,
|
|
570
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
571
|
+
) -> ta.Iterator[None]:
|
|
572
|
+
patch = _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook._Patch._add_hook(mod_globals, self._new_import) # noqa
|
|
573
|
+
|
|
574
|
+
try:
|
|
575
|
+
yield
|
|
576
|
+
|
|
577
|
+
finally:
|
|
578
|
+
patch._remove_hook(mod_globals) # noqa
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
#
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
_cext_: ta.Any
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def _cext() -> ta.Any:
|
|
588
|
+
global _cext_
|
|
589
|
+
try:
|
|
590
|
+
return _cext_
|
|
591
|
+
except NameError:
|
|
592
|
+
pass
|
|
593
|
+
|
|
594
|
+
cext: ta.Any
|
|
595
|
+
try:
|
|
596
|
+
from . import _capture as cext # type: ignore
|
|
597
|
+
except ImportError:
|
|
598
|
+
cext = None
|
|
599
|
+
|
|
600
|
+
_cext_ = cext
|
|
601
|
+
return cext
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
class _FrameBuiltinsImportCaptureHook(_AbstractBuiltinsImportCaptureHook):
|
|
605
|
+
def __init__(
|
|
606
|
+
self,
|
|
607
|
+
*,
|
|
608
|
+
_frame: types.FrameType,
|
|
609
|
+
**kwargs: ta.Any,
|
|
610
|
+
) -> None:
|
|
611
|
+
super().__init__(**kwargs)
|
|
612
|
+
|
|
613
|
+
self._frame = _frame
|
|
614
|
+
|
|
615
|
+
@classmethod
|
|
616
|
+
def _set_frame_builtins(
|
|
617
|
+
cls,
|
|
618
|
+
frame: types.FrameType,
|
|
619
|
+
new_builtins: dict[str, ta.Any],
|
|
620
|
+
) -> bool:
|
|
621
|
+
return _cext()._set_frame_builtins(frame, frame.f_builtins, new_builtins) # noqa
|
|
622
|
+
|
|
623
|
+
@contextlib.contextmanager
|
|
624
|
+
def _hook_context(
|
|
625
|
+
self,
|
|
626
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
627
|
+
) -> ta.Iterator[None]:
|
|
628
|
+
old_builtins = self._frame.f_builtins
|
|
629
|
+
old_import = old_builtins['__import__']
|
|
630
|
+
new_import = functools.partial(self._new_import, old_import)
|
|
631
|
+
|
|
632
|
+
new_builtins = dict(old_builtins)
|
|
633
|
+
new_builtins['__import__'] = new_import
|
|
634
|
+
if not self._set_frame_builtins(self._frame, new_builtins):
|
|
635
|
+
raise ImportCaptureErrors.HookError
|
|
636
|
+
|
|
637
|
+
try:
|
|
638
|
+
yield
|
|
639
|
+
|
|
640
|
+
finally:
|
|
641
|
+
if self._frame.f_builtins is not new_builtins:
|
|
642
|
+
raise ImportCaptureErrors.HookError
|
|
643
|
+
|
|
644
|
+
if not self._set_frame_builtins(self._frame, old_builtins):
|
|
645
|
+
raise ImportCaptureErrors.HookError
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
#
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
_CAPTURE_IMPLS: ta.Mapping[str, type[_AbstractBuiltinsImportCaptureHook]] = {
|
|
652
|
+
'cext': _FrameBuiltinsImportCaptureHook,
|
|
653
|
+
'somewhat_safe': _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook,
|
|
654
|
+
'unsafe': _UnsafeGlobalBuiltinsImportCaptureHook,
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def _new_import_capture_hook(
|
|
659
|
+
mod_globals: ta.MutableMapping[str, ta.Any], # noqa
|
|
660
|
+
*,
|
|
661
|
+
stack_offset: int = 0,
|
|
662
|
+
capture_impl: str | None = None,
|
|
663
|
+
**kwargs: ta.Any,
|
|
664
|
+
) -> '_ImportCaptureHook':
|
|
665
|
+
if '_frame' not in kwargs:
|
|
666
|
+
frame: types.FrameType | None = sys._getframe(1 + stack_offset) # noqa
|
|
667
|
+
if frame is None or frame.f_globals is not mod_globals:
|
|
668
|
+
raise ImportCaptureError("Can't find importing frame")
|
|
669
|
+
kwargs['_frame'] = frame
|
|
670
|
+
|
|
671
|
+
kwargs.setdefault('package', mod_globals.get('__package__'))
|
|
672
|
+
|
|
673
|
+
cls: type[_AbstractBuiltinsImportCaptureHook]
|
|
674
|
+
if capture_impl is not None:
|
|
675
|
+
cls = _CAPTURE_IMPLS[capture_impl]
|
|
676
|
+
elif _cext() is not None:
|
|
677
|
+
cls = _FrameBuiltinsImportCaptureHook
|
|
678
|
+
else:
|
|
679
|
+
cls = _SomewhatThreadSafeGlobalBuiltinsImportCaptureHook
|
|
680
|
+
|
|
681
|
+
return cls(**kwargs)
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
##
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
ImportCaptureModuleKind: ta.TypeAlias = ta.Literal[
|
|
688
|
+
'parent',
|
|
689
|
+
'terminal',
|
|
690
|
+
'leaf',
|
|
691
|
+
]
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
class ImportCapture:
|
|
695
|
+
@ta.final
|
|
696
|
+
class Module:
|
|
697
|
+
def __init__(
|
|
698
|
+
self,
|
|
699
|
+
name: str,
|
|
700
|
+
children: ta.Mapping[str, 'ImportCapture.Module'] | None = None,
|
|
701
|
+
attrs: ta.Sequence[str] | None = None,
|
|
702
|
+
) -> None:
|
|
703
|
+
self.name = name
|
|
704
|
+
self.children = children
|
|
705
|
+
self.attrs = attrs
|
|
706
|
+
|
|
707
|
+
self.base_name = name.rpartition('.')[2]
|
|
708
|
+
|
|
709
|
+
if not self.children and not self.attrs:
|
|
710
|
+
self.kind = 'leaf'
|
|
711
|
+
elif not self.children or all(c.kind == 'leaf' for c in self.children.values()):
|
|
712
|
+
self.kind = 'terminal'
|
|
713
|
+
else:
|
|
714
|
+
self.kind = 'parent'
|
|
715
|
+
|
|
716
|
+
parent: ta.Optional['ImportCapture.Module']
|
|
717
|
+
|
|
718
|
+
kind: ImportCaptureModuleKind
|
|
719
|
+
|
|
720
|
+
def __repr__(self) -> str:
|
|
721
|
+
return ''.join([
|
|
722
|
+
f'{self.__class__.__name__}(',
|
|
723
|
+
f'{self.name!r}',
|
|
724
|
+
f', :{self.kind}',
|
|
725
|
+
*([f', children=[{", ".join(map(repr, self.children))}]'] if self.children else []),
|
|
726
|
+
*([f', attrs={self.attrs!r}'] if self.attrs else []),
|
|
727
|
+
')',
|
|
728
|
+
])
|
|
729
|
+
|
|
730
|
+
_root: 'ImportCapture.Module'
|
|
731
|
+
|
|
732
|
+
@property
|
|
733
|
+
def root(self) -> 'ImportCapture.Module':
|
|
734
|
+
try:
|
|
735
|
+
return self._root
|
|
736
|
+
except AttributeError:
|
|
737
|
+
pass
|
|
738
|
+
|
|
739
|
+
root = self
|
|
740
|
+
while root.parent is not None:
|
|
741
|
+
root = root.parent
|
|
742
|
+
self._root = root
|
|
743
|
+
return root
|
|
744
|
+
|
|
745
|
+
@ta.final
|
|
746
|
+
class Import:
|
|
747
|
+
def __init__(
|
|
748
|
+
self,
|
|
749
|
+
module: 'ImportCapture.Module',
|
|
750
|
+
as_: ta.Sequence[str] | None,
|
|
751
|
+
attrs: ta.Sequence[tuple[str, str]] | None, # ('foo', 'bar') -> `import foo as bar` - explicitly not a dict # noqa
|
|
752
|
+
) -> None:
|
|
753
|
+
self.module = module
|
|
754
|
+
self.as_ = as_
|
|
755
|
+
self.attrs = attrs
|
|
756
|
+
|
|
757
|
+
def __repr__(self) -> str:
|
|
758
|
+
return ''.join([
|
|
759
|
+
f'{self.__class__.__name__}(',
|
|
760
|
+
f'{self.module.name!r}',
|
|
761
|
+
*([f', as_={self.as_!r}'] if self.as_ else []),
|
|
762
|
+
*([f', attrs={self.attrs!r}'] if self.attrs else []),
|
|
763
|
+
')',
|
|
764
|
+
])
|
|
765
|
+
|
|
766
|
+
@ta.final
|
|
767
|
+
class Captured:
|
|
768
|
+
def __init__(
|
|
769
|
+
self,
|
|
770
|
+
|
|
771
|
+
imports: ta.Mapping[str, 'ImportCapture.Import'],
|
|
772
|
+
|
|
773
|
+
modules: ta.Mapping[str, 'ImportCapture.Module'],
|
|
774
|
+
root_modules: ta.Mapping[str, 'ImportCapture.Module'],
|
|
775
|
+
|
|
776
|
+
unreferenced: ta.Sequence[str] | None,
|
|
777
|
+
) -> None:
|
|
778
|
+
self.imports = imports
|
|
779
|
+
|
|
780
|
+
self.modules = modules
|
|
781
|
+
self.root_modules = root_modules
|
|
782
|
+
|
|
783
|
+
self.unreferenced = unreferenced
|
|
784
|
+
|
|
785
|
+
@property
|
|
786
|
+
def attrs(self) -> ta.Iterator[str]:
|
|
787
|
+
for pi in self.imports.values():
|
|
788
|
+
if pi.as_:
|
|
789
|
+
yield from pi.as_
|
|
790
|
+
if pi.attrs:
|
|
791
|
+
for _, a in pi.attrs:
|
|
792
|
+
yield a
|
|
793
|
+
|
|
794
|
+
EMPTY_CAPTURED: ta.ClassVar[Captured] = Captured(
|
|
795
|
+
{},
|
|
796
|
+
{},
|
|
797
|
+
{},
|
|
798
|
+
None,
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
#
|
|
802
|
+
|
|
803
|
+
def __init__(
|
|
804
|
+
self,
|
|
805
|
+
mod_globals: ta.MutableMapping[str, ta.Any],
|
|
806
|
+
*,
|
|
807
|
+
_hook: _ImportCaptureHook,
|
|
808
|
+
|
|
809
|
+
disable: bool = False,
|
|
810
|
+
) -> None:
|
|
811
|
+
super().__init__()
|
|
812
|
+
|
|
813
|
+
self._mod_globals = mod_globals
|
|
814
|
+
self._hook = _hook
|
|
815
|
+
|
|
816
|
+
self._disabled = disable
|
|
817
|
+
|
|
818
|
+
@property
|
|
819
|
+
def disabled(self) -> bool:
|
|
820
|
+
return self._disabled
|
|
821
|
+
|
|
822
|
+
#
|
|
823
|
+
|
|
824
|
+
class _Result(ta.NamedTuple):
|
|
825
|
+
captured: 'ImportCapture.Captured'
|
|
826
|
+
|
|
827
|
+
_result_: _Result | None = None
|
|
828
|
+
|
|
829
|
+
@property
|
|
830
|
+
def _result(self) -> _Result:
|
|
831
|
+
if (rs := self._result_) is None:
|
|
832
|
+
raise ImportCaptureErrors.CaptureInProgressError
|
|
833
|
+
return rs
|
|
834
|
+
|
|
835
|
+
@property
|
|
836
|
+
def is_complete(self) -> bool:
|
|
837
|
+
return self._result_ is not None
|
|
838
|
+
|
|
839
|
+
@property
|
|
840
|
+
def captured(self) -> Captured:
|
|
841
|
+
return self._result.captured
|
|
842
|
+
|
|
843
|
+
#
|
|
844
|
+
|
|
845
|
+
@contextlib.contextmanager
|
|
846
|
+
def capture(
|
|
847
|
+
self,
|
|
848
|
+
*,
|
|
849
|
+
unreferenced_callback: ta.Callable[[ta.Sequence[str]], None] | None = None,
|
|
850
|
+
raise_unreferenced: bool = False,
|
|
851
|
+
) -> ta.Iterator[ta.Self]:
|
|
852
|
+
if self._result_ is not None:
|
|
853
|
+
raise ImportCaptureError('capture already complete')
|
|
854
|
+
|
|
855
|
+
if self._disabled:
|
|
856
|
+
self._result_ = ImportCapture._Result(
|
|
857
|
+
ImportCapture.EMPTY_CAPTURED,
|
|
858
|
+
)
|
|
859
|
+
yield self
|
|
860
|
+
return
|
|
861
|
+
|
|
862
|
+
with self._hook.hook_context(self._mod_globals):
|
|
863
|
+
yield self
|
|
864
|
+
|
|
865
|
+
self._hook.verify_state(self._mod_globals)
|
|
866
|
+
|
|
867
|
+
blt = self._hook.build_captured(
|
|
868
|
+
self._mod_globals,
|
|
869
|
+
collect_unreferenced=unreferenced_callback is not None or raise_unreferenced,
|
|
870
|
+
)
|
|
871
|
+
|
|
872
|
+
if blt.unreferenced:
|
|
873
|
+
if unreferenced_callback:
|
|
874
|
+
unreferenced_callback(blt.unreferenced)
|
|
875
|
+
if raise_unreferenced:
|
|
876
|
+
raise ImportCaptureErrors.UnreferencedImportsError(blt.unreferenced)
|
|
877
|
+
|
|
878
|
+
for a in blt.attrs:
|
|
879
|
+
del self._mod_globals[a]
|
|
880
|
+
|
|
881
|
+
self._result_ = ImportCapture._Result(
|
|
882
|
+
blt,
|
|
883
|
+
)
|
|
884
|
+
|
|
885
|
+
#
|
|
886
|
+
|
|
887
|
+
def update_exports(self) -> None:
|
|
888
|
+
cap = self._result.captured
|
|
889
|
+
|
|
890
|
+
try:
|
|
891
|
+
al: ta.Any = self._mod_globals['__all__']
|
|
892
|
+
except KeyError:
|
|
893
|
+
al = self._mod_globals['__all__'] = [k for k in self._mod_globals if not k.startswith('_')]
|
|
894
|
+
else:
|
|
895
|
+
if not isinstance(al, ta.MutableSequence):
|
|
896
|
+
al = self._mod_globals['__all__'] = list(al)
|
|
897
|
+
|
|
898
|
+
al_s = set(al)
|
|
899
|
+
for a in cap.attrs:
|
|
900
|
+
if a not in al_s:
|
|
901
|
+
al.append(a)
|
|
902
|
+
al_s.add(a)
|