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.
Files changed (58) hide show
  1. nexus/__init__.py +169 -0
  2. nexus/cli.py +194 -0
  3. nexus/config/__init__.py +5 -0
  4. nexus/config/settings.py +98 -0
  5. nexus/core/__init__.py +1 -0
  6. nexus/core/entities/__init__.py +343 -0
  7. nexus/core/exceptions/__init__.py +314 -0
  8. nexus/core/interfaces/__init__.py +69 -0
  9. nexus/core/jwt.py +145 -0
  10. nexus/data/__init__.py +30 -0
  11. nexus/data/frame.py +406 -0
  12. nexus/data/loader.py +277 -0
  13. nexus/data/pipeline.py +190 -0
  14. nexus/data/sink.py +220 -0
  15. nexus/data/testing.py +193 -0
  16. nexus/db/__init__.py +63 -0
  17. nexus/db/expert.py +116 -0
  18. nexus/db/magic.py +285 -0
  19. nexus/db/model.py +588 -0
  20. nexus/db/session.py +231 -0
  21. nexus/deployment.py +191 -0
  22. nexus/logging/__init__.py +5 -0
  23. nexus/logging/logger.py +59 -0
  24. nexus/magic/__init__.py +27 -0
  25. nexus/magic/injector.py +307 -0
  26. nexus/magic/introspect.py +122 -0
  27. nexus/observability.py +593 -0
  28. nexus/py.typed +1 -0
  29. nexus/testing.py +567 -0
  30. nexus/web/__init__.py +111 -0
  31. nexus/web/app.py +809 -0
  32. nexus/web/asgi.py +227 -0
  33. nexus/web/auth.py +643 -0
  34. nexus/web/background.py +59 -0
  35. nexus/web/cookies.py +70 -0
  36. nexus/web/idempotency.py +74 -0
  37. nexus/web/lifespan.py +78 -0
  38. nexus/web/middlewares.py +429 -0
  39. nexus/web/openapi.py +216 -0
  40. nexus/web/pagination.py +81 -0
  41. nexus/web/router.py +472 -0
  42. nexus/web/security.py +84 -0
  43. nexus/web/session.py +349 -0
  44. nexus/web/sse.py +120 -0
  45. nexus/web/staticfiles.py +146 -0
  46. nexus/web/template/__init__.py +18 -0
  47. nexus/web/template/compiler.py +198 -0
  48. nexus/web/template/engine.py +130 -0
  49. nexus/web/template/filters.py +133 -0
  50. nexus/web/template/lexer.py +170 -0
  51. nexus/web/template/parser.py +356 -0
  52. nexus/web/upload.py +68 -0
  53. nexus/web/validation.py +227 -0
  54. nexus/web/websocket.py +120 -0
  55. nexus_framework-0.1.0.dist-info/METADATA +202 -0
  56. nexus_framework-0.1.0.dist-info/RECORD +58 -0
  57. nexus_framework-0.1.0.dist-info/WHEEL +4 -0
  58. 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())
@@ -0,0 +1,5 @@
1
+ """Nexus Configuration package."""
2
+
3
+ from nexus.config.settings import Environment, NexusSettings, get_settings
4
+
5
+ __all__ = ["Environment", "NexusSettings", "get_settings"]
@@ -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."""