nyxa 0.0.1__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.
- nyxa/__init__.py +296 -0
- nyxa/__main__.py +6 -0
- nyxa/_awaitable.py +46 -0
- nyxa/_current.py +44 -0
- nyxa/_speedups.py +170 -0
- nyxa/adapters/__init__.py +72 -0
- nyxa/adapters/asgi.py +84 -0
- nyxa/adapters/base.py +139 -0
- nyxa/adapters/cloudrun.py +103 -0
- nyxa/adapters/container.py +254 -0
- nyxa/adapters/docker.py +131 -0
- nyxa/adapters/fly.py +60 -0
- nyxa/adapters/granian.py +94 -0
- nyxa/adapters/native.py +85 -0
- nyxa/adapters/promotion.py +232 -0
- nyxa/adapters/railway.py +46 -0
- nyxa/adapters/render.py +39 -0
- nyxa/application.py +5 -0
- nyxa/asgi.py +16 -0
- nyxa/bridge/__init__.py +30 -0
- nyxa/bridge/asgi.py +561 -0
- nyxa/bridge/base.py +54 -0
- nyxa/bridge/blacksheep.py +113 -0
- nyxa/bridge/native.py +364 -0
- nyxa/bridge/rsgi.py +346 -0
- nyxa/bridge/starlette.py +81 -0
- nyxa/build/__init__.py +1 -0
- nyxa/build/binary.py +106 -0
- nyxa/build/bundle.py +501 -0
- nyxa/build/classify.py +229 -0
- nyxa/build/deps.py +548 -0
- nyxa/build/emit_config.py +138 -0
- nyxa/build/emit_container.py +78 -0
- nyxa/build/emit_discovery.py +179 -0
- nyxa/build/emit_macros.py +234 -0
- nyxa/build/emit_plans.py +304 -0
- nyxa/build/emit_routes.py +343 -0
- nyxa/build/frozen.py +193 -0
- nyxa/build/manifest.py +150 -0
- nyxa/build/suggest.py +118 -0
- nyxa/cli/__init__.py +14 -0
- nyxa/cli/ai_scaffold.py +172 -0
- nyxa/cli/commands/__init__.py +176 -0
- nyxa/cli/commands/backup.py +251 -0
- nyxa/cli/commands/catalog.py +61 -0
- nyxa/cli/commands/database.py +231 -0
- nyxa/cli/commands/deploy_promote.py +91 -0
- nyxa/cli/commands/project.py +972 -0
- nyxa/cli/commands/publish.py +166 -0
- nyxa/cli/commands/queue.py +351 -0
- nyxa/cli/commands/runtime.py +714 -0
- nyxa/cli/commands/scaffold.py +562 -0
- nyxa/cli/commands/schedule.py +313 -0
- nyxa/cli/commands/utils.py +73 -0
- nyxa/cli/commands/workflows.py +102 -0
- nyxa/cli/dev.py +204 -0
- nyxa/cli/fields.py +292 -0
- nyxa/cli/hooks.py +157 -0
- nyxa/cli/kits.py +107 -0
- nyxa/cli/local_deps.py +173 -0
- nyxa/cli/main.py +69 -0
- nyxa/cli/make.py +1484 -0
- nyxa/cli/new.py +161 -0
- nyxa/cli/ops_assist.py +48 -0
- nyxa/cli/package.py +275 -0
- nyxa/cli/runtime/__init__.py +85 -0
- nyxa/cli/runtime/bridge.py +206 -0
- nyxa/cli/runtime/process.py +82 -0
- nyxa/cli/runtime/ui/__init__.py +7 -0
- nyxa/cli/runtime/ui/app.py +58 -0
- nyxa/cli/runtime/ui/runner.py +113 -0
- nyxa/cli/runtime/ui/screens/__init__.py +7 -0
- nyxa/cli/runtime/ui/screens/home.py +416 -0
- nyxa/cli/runtime/ui/slash.py +76 -0
- nyxa/cli/runtime/ui/widgets/__init__.py +19 -0
- nyxa/cli/runtime/ui/widgets/choice_overlay.py +133 -0
- nyxa/cli/runtime/ui/widgets/chrome.py +42 -0
- nyxa/cli/runtime/ui/widgets/input_bar.py +102 -0
- nyxa/cli/runtime/ui/widgets/scrollback.py +60 -0
- nyxa/cli/runtime/ui/widgets/slash_menu.py +77 -0
- nyxa/cli/runtime/ui/widgets/status_bar.py +114 -0
- nyxa/cli/stubs/action.stub +14 -0
- nyxa/cli/stubs/agents_md.stub +47 -0
- nyxa/cli/stubs/app_provider.stub +14 -0
- nyxa/cli/stubs/binary_cargo_toml.stub +7 -0
- nyxa/cli/stubs/binary_main_rs.stub +21 -0
- nyxa/cli/stubs/command.stub +17 -0
- nyxa/cli/stubs/config_app.stub +6 -0
- nyxa/cli/stubs/config_csrf.stub +9 -0
- nyxa/cli/stubs/config_database.stub +51 -0
- nyxa/cli/stubs/config_http.stub +19 -0
- nyxa/cli/stubs/config_queue.stub +51 -0
- nyxa/cli/stubs/config_workflows.stub +20 -0
- nyxa/cli/stubs/conftest.stub +28 -0
- nyxa/cli/stubs/controller.home.stub +8 -0
- nyxa/cli/stubs/controller.invokable.stub +8 -0
- nyxa/cli/stubs/controller.model.crud.stub +31 -0
- nyxa/cli/stubs/controller.model.stub +24 -0
- nyxa/cli/stubs/controller.resource.stub +20 -0
- nyxa/cli/stubs/controller.singleton.stub +13 -0
- nyxa/cli/stubs/controller.stub +8 -0
- nyxa/cli/stubs/env_example.stub +7 -0
- nyxa/cli/stubs/event.stub +14 -0
- nyxa/cli/stubs/exception.stub +18 -0
- nyxa/cli/stubs/factory.stub +19 -0
- nyxa/cli/stubs/fly.toml.stub +19 -0
- nyxa/cli/stubs/form_request.bare.stub +21 -0
- nyxa/cli/stubs/form_request.pair.stub +25 -0
- nyxa/cli/stubs/form_request.store.stub +15 -0
- nyxa/cli/stubs/form_request.update.stub +15 -0
- nyxa/cli/stubs/gitignore.stub +9 -0
- nyxa/cli/stubs/job.stub +22 -0
- nyxa/cli/stubs/listener.stub +18 -0
- nyxa/cli/stubs/manifest.stub +10 -0
- nyxa/cli/stubs/middleware.stub +13 -0
- nyxa/cli/stubs/migration.create.fields.stub +24 -0
- nyxa/cli/stubs/migration.create.stub +24 -0
- nyxa/cli/stubs/migration.stub +17 -0
- nyxa/cli/stubs/model.fields.stub +13 -0
- nyxa/cli/stubs/model.stub +13 -0
- nyxa/cli/stubs/package.config.stub +3 -0
- nyxa/cli/stubs/package.init.stub +7 -0
- nyxa/cli/stubs/package.lang.stub +1 -0
- nyxa/cli/stubs/package.migration.stub +23 -0
- nyxa/cli/stubs/package.provider.stub +23 -0
- nyxa/cli/stubs/package.pyproject.stub +36 -0
- nyxa/cli/stubs/package.routes.stub +5 -0
- nyxa/cli/stubs/package.test.stub +17 -0
- nyxa/cli/stubs/package.view.stub +2 -0
- nyxa/cli/stubs/provider.stub +21 -0
- nyxa/cli/stubs/pyproject.stub +12 -0
- nyxa/cli/stubs/railway.toml.stub +10 -0
- nyxa/cli/stubs/render.yaml.stub +9 -0
- nyxa/cli/stubs/routes.stub +6 -0
- nyxa/cli/stubs/schedule.stub +18 -0
- nyxa/cli/stubs/seeder.stub +13 -0
- nyxa/cli/stubs/service.ai.stub +11 -0
- nyxa/cli/stubs/service.stub +5 -0
- nyxa/cli/stubs/smoke_test.stub +26 -0
- nyxa/cli/stubs/test.action.stub +15 -0
- nyxa/cli/stubs/test.command.stub +20 -0
- nyxa/cli/stubs/test.controller.invokable.stub +25 -0
- nyxa/cli/stubs/test.controller.model.crud.stub +42 -0
- nyxa/cli/stubs/test.controller.model.stub +42 -0
- nyxa/cli/stubs/test.controller.resource.stub +40 -0
- nyxa/cli/stubs/test.controller.singleton.stub +30 -0
- nyxa/cli/stubs/test.controller.stub +27 -0
- nyxa/cli/stubs/test.event.stub +22 -0
- nyxa/cli/stubs/test.exception.stub +18 -0
- nyxa/cli/stubs/test.job.stub +25 -0
- nyxa/cli/stubs/test.listener.stub +33 -0
- nyxa/cli/stubs/test.middleware.stub +25 -0
- nyxa/cli/stubs/test.provider.stub +24 -0
- nyxa/cli/stubs/test.service.stub +16 -0
- nyxa/cli/stubs/test.stub +16 -0
- nyxa/cli/stubs/test.validator.stub +16 -0
- nyxa/cli/stubs/validator.stub +9 -0
- nyxa/cli/stubs/workflow.cloudrun.yml.stub +39 -0
- nyxa/cli/stubs/workflow.docker.yml.stub +304 -0
- nyxa/cli/stubs/workflow.fly.yml.stub +27 -0
- nyxa/cli/stubs/workflow.stub +23 -0
- nyxa/cli/templates.py +134 -0
- nyxa/cli/wizard.py +576 -0
- nyxa/command.py +363 -0
- nyxa/concurrency.py +97 -0
- nyxa/config/__init__.py +41 -0
- nyxa/config/config.py +599 -0
- nyxa/config/env.py +86 -0
- nyxa/config/logging.py +285 -0
- nyxa/config/secrets.py +95 -0
- nyxa/console/__init__.py +7 -0
- nyxa/console/errors.py +30 -0
- nyxa/console/input.py +102 -0
- nyxa/console/kernel.py +340 -0
- nyxa/console/output.py +426 -0
- nyxa/console/parser.py +121 -0
- nyxa/console/signature.py +222 -0
- nyxa/container.py +24 -0
- nyxa/context.py +779 -0
- nyxa/contracts.py +276 -0
- nyxa/controller.py +130 -0
- nyxa/core/__init__.py +6 -0
- nyxa/core/application.py +1542 -0
- nyxa/core/container.py +781 -0
- nyxa/core/direct.py +321 -0
- nyxa/core/discovery.py +168 -0
- nyxa/core/ignitor.py +306 -0
- nyxa/core/maintenance.py +134 -0
- nyxa/core/manifest.py +210 -0
- nyxa/core/plugins.py +261 -0
- nyxa/core/serve.py +700 -0
- nyxa/core/settings.py +115 -0
- nyxa/core/telemetry.py +104 -0
- nyxa/db/__init__.py +109 -0
- nyxa/db/builder.py +914 -0
- nyxa/db/casts.py +178 -0
- nyxa/db/collection.py +605 -0
- nyxa/db/connection.py +565 -0
- nyxa/db/drivers/__init__.py +43 -0
- nyxa/db/drivers/base.py +140 -0
- nyxa/db/drivers/mysql.py +351 -0
- nyxa/db/drivers/postgres.py +338 -0
- nyxa/db/drivers/sqlite.py +273 -0
- nyxa/db/errors.py +73 -0
- nyxa/db/events.py +125 -0
- nyxa/db/factory.py +323 -0
- nyxa/db/grammar.py +707 -0
- nyxa/db/manager.py +328 -0
- nyxa/db/migrations.py +383 -0
- nyxa/db/model.py +1597 -0
- nyxa/db/pagination.py +142 -0
- nyxa/db/plan.py +128 -0
- nyxa/db/provider.py +7 -0
- nyxa/db/query.py +612 -0
- nyxa/db/relations.py +1084 -0
- nyxa/db/schema.py +308 -0
- nyxa/db/seeder.py +105 -0
- nyxa/db/sync.py +357 -0
- nyxa/db/traits.py +105 -0
- nyxa/db/vectors.py +92 -0
- nyxa/dev/__init__.py +7 -0
- nyxa/dev/access.py +53 -0
- nyxa/dev/introspect.py +377 -0
- nyxa/dev/snapshot.py +436 -0
- nyxa/discovery.py +19 -0
- nyxa/env.py +5 -0
- nyxa/errors.py +245 -0
- nyxa/events.py +748 -0
- nyxa/exceptions.py +131 -0
- nyxa/helpers/__init__.py +195 -0
- nyxa/helpers/ambient.py +826 -0
- nyxa/helpers/benchmark.py +36 -0
- nyxa/helpers/bounded.py +232 -0
- nyxa/helpers/core.py +876 -0
- nyxa/helpers/dates.py +46 -0
- nyxa/helpers/payload.py +99 -0
- nyxa/helpers/pipeline.py +115 -0
- nyxa/helpers/timebox.py +54 -0
- nyxa/http/__init__.py +105 -0
- nyxa/http/context.py +541 -0
- nyxa/http/ctx_snapshot.py +146 -0
- nyxa/http/exceptions.py +228 -0
- nyxa/http/headers.py +68 -0
- nyxa/http/multipart.py +168 -0
- nyxa/http/params.py +416 -0
- nyxa/http/request.py +671 -0
- nyxa/http/response.py +969 -0
- nyxa/http/streaming.py +93 -0
- nyxa/http/streams.py +144 -0
- nyxa/http/websocket.py +194 -0
- nyxa/ignitor.py +6 -0
- nyxa/logging.py +9 -0
- nyxa/manifest.py +5 -0
- nyxa/middleware/__init__.py +75 -0
- nyxa/middleware/access_log.py +80 -0
- nyxa/middleware/context.py +40 -0
- nyxa/middleware/cors.py +172 -0
- nyxa/middleware/csrf.py +287 -0
- nyxa/middleware/discovery.py +58 -0
- nyxa/middleware/gzip.py +128 -0
- nyxa/middleware/https_redirect.py +54 -0
- nyxa/middleware/phase.py +222 -0
- nyxa/middleware/pipeline.py +264 -0
- nyxa/middleware/registry.py +75 -0
- nyxa/middleware/trusted_host.py +71 -0
- nyxa/monitoring/__init__.py +15 -0
- nyxa/monitoring/alerts.py +173 -0
- nyxa/monitoring/errors.py +79 -0
- nyxa/openapi.py +243 -0
- nyxa/playground.py +334 -0
- nyxa/playground_actions.py +228 -0
- nyxa/playground_terminal.py +324 -0
- nyxa/plugins.py +5 -0
- nyxa/plugins_catalog.py +182 -0
- nyxa/process.py +1351 -0
- nyxa/providers/__init__.py +24 -0
- nyxa/providers/base.py +440 -0
- nyxa/providers/core.py +392 -0
- nyxa/providers/database.py +88 -0
- nyxa/providers/queue.py +148 -0
- nyxa/providers/schedule.py +70 -0
- nyxa/providers/workflows.py +75 -0
- nyxa/py.typed +0 -0
- nyxa/pytest_plugin.py +55 -0
- nyxa/queue/__init__.py +118 -0
- nyxa/queue/driver.py +528 -0
- nyxa/queue/drivers/__init__.py +8 -0
- nyxa/queue/drivers/memory.py +381 -0
- nyxa/queue/drivers/sync.py +128 -0
- nyxa/queue/events.py +293 -0
- nyxa/queue/job.py +622 -0
- nyxa/queue/listener.py +95 -0
- nyxa/queue/manager.py +757 -0
- nyxa/queue/middleware.py +81 -0
- nyxa/queue/provider.py +7 -0
- nyxa/queue/stores/__init__.py +17 -0
- nyxa/queue/stores/db.py +320 -0
- nyxa/queue/testing.py +186 -0
- nyxa/queue/worker.py +547 -0
- nyxa/routing/__init__.py +44 -0
- nyxa/routing/ambient.py +930 -0
- nyxa/routing/compiler.py +188 -0
- nyxa/routing/plan.py +1491 -0
- nyxa/routing/refs.py +115 -0
- nyxa/routing/route.py +958 -0
- nyxa/routing/router.py +1494 -0
- nyxa/routing/static.py +122 -0
- nyxa/routing/tree.py +347 -0
- nyxa/rsgi.py +13 -0
- nyxa/scheduling/__init__.py +49 -0
- nyxa/scheduling/cron.py +162 -0
- nyxa/scheduling/runner.py +296 -0
- nyxa/scheduling/schedule.py +618 -0
- nyxa/scheduling/store.py +221 -0
- nyxa/security.py +332 -0
- nyxa/server.py +259 -0
- nyxa/services.py +111 -0
- nyxa/testing/__init__.py +876 -0
- nyxa/testing/browser.py +172 -0
- nyxa/testing/jobs.py +209 -0
- nyxa/types.py +252 -0
- nyxa/upgrade/__init__.py +1 -0
- nyxa/upgrade/codemods.py +190 -0
- nyxa/warmup.py +27 -0
- nyxa/workflows/__init__.py +53 -0
- nyxa/workflows/events.py +72 -0
- nyxa/workflows/executor.py +353 -0
- nyxa/workflows/manager.py +182 -0
- nyxa/workflows/store.py +240 -0
- nyxa/workflows/workflow.py +211 -0
- nyxa/wsgi.py +230 -0
- nyxa-0.0.1.dist-info/METADATA +317 -0
- nyxa-0.0.1.dist-info/RECORD +336 -0
- nyxa-0.0.1.dist-info/WHEEL +4 -0
- nyxa-0.0.1.dist-info/entry_points.txt +6 -0
- nyxa-0.0.1.dist-info/licenses/LICENSE +21 -0
nyxa/__init__.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""Nyxa — a standalone backend framework for Python."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
# Declared for static analyzers; the real bindings resolve lazily via
|
|
7
|
+
# ``__getattr__`` below so ``import nyxa`` stays near-free.
|
|
8
|
+
from nyxa.command import Command
|
|
9
|
+
from nyxa.config.config import define_config
|
|
10
|
+
from nyxa.config.env import Env
|
|
11
|
+
from nyxa.context import Context
|
|
12
|
+
from nyxa.controller import Controller, Middleware
|
|
13
|
+
from nyxa.core.application import Application
|
|
14
|
+
from nyxa.core.container import (
|
|
15
|
+
CircularDependencyError,
|
|
16
|
+
Container,
|
|
17
|
+
ContainerError,
|
|
18
|
+
Inject,
|
|
19
|
+
Provider,
|
|
20
|
+
ResolutionError,
|
|
21
|
+
Scope,
|
|
22
|
+
)
|
|
23
|
+
from nyxa.db.collection import Collection
|
|
24
|
+
from nyxa.db.factory import Factory
|
|
25
|
+
from nyxa.db.manager import DB, Schema
|
|
26
|
+
from nyxa.db.migrations import Migration
|
|
27
|
+
from nyxa.db.model import Model
|
|
28
|
+
from nyxa.db.seeder import Seeder
|
|
29
|
+
from nyxa.db.traits import SoftDeletes
|
|
30
|
+
from nyxa.errors import NyxaError
|
|
31
|
+
from nyxa.events import Event, EventEmitter, Listener
|
|
32
|
+
from nyxa.exceptions import ExceptionHandler, HttpExceptionHandler
|
|
33
|
+
from nyxa.http.context import HttpContext, get_request, use
|
|
34
|
+
from nyxa.http.exceptions import (
|
|
35
|
+
BadRequestException,
|
|
36
|
+
ConflictException,
|
|
37
|
+
ForbiddenException,
|
|
38
|
+
HttpException,
|
|
39
|
+
InternalServerErrorException,
|
|
40
|
+
MethodNotAllowedException,
|
|
41
|
+
ModelNotFound,
|
|
42
|
+
NotFoundException,
|
|
43
|
+
ServiceUnavailableException,
|
|
44
|
+
TooManyRequestsException,
|
|
45
|
+
UnauthorizedException,
|
|
46
|
+
ValidationException,
|
|
47
|
+
abort,
|
|
48
|
+
)
|
|
49
|
+
from nyxa.http.params import Body, Cookie, Files, Form, Header, Ip, Path, Query
|
|
50
|
+
from nyxa.http.request import Request
|
|
51
|
+
from nyxa.http.response import Response, ResponseBuilder, use_response
|
|
52
|
+
from nyxa.http.streaming import sse_event, sse_stream
|
|
53
|
+
from nyxa.http.websocket import Ws, WsClosed
|
|
54
|
+
from nyxa.middleware import MiddlewareRegistry
|
|
55
|
+
from nyxa.process import Process
|
|
56
|
+
from nyxa.providers import ServiceProvider
|
|
57
|
+
from nyxa.routing import Route, RouteError, Router
|
|
58
|
+
from nyxa.routing.ambient import router
|
|
59
|
+
from nyxa.testing import TestClient
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _package_version() -> str:
|
|
63
|
+
"""Return the installed ``nyxa`` distribution version.
|
|
64
|
+
|
|
65
|
+
Source of truth is ``packages/nyxa/pyproject.toml`` (stamped by
|
|
66
|
+
``.github/sync_version.py`` on release). Falls back when the package
|
|
67
|
+
metadata is not on ``sys.path`` yet (raw source tree).
|
|
68
|
+
"""
|
|
69
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
return version("nyxa")
|
|
73
|
+
except PackageNotFoundError:
|
|
74
|
+
from pathlib import Path
|
|
75
|
+
from tomllib import loads
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
manifest = loads((Path(__file__).resolve().parents[2] / "pyproject.toml").read_text())
|
|
79
|
+
return str(manifest["project"]["version"])
|
|
80
|
+
except (KeyError, OSError):
|
|
81
|
+
return "0.0.0+local"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
__version__ = _package_version()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
__all__ = [
|
|
88
|
+
"DB",
|
|
89
|
+
"Application",
|
|
90
|
+
"BadRequestException",
|
|
91
|
+
"Body",
|
|
92
|
+
"CircularDependencyError",
|
|
93
|
+
"Collection",
|
|
94
|
+
"Command",
|
|
95
|
+
"ConflictException",
|
|
96
|
+
"Container",
|
|
97
|
+
"ContainerError",
|
|
98
|
+
"Context",
|
|
99
|
+
"Controller",
|
|
100
|
+
"Cookie",
|
|
101
|
+
"Env",
|
|
102
|
+
"Event",
|
|
103
|
+
"EventEmitter",
|
|
104
|
+
"ExceptionHandler",
|
|
105
|
+
"Factory",
|
|
106
|
+
"Files",
|
|
107
|
+
"ForbiddenException",
|
|
108
|
+
"Form",
|
|
109
|
+
"Header",
|
|
110
|
+
"HttpContext",
|
|
111
|
+
"HttpException",
|
|
112
|
+
"HttpExceptionHandler",
|
|
113
|
+
"Inject",
|
|
114
|
+
"InternalServerErrorException",
|
|
115
|
+
"Ip",
|
|
116
|
+
"Listener",
|
|
117
|
+
"MethodNotAllowedException",
|
|
118
|
+
"Middleware",
|
|
119
|
+
"MiddlewareRegistry",
|
|
120
|
+
"Migration",
|
|
121
|
+
"Model",
|
|
122
|
+
"ModelNotFound",
|
|
123
|
+
"NotFoundException",
|
|
124
|
+
"NyxaError",
|
|
125
|
+
"Path",
|
|
126
|
+
"Process",
|
|
127
|
+
"Provider",
|
|
128
|
+
"Query",
|
|
129
|
+
"Request",
|
|
130
|
+
"ResolutionError",
|
|
131
|
+
"Response",
|
|
132
|
+
"ResponseBuilder",
|
|
133
|
+
"Route",
|
|
134
|
+
"RouteError",
|
|
135
|
+
"Router",
|
|
136
|
+
"Schema",
|
|
137
|
+
"Scope",
|
|
138
|
+
"Seeder",
|
|
139
|
+
"ServiceProvider",
|
|
140
|
+
"ServiceUnavailableException",
|
|
141
|
+
"SoftDeletes",
|
|
142
|
+
"TestClient",
|
|
143
|
+
"TooManyRequestsException",
|
|
144
|
+
"UnauthorizedException",
|
|
145
|
+
"ValidationException",
|
|
146
|
+
"Ws",
|
|
147
|
+
"WsClosed",
|
|
148
|
+
"__version__",
|
|
149
|
+
"abort",
|
|
150
|
+
"define_config",
|
|
151
|
+
"get_request",
|
|
152
|
+
"router",
|
|
153
|
+
"sse_event",
|
|
154
|
+
"sse_stream",
|
|
155
|
+
"use",
|
|
156
|
+
"use_response",
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
# Every public name → the module that defines it. ``import nyxa`` pays for
|
|
160
|
+
# nothing but this module object; a name imports its backing module on first
|
|
161
|
+
# access and caches the result in ``globals()``.
|
|
162
|
+
_LAZY = {
|
|
163
|
+
"Application": "nyxa.core.application",
|
|
164
|
+
"Command": "nyxa.command",
|
|
165
|
+
"Context": "nyxa.context",
|
|
166
|
+
"define_config": "nyxa.config.config",
|
|
167
|
+
"CircularDependencyError": "nyxa.core.container",
|
|
168
|
+
"Container": "nyxa.core.container",
|
|
169
|
+
"ContainerError": "nyxa.core.container",
|
|
170
|
+
"Inject": "nyxa.core.container",
|
|
171
|
+
"Provider": "nyxa.core.container",
|
|
172
|
+
"ResolutionError": "nyxa.core.container",
|
|
173
|
+
"Scope": "nyxa.core.container",
|
|
174
|
+
"Controller": "nyxa.controller",
|
|
175
|
+
"Middleware": "nyxa.controller",
|
|
176
|
+
"Env": "nyxa.config.env",
|
|
177
|
+
"Event": "nyxa.events",
|
|
178
|
+
"EventEmitter": "nyxa.events",
|
|
179
|
+
"Listener": "nyxa.events",
|
|
180
|
+
"NyxaError": "nyxa.errors",
|
|
181
|
+
"ExceptionHandler": "nyxa.exceptions",
|
|
182
|
+
"HttpExceptionHandler": "nyxa.exceptions",
|
|
183
|
+
"BadRequestException": "nyxa.http.exceptions",
|
|
184
|
+
"ConflictException": "nyxa.http.exceptions",
|
|
185
|
+
"ForbiddenException": "nyxa.http.exceptions",
|
|
186
|
+
"HttpException": "nyxa.http.exceptions",
|
|
187
|
+
"InternalServerErrorException": "nyxa.http.exceptions",
|
|
188
|
+
"MethodNotAllowedException": "nyxa.http.exceptions",
|
|
189
|
+
"ModelNotFound": "nyxa.http.exceptions",
|
|
190
|
+
"NotFoundException": "nyxa.http.exceptions",
|
|
191
|
+
"ServiceUnavailableException": "nyxa.http.exceptions",
|
|
192
|
+
"TooManyRequestsException": "nyxa.http.exceptions",
|
|
193
|
+
"UnauthorizedException": "nyxa.http.exceptions",
|
|
194
|
+
"ValidationException": "nyxa.http.exceptions",
|
|
195
|
+
"abort": "nyxa.http.exceptions",
|
|
196
|
+
"Body": "nyxa.http.params",
|
|
197
|
+
"Cookie": "nyxa.http.params",
|
|
198
|
+
"Files": "nyxa.http.params",
|
|
199
|
+
"Form": "nyxa.http.params",
|
|
200
|
+
"Header": "nyxa.http.params",
|
|
201
|
+
"Ip": "nyxa.http.params",
|
|
202
|
+
"Path": "nyxa.http.params",
|
|
203
|
+
"Query": "nyxa.http.params",
|
|
204
|
+
"HttpContext": "nyxa.http.context",
|
|
205
|
+
"get_request": "nyxa.http.context",
|
|
206
|
+
"use": "nyxa.http.context",
|
|
207
|
+
"Request": "nyxa.http.request",
|
|
208
|
+
"Response": "nyxa.http.response",
|
|
209
|
+
"ResponseBuilder": "nyxa.http.response",
|
|
210
|
+
"use_response": "nyxa.http.response",
|
|
211
|
+
"sse_event": "nyxa.http.streaming",
|
|
212
|
+
"sse_stream": "nyxa.http.streaming",
|
|
213
|
+
"Ws": "nyxa.http.websocket",
|
|
214
|
+
"WsClosed": "nyxa.http.websocket",
|
|
215
|
+
"MiddlewareRegistry": "nyxa.middleware",
|
|
216
|
+
"Process": "nyxa.process",
|
|
217
|
+
"ServiceProvider": "nyxa.providers",
|
|
218
|
+
"Route": "nyxa.routing",
|
|
219
|
+
"RouteError": "nyxa.routing",
|
|
220
|
+
"Router": "nyxa.routing",
|
|
221
|
+
"router": "nyxa.routing.ambient",
|
|
222
|
+
"TestClient": "nyxa.testing",
|
|
223
|
+
"Collection": "nyxa.db.collection",
|
|
224
|
+
"DB": "nyxa.db.manager",
|
|
225
|
+
"Schema": "nyxa.db.manager",
|
|
226
|
+
"Factory": "nyxa.db.factory",
|
|
227
|
+
"Migration": "nyxa.db.migrations",
|
|
228
|
+
"Model": "nyxa.db.model",
|
|
229
|
+
"Seeder": "nyxa.db.seeder",
|
|
230
|
+
"SoftDeletes": "nyxa.db.traits",
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Submodules reachable as attributes (``nyxa.db`` without an explicit
|
|
234
|
+
# ``import nyxa.db``) — resolved lazily the same way.
|
|
235
|
+
_MODULES = frozenset(
|
|
236
|
+
{
|
|
237
|
+
"adapters",
|
|
238
|
+
"application",
|
|
239
|
+
"asgi",
|
|
240
|
+
"bridge",
|
|
241
|
+
"build",
|
|
242
|
+
"cli",
|
|
243
|
+
"command",
|
|
244
|
+
"config",
|
|
245
|
+
"console",
|
|
246
|
+
"container",
|
|
247
|
+
"context",
|
|
248
|
+
"contracts",
|
|
249
|
+
"core",
|
|
250
|
+
"controller",
|
|
251
|
+
"db",
|
|
252
|
+
"discovery",
|
|
253
|
+
"env",
|
|
254
|
+
"errors",
|
|
255
|
+
"events",
|
|
256
|
+
"exceptions",
|
|
257
|
+
"helpers",
|
|
258
|
+
"http",
|
|
259
|
+
"ignitor",
|
|
260
|
+
"logging",
|
|
261
|
+
"manifest",
|
|
262
|
+
"middleware",
|
|
263
|
+
"openapi",
|
|
264
|
+
"plugins",
|
|
265
|
+
"process",
|
|
266
|
+
"providers",
|
|
267
|
+
"pytest_plugin",
|
|
268
|
+
"queue",
|
|
269
|
+
"routing",
|
|
270
|
+
"rsgi",
|
|
271
|
+
"scheduling",
|
|
272
|
+
"security",
|
|
273
|
+
"server",
|
|
274
|
+
"testing",
|
|
275
|
+
"types",
|
|
276
|
+
"workflows",
|
|
277
|
+
"wsgi",
|
|
278
|
+
}
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# Any required — PEP 562 lazy re-export: the resolved type is unknowable at the
|
|
283
|
+
# signature level (dynamic-attribute carve-out).
|
|
284
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401 — see comment above
|
|
285
|
+
"""Lazy public surface — names and submodules import on first access."""
|
|
286
|
+
import importlib
|
|
287
|
+
|
|
288
|
+
module = _LAZY.get(name)
|
|
289
|
+
if module is not None:
|
|
290
|
+
value = getattr(importlib.import_module(module), name)
|
|
291
|
+
elif name in _MODULES:
|
|
292
|
+
value = importlib.import_module(f"nyxa.{name}")
|
|
293
|
+
else:
|
|
294
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
295
|
+
globals()[name] = value
|
|
296
|
+
return value
|
nyxa/__main__.py
ADDED
nyxa/_awaitable.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Fast awaitable probe for hot paths.
|
|
2
|
+
|
|
3
|
+
``inspect.isawaitable`` falls through to an ABC ``isinstance`` for every value
|
|
4
|
+
that is not a coroutine, which dominates the cost of the common case (a
|
|
5
|
+
handler returned a plain model, dict or ``None``). Awaitability is a property
|
|
6
|
+
of the *type* (the one exception, generator-based coroutines, is excluded), so
|
|
7
|
+
negative answers are memoized per type.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
from collections.abc import Awaitable
|
|
14
|
+
from types import CoroutineType, GeneratorType
|
|
15
|
+
from typing import TypeGuard
|
|
16
|
+
|
|
17
|
+
_NOT_AWAITABLE: set[type] = {type(None), bool, int, float, str, bytes, dict, list, tuple}
|
|
18
|
+
_NOT_AWAITABLE_MAX = 4096
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_awaitable(obj: object) -> TypeGuard[Awaitable[object]]:
|
|
22
|
+
"""Whether ``await obj`` is valid — same answer as :func:`inspect.isawaitable`.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
obj: Any handler/listener/hook result.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
``True`` for coroutines, futures and other awaitables.
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
>>> is_awaitable(1), is_awaitable(None)
|
|
32
|
+
(False, False)
|
|
33
|
+
"""
|
|
34
|
+
kind = type(obj)
|
|
35
|
+
if kind is CoroutineType:
|
|
36
|
+
return True
|
|
37
|
+
if kind in _NOT_AWAITABLE:
|
|
38
|
+
return False
|
|
39
|
+
if inspect.isawaitable(obj):
|
|
40
|
+
return True
|
|
41
|
+
if kind is not GeneratorType and len(_NOT_AWAITABLE) < _NOT_AWAITABLE_MAX:
|
|
42
|
+
_NOT_AWAITABLE.add(kind)
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = ["is_awaitable"]
|
nyxa/_current.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Process-local reference to the most recently created Application.
|
|
2
|
+
|
|
3
|
+
Lets module-level helpers that have no app handle — bare
|
|
4
|
+
``Job.dispatch(...)`` and the ``DB``/``Schema`` facades are the canonical
|
|
5
|
+
cases — reach the lazily bound managers without importing feature stacks
|
|
6
|
+
at boot. ``tick()`` orders app construction against facade bindings so
|
|
7
|
+
"most recently bound wins" keeps working across lazy creation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import weakref
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from nyxa.core.application import Application
|
|
17
|
+
|
|
18
|
+
_app: weakref.ReferenceType[Application] | None = None
|
|
19
|
+
_app_seq = 0
|
|
20
|
+
_tick = 0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def tick() -> int:
|
|
24
|
+
"""Monotonic sequence — bump on app creation and facade binds."""
|
|
25
|
+
global _tick
|
|
26
|
+
_tick += 1
|
|
27
|
+
return _tick
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def set_app(app: Application) -> None:
|
|
31
|
+
"""Record ``app`` as the current application."""
|
|
32
|
+
global _app, _app_seq
|
|
33
|
+
_app = weakref.ref(app)
|
|
34
|
+
_app_seq = tick()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_app() -> Application | None:
|
|
38
|
+
"""The most recently created live application, or ``None``."""
|
|
39
|
+
return _app() if _app is not None else None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def app_seq() -> int:
|
|
43
|
+
"""The sequence at which the current app was created."""
|
|
44
|
+
return _app_seq
|
nyxa/_speedups.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Bundled native accelerators behind pure-Python references.
|
|
2
|
+
|
|
3
|
+
``nyxa-speedups`` is a separate compiled distribution. Each helper here has a
|
|
4
|
+
Python reference implementation with identical results; the native version
|
|
5
|
+
handles the common inputs and returns ``None`` for anything else (non-ASCII,
|
|
6
|
+
quoted cookies, unusual header items), which falls back to the reference.
|
|
7
|
+
Set ``NYXA_NO_SPEEDUPS=1`` to force the Python versions.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import importlib
|
|
13
|
+
import os
|
|
14
|
+
from collections.abc import Callable, Iterable, Mapping
|
|
15
|
+
from http.cookies import SimpleCookie
|
|
16
|
+
from types import ModuleType
|
|
17
|
+
from urllib.parse import parse_qsl
|
|
18
|
+
|
|
19
|
+
from nyxa.types import FormValue, NativeHeaderIndex, NativeMatcher
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load() -> ModuleType | None:
|
|
23
|
+
if os.environ.get("NYXA_NO_SPEEDUPS"):
|
|
24
|
+
return None
|
|
25
|
+
try:
|
|
26
|
+
return importlib.import_module("nyxa_speedups")
|
|
27
|
+
except ImportError:
|
|
28
|
+
return None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
native: ModuleType | None = _load()
|
|
32
|
+
"""The ``nyxa_speedups`` module, or ``None`` when absent or disabled."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def py_parse_query(qs: str) -> dict[str, str]:
|
|
36
|
+
"""Reference: query-string parameters, last value wins, blanks kept."""
|
|
37
|
+
return dict(parse_qsl(qs, keep_blank_values=True))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def py_parse_cookies(header: str) -> dict[str, str]:
|
|
41
|
+
"""Reference: ``Cookie`` header as ``SimpleCookie`` reads it."""
|
|
42
|
+
jar = SimpleCookie(header)
|
|
43
|
+
return {k: morsel.value for k, morsel in jar.items()}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def py_parse_query_multi(qs: str) -> dict[str, str | list[str]]:
|
|
47
|
+
"""Reference: ``parse_qsl`` with repeated keys collapsed into lists."""
|
|
48
|
+
out: dict[str, str | list[str]] = {}
|
|
49
|
+
for k, v in parse_qsl(qs, keep_blank_values=True):
|
|
50
|
+
if k in out:
|
|
51
|
+
existing = out[k]
|
|
52
|
+
if isinstance(existing, list):
|
|
53
|
+
existing.append(v)
|
|
54
|
+
else:
|
|
55
|
+
out[k] = [existing, v]
|
|
56
|
+
else:
|
|
57
|
+
out[k] = v
|
|
58
|
+
return out
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _with_fallback[T, R](fast: Callable[[T], R | None], reference: Callable[[T], R]) -> Callable[[T], R]:
|
|
62
|
+
"""Wrap ``fast`` so a ``None`` result re-runs through ``reference``."""
|
|
63
|
+
|
|
64
|
+
def parse(value: T) -> R:
|
|
65
|
+
result = fast(value)
|
|
66
|
+
return result if result is not None else reference(value)
|
|
67
|
+
|
|
68
|
+
parse.__doc__ = reference.__doc__
|
|
69
|
+
return parse
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if native is not None:
|
|
73
|
+
parse_query: Callable[[str], dict[str, str]] = _with_fallback(native.parse_query, py_parse_query)
|
|
74
|
+
parse_cookies: Callable[[str], dict[str, str]] = _with_fallback(native.parse_cookies, py_parse_cookies)
|
|
75
|
+
parse_query_multi: Callable[[str], dict[str, str | list[str]]] = _with_fallback(
|
|
76
|
+
native.parse_query_multi, py_parse_query_multi
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
parse_query = py_parse_query
|
|
80
|
+
parse_cookies = py_parse_cookies
|
|
81
|
+
parse_query_multi = py_parse_query_multi
|
|
82
|
+
|
|
83
|
+
Matcher: type[NativeMatcher] | None = native.Matcher if native is not None else None
|
|
84
|
+
"""Native route matcher class (see ``RouteTree``), or ``None``."""
|
|
85
|
+
|
|
86
|
+
scan_headers: Callable[[Iterable[tuple[bytes, bytes]]], tuple[bytes | None, bool] | None] | None = (
|
|
87
|
+
native.scan_headers if native is not None else None
|
|
88
|
+
)
|
|
89
|
+
"""``(x-request-id, declares_body)`` over ASGI headers, ``None`` to fall back; or ``None``."""
|
|
90
|
+
|
|
91
|
+
encode_headers: Callable[[dict[str, str]], list[tuple[bytes, bytes]] | None] | None = (
|
|
92
|
+
native.encode_headers if native is not None else None
|
|
93
|
+
)
|
|
94
|
+
"""ASGI response header list for ASCII headers, ``None`` to fall back; or ``None``."""
|
|
95
|
+
|
|
96
|
+
parse_multipart: (
|
|
97
|
+
Callable[
|
|
98
|
+
[bytes, bytes, int, int, int | None],
|
|
99
|
+
tuple[dict[str, FormValue], list[tuple[str, str, str, bytes]]] | None,
|
|
100
|
+
]
|
|
101
|
+
| None
|
|
102
|
+
) = getattr(native, "parse_multipart", None) if native is not None else None
|
|
103
|
+
"""Multipart boundary scanner — ``(fields, file_parts)`` or ``None`` to fall back."""
|
|
104
|
+
|
|
105
|
+
header_index: Callable[[Iterable[tuple[bytes, bytes]]], NativeHeaderIndex | None] | None = (
|
|
106
|
+
getattr(native, "header_index", None) if native is not None else None
|
|
107
|
+
)
|
|
108
|
+
"""Build a ``HeaderIndex`` over raw ASGI header pairs, ``None`` to fall back; or ``None``."""
|
|
109
|
+
|
|
110
|
+
flatten_headers: Callable[[dict[str, str | list[str]]], list[tuple[str, str]] | None] | None = (
|
|
111
|
+
getattr(native, "flatten_headers", None) if native is not None else None
|
|
112
|
+
)
|
|
113
|
+
"""``header_items`` equivalent, ``None`` to fall back; or ``None``."""
|
|
114
|
+
|
|
115
|
+
normalize_headers: Callable[[dict[str, str | list[str]], dict[str, object]], tuple[()] | None] | None = (
|
|
116
|
+
getattr(native, "normalize_headers", None) if native is not None else None
|
|
117
|
+
)
|
|
118
|
+
"""Default-header merge into a response's dict in place, ``None`` to fall back; or ``None``."""
|
|
119
|
+
|
|
120
|
+
native_sign_cookie: Callable[[str, str, bool], str] | None = (
|
|
121
|
+
getattr(native, "sign_cookie", None) if native is not None else None
|
|
122
|
+
)
|
|
123
|
+
"""Fused ``<b64>.<hmac>`` signer, or ``None`` when the wheel is absent."""
|
|
124
|
+
|
|
125
|
+
native_verify_cookie: Callable[[str, str, float | None], str | None] | None = (
|
|
126
|
+
getattr(native, "verify_cookie", None) if native is not None else None
|
|
127
|
+
)
|
|
128
|
+
"""Fused signed-cookie verify, ``None`` on invalid or unusual input; or ``None``."""
|
|
129
|
+
|
|
130
|
+
url_build: Callable[[str, Mapping[str, object], Mapping[str, str], Mapping[str, str]], str | None] | None = (
|
|
131
|
+
getattr(native, "url_build", None) if native is not None else None
|
|
132
|
+
)
|
|
133
|
+
"""Route URL substitution + constraint checks, ``None`` to fall back; or ``None``."""
|
|
134
|
+
|
|
135
|
+
validate_plan: (
|
|
136
|
+
Callable[
|
|
137
|
+
[dict[str, list[tuple[int, list[str], int]]], dict[str, object]],
|
|
138
|
+
dict[str, dict[str, list[int]]] | None,
|
|
139
|
+
]
|
|
140
|
+
| None
|
|
141
|
+
) = getattr(native, "validate_plan", None) if native is not None else None
|
|
142
|
+
"""Native evaluation of a compiled validation plan's pure rules; or ``None``."""
|
|
143
|
+
|
|
144
|
+
native_rule_ids: dict[str, int] = dict(getattr(native, "NATIVE_RULE_IDS", {})) if native is not None else {}
|
|
145
|
+
"""rule name → plan id for the native-evaluable pure rules; empty when absent."""
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def py_paginate_to_json(rows: list[dict[str, object]], meta: Mapping[str, object]) -> bytes:
|
|
149
|
+
"""Reference: ``{data, meta}`` envelope via orjson (plain JSON scalars only)."""
|
|
150
|
+
import orjson
|
|
151
|
+
|
|
152
|
+
return orjson.dumps({"data": rows, "meta": dict(meta)})
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _native_paginate_to_json(rows: list[dict[str, object]], meta: Mapping[str, object]) -> bytes | None:
|
|
156
|
+
"""Call the Rust encoder; ``None`` means fall back to Python."""
|
|
157
|
+
if native is None:
|
|
158
|
+
return None
|
|
159
|
+
fn = getattr(native, "paginate_to_json", None)
|
|
160
|
+
if fn is None:
|
|
161
|
+
return None
|
|
162
|
+
return fn(rows, dict(meta))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
paginate_to_json: Callable[[list[dict[str, object]], Mapping[str, object]], bytes] = (
|
|
166
|
+
(lambda rows, meta: _native_paginate_to_json(rows, meta) or py_paginate_to_json(rows, meta))
|
|
167
|
+
if native is not None
|
|
168
|
+
else py_paginate_to_json
|
|
169
|
+
)
|
|
170
|
+
"""``{data, meta}`` JSON bytes — native when installed, else orjson."""
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Deployment adapters — the platform contract and the built-ins."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from nyxa.adapters.asgi import AsgiAdapter
|
|
7
|
+
from nyxa.adapters.base import (
|
|
8
|
+
Adapter,
|
|
9
|
+
AdapterError,
|
|
10
|
+
Capabilities,
|
|
11
|
+
collect_adapters,
|
|
12
|
+
required_capabilities,
|
|
13
|
+
spawn,
|
|
14
|
+
)
|
|
15
|
+
from nyxa.adapters.cloudrun import CloudRunAdapter
|
|
16
|
+
from nyxa.adapters.container import ContainerAdapter
|
|
17
|
+
from nyxa.adapters.docker import DockerAdapter
|
|
18
|
+
from nyxa.adapters.fly import FlyAdapter
|
|
19
|
+
from nyxa.adapters.granian import GranianAdapter
|
|
20
|
+
from nyxa.adapters.native import NativeAdapter
|
|
21
|
+
from nyxa.adapters.railway import RailwayAdapter
|
|
22
|
+
from nyxa.adapters.render import RenderAdapter
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"Adapter",
|
|
26
|
+
"AdapterError",
|
|
27
|
+
"AsgiAdapter",
|
|
28
|
+
"Capabilities",
|
|
29
|
+
"CloudRunAdapter",
|
|
30
|
+
"ContainerAdapter",
|
|
31
|
+
"DockerAdapter",
|
|
32
|
+
"FlyAdapter",
|
|
33
|
+
"GranianAdapter",
|
|
34
|
+
"NativeAdapter",
|
|
35
|
+
"RailwayAdapter",
|
|
36
|
+
"RenderAdapter",
|
|
37
|
+
"collect_adapters",
|
|
38
|
+
"required_capabilities",
|
|
39
|
+
"spawn",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
_LAZY = {
|
|
43
|
+
"AsgiAdapter": "nyxa.adapters.asgi",
|
|
44
|
+
"Adapter": "nyxa.adapters.base",
|
|
45
|
+
"AdapterError": "nyxa.adapters.base",
|
|
46
|
+
"Capabilities": "nyxa.adapters.base",
|
|
47
|
+
"CloudRunAdapter": "nyxa.adapters.cloudrun",
|
|
48
|
+
"ContainerAdapter": "nyxa.adapters.container",
|
|
49
|
+
"collect_adapters": "nyxa.adapters.base",
|
|
50
|
+
"required_capabilities": "nyxa.adapters.base",
|
|
51
|
+
"spawn": "nyxa.adapters.base",
|
|
52
|
+
"DockerAdapter": "nyxa.adapters.docker",
|
|
53
|
+
"FlyAdapter": "nyxa.adapters.fly",
|
|
54
|
+
"GranianAdapter": "nyxa.adapters.granian",
|
|
55
|
+
"NativeAdapter": "nyxa.adapters.native",
|
|
56
|
+
"RailwayAdapter": "nyxa.adapters.railway",
|
|
57
|
+
"RenderAdapter": "nyxa.adapters.render",
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Any required — PEP 562 lazy re-export: the resolved type is unknowable at the
|
|
62
|
+
# signature level (dynamic-attribute carve-out).
|
|
63
|
+
def __getattr__(name: str) -> Any: # noqa: ANN401 — see comment above
|
|
64
|
+
"""Lazy attribute exports — keeps ``import nyxa.adapters`` cheap."""
|
|
65
|
+
module = _LAZY.get(name)
|
|
66
|
+
if module is None:
|
|
67
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
68
|
+
import importlib
|
|
69
|
+
|
|
70
|
+
value = getattr(importlib.import_module(module), name)
|
|
71
|
+
globals()[name] = value
|
|
72
|
+
return value
|