nexus-framework 0.1.0__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.
- nexus/__init__.py +169 -0
- nexus/cli.py +194 -0
- nexus/config/__init__.py +5 -0
- nexus/config/settings.py +98 -0
- nexus/core/__init__.py +1 -0
- nexus/core/entities/__init__.py +343 -0
- nexus/core/exceptions/__init__.py +314 -0
- nexus/core/interfaces/__init__.py +69 -0
- nexus/core/jwt.py +145 -0
- nexus/data/__init__.py +30 -0
- nexus/data/frame.py +406 -0
- nexus/data/loader.py +277 -0
- nexus/data/pipeline.py +190 -0
- nexus/data/sink.py +220 -0
- nexus/data/testing.py +193 -0
- nexus/db/__init__.py +63 -0
- nexus/db/expert.py +116 -0
- nexus/db/magic.py +285 -0
- nexus/db/model.py +588 -0
- nexus/db/session.py +231 -0
- nexus/deployment.py +191 -0
- nexus/logging/__init__.py +5 -0
- nexus/logging/logger.py +59 -0
- nexus/magic/__init__.py +27 -0
- nexus/magic/injector.py +307 -0
- nexus/magic/introspect.py +122 -0
- nexus/observability.py +593 -0
- nexus/py.typed +1 -0
- nexus/testing.py +567 -0
- nexus/web/__init__.py +111 -0
- nexus/web/app.py +809 -0
- nexus/web/asgi.py +227 -0
- nexus/web/auth.py +643 -0
- nexus/web/background.py +59 -0
- nexus/web/cookies.py +70 -0
- nexus/web/idempotency.py +74 -0
- nexus/web/lifespan.py +78 -0
- nexus/web/middlewares.py +429 -0
- nexus/web/openapi.py +216 -0
- nexus/web/pagination.py +81 -0
- nexus/web/router.py +472 -0
- nexus/web/security.py +84 -0
- nexus/web/session.py +349 -0
- nexus/web/sse.py +120 -0
- nexus/web/staticfiles.py +146 -0
- nexus/web/template/__init__.py +18 -0
- nexus/web/template/compiler.py +198 -0
- nexus/web/template/engine.py +130 -0
- nexus/web/template/filters.py +133 -0
- nexus/web/template/lexer.py +170 -0
- nexus/web/template/parser.py +356 -0
- nexus/web/upload.py +68 -0
- nexus/web/validation.py +227 -0
- nexus/web/websocket.py +120 -0
- nexus_framework-0.1.0.dist-info/METADATA +202 -0
- nexus_framework-0.1.0.dist-info/RECORD +58 -0
- nexus_framework-0.1.0.dist-info/WHEEL +4 -0
- nexus_framework-0.1.0.dist-info/entry_points.txt +2 -0
nexus/__init__.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""Nexus Framework.
|
|
2
|
+
|
|
3
|
+
Ultimate Simplicity, Uncompromising Power.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from nexus.cli import main as cli_main
|
|
7
|
+
from nexus.core.entities import (
|
|
8
|
+
FileResponse,
|
|
9
|
+
HTMLResponse,
|
|
10
|
+
HTTPMethod,
|
|
11
|
+
JSONResponse,
|
|
12
|
+
NexusRequest,
|
|
13
|
+
NexusResponse,
|
|
14
|
+
PlainTextResponse,
|
|
15
|
+
RedirectResponse,
|
|
16
|
+
StreamingResponse,
|
|
17
|
+
)
|
|
18
|
+
from nexus.data import (
|
|
19
|
+
DataFrame,
|
|
20
|
+
Pipeline,
|
|
21
|
+
PipelineTestClient,
|
|
22
|
+
PipelineTestResult,
|
|
23
|
+
load,
|
|
24
|
+
pipeline_registry,
|
|
25
|
+
save,
|
|
26
|
+
stream_csv,
|
|
27
|
+
)
|
|
28
|
+
from nexus.db import Field, Model, Relationship, db
|
|
29
|
+
from nexus.deployment import (
|
|
30
|
+
GracefulShutdownManager,
|
|
31
|
+
generate_dockerfile,
|
|
32
|
+
generate_env_documentation,
|
|
33
|
+
run_app,
|
|
34
|
+
)
|
|
35
|
+
from nexus.magic.injector import (
|
|
36
|
+
CircularDependencyError,
|
|
37
|
+
DIContainer,
|
|
38
|
+
ProviderNotFoundError,
|
|
39
|
+
ScopeType,
|
|
40
|
+
)
|
|
41
|
+
from nexus.observability import (
|
|
42
|
+
Counter,
|
|
43
|
+
Gauge,
|
|
44
|
+
HealthCheckManager,
|
|
45
|
+
Histogram,
|
|
46
|
+
MetricsRegistry,
|
|
47
|
+
ObservabilityMiddleware,
|
|
48
|
+
Span,
|
|
49
|
+
Tracer,
|
|
50
|
+
health_manager,
|
|
51
|
+
metrics,
|
|
52
|
+
tracer,
|
|
53
|
+
)
|
|
54
|
+
from nexus.testing import TestClient, TestResponse
|
|
55
|
+
from nexus.web.app import Nexus, NexusApp
|
|
56
|
+
from nexus.web.background import BackgroundTask, BackgroundTasks
|
|
57
|
+
from nexus.web.idempotency import IdempotencyMiddleware
|
|
58
|
+
from nexus.web.middlewares import (
|
|
59
|
+
CORSMiddleware,
|
|
60
|
+
CSRFMiddleware,
|
|
61
|
+
GZipMiddleware,
|
|
62
|
+
RateLimitMiddleware,
|
|
63
|
+
RequestIdMiddleware,
|
|
64
|
+
SecurityHeadersMiddleware,
|
|
65
|
+
TimingMiddleware,
|
|
66
|
+
TrustedHostMiddleware,
|
|
67
|
+
)
|
|
68
|
+
from nexus.web.openapi import OpenAPIGenerator, get_redoc_html, get_swagger_ui_html
|
|
69
|
+
from nexus.web.pagination import Page, paginate
|
|
70
|
+
from nexus.web.router import Blueprint
|
|
71
|
+
from nexus.web.security import (
|
|
72
|
+
constant_time_compare,
|
|
73
|
+
generate_hmac_signature,
|
|
74
|
+
generate_secure_token,
|
|
75
|
+
verify_hmac_signature,
|
|
76
|
+
)
|
|
77
|
+
from nexus.web.session import (
|
|
78
|
+
MemorySessionBackend,
|
|
79
|
+
SessionBackend,
|
|
80
|
+
SessionMiddleware,
|
|
81
|
+
)
|
|
82
|
+
from nexus.web.sse import EventSourceResponse, ServerSentEvent
|
|
83
|
+
from nexus.web.staticfiles import StaticFiles
|
|
84
|
+
from nexus.web.template.engine import NXEngine
|
|
85
|
+
from nexus.web.upload import UploadFile
|
|
86
|
+
from nexus.web.websocket import WebSocket, WebSocketDisconnect, WebSocketGroup
|
|
87
|
+
|
|
88
|
+
__version__ = "0.1.0"
|
|
89
|
+
|
|
90
|
+
__all__ = [
|
|
91
|
+
"BackgroundTask",
|
|
92
|
+
"BackgroundTasks",
|
|
93
|
+
"Blueprint",
|
|
94
|
+
"CORSMiddleware",
|
|
95
|
+
"CSRFMiddleware",
|
|
96
|
+
"CircularDependencyError",
|
|
97
|
+
"Counter",
|
|
98
|
+
"DIContainer",
|
|
99
|
+
"DataFrame",
|
|
100
|
+
"EventSourceResponse",
|
|
101
|
+
"Field",
|
|
102
|
+
"FileResponse",
|
|
103
|
+
"GZipMiddleware",
|
|
104
|
+
"Gauge",
|
|
105
|
+
"GracefulShutdownManager",
|
|
106
|
+
"HTMLResponse",
|
|
107
|
+
"HTTPMethod",
|
|
108
|
+
"HealthCheckManager",
|
|
109
|
+
"Histogram",
|
|
110
|
+
"IdempotencyMiddleware",
|
|
111
|
+
"JSONResponse",
|
|
112
|
+
"MemorySessionBackend",
|
|
113
|
+
"MetricsRegistry",
|
|
114
|
+
"Model",
|
|
115
|
+
"NXEngine",
|
|
116
|
+
"Nexus",
|
|
117
|
+
"NexusApp",
|
|
118
|
+
"NexusRequest",
|
|
119
|
+
"NexusResponse",
|
|
120
|
+
"ObservabilityMiddleware",
|
|
121
|
+
"OpenAPIGenerator",
|
|
122
|
+
"Page",
|
|
123
|
+
"Pipeline",
|
|
124
|
+
"PipelineTestClient",
|
|
125
|
+
"PipelineTestResult",
|
|
126
|
+
"PlainTextResponse",
|
|
127
|
+
"ProviderNotFoundError",
|
|
128
|
+
"RateLimitMiddleware",
|
|
129
|
+
"RedirectResponse",
|
|
130
|
+
"Relationship",
|
|
131
|
+
"RequestIdMiddleware",
|
|
132
|
+
"ScopeType",
|
|
133
|
+
"SecurityHeadersMiddleware",
|
|
134
|
+
"ServerSentEvent",
|
|
135
|
+
"SessionBackend",
|
|
136
|
+
"SessionMiddleware",
|
|
137
|
+
"Span",
|
|
138
|
+
"StaticFiles",
|
|
139
|
+
"StreamingResponse",
|
|
140
|
+
"TestClient",
|
|
141
|
+
"TestResponse",
|
|
142
|
+
"TimingMiddleware",
|
|
143
|
+
"Tracer",
|
|
144
|
+
"TrustedHostMiddleware",
|
|
145
|
+
"UploadFile",
|
|
146
|
+
"WebSocket",
|
|
147
|
+
"WebSocketDisconnect",
|
|
148
|
+
"WebSocketGroup",
|
|
149
|
+
"__version__",
|
|
150
|
+
"cli_main",
|
|
151
|
+
"constant_time_compare",
|
|
152
|
+
"db",
|
|
153
|
+
"generate_dockerfile",
|
|
154
|
+
"generate_env_documentation",
|
|
155
|
+
"generate_hmac_signature",
|
|
156
|
+
"generate_secure_token",
|
|
157
|
+
"get_redoc_html",
|
|
158
|
+
"get_swagger_ui_html",
|
|
159
|
+
"health_manager",
|
|
160
|
+
"load",
|
|
161
|
+
"metrics",
|
|
162
|
+
"paginate",
|
|
163
|
+
"pipeline_registry",
|
|
164
|
+
"run_app",
|
|
165
|
+
"save",
|
|
166
|
+
"stream_csv",
|
|
167
|
+
"tracer",
|
|
168
|
+
"verify_hmac_signature",
|
|
169
|
+
]
|
nexus/cli.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""Nexus Command Line Interface (CLI).
|
|
2
|
+
|
|
3
|
+
Provides commands:
|
|
4
|
+
- `nexus run [app]`
|
|
5
|
+
- `nexus pipeline list`
|
|
6
|
+
- `nexus pipeline run <name>`
|
|
7
|
+
- `nexus db check`
|
|
8
|
+
- `nexus dockerfile`
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import asyncio
|
|
15
|
+
import sys
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from nexus.data.pipeline import pipeline_registry
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _handle_pipeline_list(
|
|
22
|
+
_args: argparse.Namespace, stdout: Any = sys.stdout, **_kwargs: Any
|
|
23
|
+
) -> int:
|
|
24
|
+
pipelines = pipeline_registry.list_all()
|
|
25
|
+
if not pipelines:
|
|
26
|
+
print("No pipelines registered in current session.", file=stdout)
|
|
27
|
+
return 0
|
|
28
|
+
|
|
29
|
+
print(f"\nRegistered Data Pipelines ({len(pipelines)}):", file=stdout)
|
|
30
|
+
print("-" * 65, file=stdout)
|
|
31
|
+
print(f"{'NAME':<25} {'SCHEDULE':<15} {'LAST STATUS':<12} {'RUNS'}", file=stdout)
|
|
32
|
+
print("-" * 65, file=stdout)
|
|
33
|
+
for p in pipelines:
|
|
34
|
+
name = p.get("name", "unnamed")
|
|
35
|
+
schedule = p.get("schedule") or "manual"
|
|
36
|
+
last = p.get("last_run") or {}
|
|
37
|
+
last_status = last.get("status", "never_run")
|
|
38
|
+
total_runs = p.get("total_runs", 0)
|
|
39
|
+
print(f"{name:<25} {schedule:<15} {last_status:<12} {total_runs}", file=stdout)
|
|
40
|
+
print("-" * 65, file=stdout)
|
|
41
|
+
return 0
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _handle_pipeline_run(
|
|
45
|
+
args: argparse.Namespace, stdout: Any = sys.stdout, stderr: Any = sys.stderr, **_kwargs: Any
|
|
46
|
+
) -> int:
|
|
47
|
+
name: str = args.name
|
|
48
|
+
pipe = pipeline_registry.get(name)
|
|
49
|
+
if pipe is None:
|
|
50
|
+
print(f"Error: Pipeline '{name}' not found.", file=stderr)
|
|
51
|
+
return 1
|
|
52
|
+
|
|
53
|
+
print(f"Executing pipeline: {name} ...", file=stdout)
|
|
54
|
+
try:
|
|
55
|
+
res = asyncio.run(pipe.run())
|
|
56
|
+
count = len(res) if hasattr(res, "__len__") else 0
|
|
57
|
+
print(f"Success: Pipeline '{name}' completed. Processed {count} records.", file=stdout)
|
|
58
|
+
return 0
|
|
59
|
+
except Exception as exc:
|
|
60
|
+
print(f"Failure: Pipeline '{name}' failed with error: {exc}", file=stderr)
|
|
61
|
+
return 1
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _handle_dockerfile(args: argparse.Namespace, stdout: Any = sys.stdout, **_kwargs: Any) -> int:
|
|
65
|
+
from pathlib import Path
|
|
66
|
+
|
|
67
|
+
from nexus.deployment import generate_dockerfile
|
|
68
|
+
|
|
69
|
+
out_path = args.output or "Dockerfile"
|
|
70
|
+
generate_dockerfile(output_path=out_path)
|
|
71
|
+
print(f"Generated Dockerfile at {out_path}", file=stdout)
|
|
72
|
+
if not args.output:
|
|
73
|
+
print(Path(out_path).read_text(encoding="utf-8"), file=stdout)
|
|
74
|
+
return 0
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _handle_init(args: argparse.Namespace, stdout: Any = sys.stdout, **_kwargs: Any) -> int:
|
|
78
|
+
from pathlib import Path
|
|
79
|
+
|
|
80
|
+
project_name = args.name or "my_nexus_app"
|
|
81
|
+
target_dir = Path(project_name).resolve()
|
|
82
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
app_py_code = '''"""Entrypoint for {project_name} application."""
|
|
85
|
+
|
|
86
|
+
from nexus import NexusApp, JSONResponse, Model, Field
|
|
87
|
+
from nexus.db import configure_db
|
|
88
|
+
|
|
89
|
+
app = NexusApp(title="{project_name}")
|
|
90
|
+
|
|
91
|
+
class Item(Model):
|
|
92
|
+
name: str = Field(index=True)
|
|
93
|
+
description: str = Field(default="")
|
|
94
|
+
|
|
95
|
+
class Meta:
|
|
96
|
+
table_name = "items"
|
|
97
|
+
|
|
98
|
+
@app.lifespan.on_startup
|
|
99
|
+
async def startup() -> None:
|
|
100
|
+
configure_db("sqlite+aiosqlite:///app.db")
|
|
101
|
+
await Item.create_table()
|
|
102
|
+
|
|
103
|
+
@app.get("/")
|
|
104
|
+
def home() -> JSONResponse:
|
|
105
|
+
return JSONResponse({{
|
|
106
|
+
"app": "{project_name}",
|
|
107
|
+
"message": "Welcome to your new Nexus web application!",
|
|
108
|
+
"docs": "/docs",
|
|
109
|
+
"health": "/health"
|
|
110
|
+
}})
|
|
111
|
+
|
|
112
|
+
@app.get("/items")
|
|
113
|
+
async def list_items() -> JSONResponse:
|
|
114
|
+
items = await Item.where().all()
|
|
115
|
+
return JSONResponse([item.to_dict() for item in items])
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
from nexus.deployment import run_app
|
|
119
|
+
run_app(app, host="127.0.0.1", port=8000)
|
|
120
|
+
'''
|
|
121
|
+
|
|
122
|
+
env_code = """APP_NAME={project_name}
|
|
123
|
+
APP_ENV=development
|
|
124
|
+
APP_DEBUG=true
|
|
125
|
+
APP_HOST=127.0.0.1
|
|
126
|
+
APP_PORT=8000
|
|
127
|
+
DATABASE_URL=sqlite+aiosqlite:///app.db
|
|
128
|
+
SECRET_KEY=nexus-insecure-dev-secret-key-change-in-production
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
app_file = target_dir / "app.py"
|
|
132
|
+
app_file.write_text(app_py_code.format(project_name=project_name), encoding="utf-8")
|
|
133
|
+
env_file = target_dir / ".env"
|
|
134
|
+
env_file.write_text(env_code.format(project_name=project_name), encoding="utf-8")
|
|
135
|
+
|
|
136
|
+
print(f"\n🎉 Successfully created Nexus project template: {project_name}/", file=stdout)
|
|
137
|
+
print(f" ├── {project_name}/app.py", file=stdout)
|
|
138
|
+
print(f" └── {project_name}/.env\n", file=stdout)
|
|
139
|
+
print("Next steps to run your app:", file=stdout)
|
|
140
|
+
print(f" cd {project_name}", file=stdout)
|
|
141
|
+
print(" python app.py\n", file=stdout)
|
|
142
|
+
print("Open http://127.0.0.1:8000 in your browser (or /docs for Swagger UI)!", file=stdout)
|
|
143
|
+
return 0
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def main(
|
|
147
|
+
argv: list[str] | None = None,
|
|
148
|
+
stdout: Any = sys.stdout,
|
|
149
|
+
stderr: Any = sys.stderr,
|
|
150
|
+
) -> int:
|
|
151
|
+
"""Main CLI entrypoint for Nexus."""
|
|
152
|
+
parser = argparse.ArgumentParser(
|
|
153
|
+
prog="nexus",
|
|
154
|
+
description="Nexus Next-Gen Python Framework CLI",
|
|
155
|
+
)
|
|
156
|
+
subparsers = parser.add_subparsers(dest="subcommand", help="Available subcommands")
|
|
157
|
+
|
|
158
|
+
# Project Initializer (like django-admin startproject)
|
|
159
|
+
init_p = subparsers.add_parser("init", help="Scaffold a new production-ready Nexus project")
|
|
160
|
+
init_p.add_argument("name", nargs="?", default="my_nexus_app", help="Project directory name")
|
|
161
|
+
init_p.set_defaults(handler=_handle_init)
|
|
162
|
+
|
|
163
|
+
# Pipeline commands
|
|
164
|
+
pipe_parser = subparsers.add_parser("pipeline", help="Manage data pipelines")
|
|
165
|
+
pipe_sub = pipe_parser.add_subparsers(dest="pipe_action", help="Pipeline action")
|
|
166
|
+
|
|
167
|
+
list_p = pipe_sub.add_parser("list", help="List all registered data pipelines")
|
|
168
|
+
list_p.set_defaults(handler=_handle_pipeline_list)
|
|
169
|
+
|
|
170
|
+
run_p = pipe_sub.add_parser("run", help="Trigger a pipeline execution")
|
|
171
|
+
run_p.add_argument("name", help="Name of the pipeline to execute")
|
|
172
|
+
run_p.set_defaults(handler=_handle_pipeline_run)
|
|
173
|
+
|
|
174
|
+
# Dockerfile generator
|
|
175
|
+
doc_p = subparsers.add_parser("dockerfile", help="Generate production Dockerfile")
|
|
176
|
+
doc_p.add_argument("--port", type=int, default=8000, help="Container port (default: 8000)")
|
|
177
|
+
doc_p.add_argument(
|
|
178
|
+
"--workers", type=int, default=4, help="Number of worker processes (default: 4)"
|
|
179
|
+
)
|
|
180
|
+
doc_p.add_argument("--python-version", default="3.12-slim", help="Base Python Docker image tag")
|
|
181
|
+
doc_p.add_argument("-o", "--output", help="Output file path (e.g. Dockerfile)")
|
|
182
|
+
doc_p.set_defaults(handler=_handle_dockerfile)
|
|
183
|
+
|
|
184
|
+
args = parser.parse_args(argv)
|
|
185
|
+
handler: Any = getattr(args, "handler", None)
|
|
186
|
+
if handler is not None:
|
|
187
|
+
return int(handler(args, stdout=stdout, stderr=stderr))
|
|
188
|
+
|
|
189
|
+
parser.print_help(stdout)
|
|
190
|
+
return 0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
sys.exit(main())
|
nexus/config/__init__.py
ADDED
nexus/config/settings.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Nexus Configuration System.
|
|
2
|
+
|
|
3
|
+
Built on pydantic-settings with strong validation, environment variable loading,
|
|
4
|
+
and hierarchical override support.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import StrEnum
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from pydantic import Field
|
|
11
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Environment(StrEnum):
|
|
15
|
+
"""Application runtime environments."""
|
|
16
|
+
|
|
17
|
+
DEVELOPMENT = "development"
|
|
18
|
+
TESTING = "testing"
|
|
19
|
+
STAGING = "staging"
|
|
20
|
+
PRODUCTION = "production"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NexusSettings(BaseSettings):
|
|
24
|
+
"""Base application settings for any Nexus service.
|
|
25
|
+
|
|
26
|
+
Reads automatically from environment variables and `.env` file.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
model_config = SettingsConfigDict(
|
|
30
|
+
env_file=".env",
|
|
31
|
+
env_file_encoding="utf-8",
|
|
32
|
+
env_prefix="NEXUS_",
|
|
33
|
+
extra="ignore",
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Core Application Settings
|
|
37
|
+
app_name: str = Field(default="Nexus Application", description="Application name")
|
|
38
|
+
env: Environment = Field(default=Environment.DEVELOPMENT, description="Runtime environment")
|
|
39
|
+
debug: bool = Field(default=True, description="Enable debug mode")
|
|
40
|
+
secret_key: str = Field(
|
|
41
|
+
default="nexus-insecure-secret-key-change-in-production",
|
|
42
|
+
description="Cryptographic secret key for tokens and sessions",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Server Network & Performance Settings
|
|
46
|
+
host: str = Field(default="127.0.0.1", description="Host address to bind server")
|
|
47
|
+
port: int = Field(default=8000, description="Port number to bind server")
|
|
48
|
+
workers: int = Field(default=1, description="Worker processes for server")
|
|
49
|
+
max_body_size: int = Field(
|
|
50
|
+
default=10 * 1024 * 1024,
|
|
51
|
+
description="Maximum allowed request body size in bytes (default: 10MB)",
|
|
52
|
+
)
|
|
53
|
+
slow_request_threshold_ms: float = Field(
|
|
54
|
+
default=1000.0,
|
|
55
|
+
description="Threshold in milliseconds above which a request is logged as slow",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# Logging Settings
|
|
59
|
+
log_level: str = Field(default="INFO", description="Log level: DEBUG, INFO, WARNING, ERROR")
|
|
60
|
+
log_format: str = Field(
|
|
61
|
+
default="console", description="Logging output format: 'console' or 'json'"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Database Settings (Placeholder for Phase 5)
|
|
65
|
+
database_url: str | None = Field(default=None, description="Database connection URL")
|
|
66
|
+
|
|
67
|
+
# Redis Settings
|
|
68
|
+
redis_url: str | None = Field(default=None, description="Redis connection URL")
|
|
69
|
+
|
|
70
|
+
# Security & CORS Settings (Auto-configured in Middlewares)
|
|
71
|
+
allowed_hosts: list[str] = Field(
|
|
72
|
+
default=["*"], description="Allowed hosts for TrustedHostMiddleware"
|
|
73
|
+
)
|
|
74
|
+
cors_origins: list[str] = Field(default=["*"], description="Allowed CORS origins")
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def is_production(self) -> bool:
|
|
78
|
+
"""Helper to quickly check if running in production."""
|
|
79
|
+
return self.env == Environment.PRODUCTION
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def is_development(self) -> bool:
|
|
83
|
+
"""Helper to check if running in local development."""
|
|
84
|
+
return self.env == Environment.DEVELOPMENT
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Global helper function for default settings
|
|
88
|
+
def get_settings(env_file: Path | str | None = None) -> NexusSettings:
|
|
89
|
+
"""Instantiate and retrieve Nexus application settings with env file discovery."""
|
|
90
|
+
if env_file:
|
|
91
|
+
return NexusSettings(_env_file=env_file) # type: ignore[call-arg]
|
|
92
|
+
|
|
93
|
+
# Auto-detect environment-specific file: .env.development or .env.production
|
|
94
|
+
for candidate in (".env.development", ".env.production", ".env"):
|
|
95
|
+
if Path(candidate).is_file():
|
|
96
|
+
return NexusSettings(_env_file=candidate) # type: ignore[call-arg]
|
|
97
|
+
|
|
98
|
+
return NexusSettings()
|
nexus/core/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Nexus core module containing protocols, entities, and base exceptions."""
|