neutron-framework 0.1.0__tar.gz
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.
- neutron_framework-0.1.0/.gitignore +240 -0
- neutron_framework-0.1.0/LICENSE +21 -0
- neutron_framework-0.1.0/PKG-INFO +144 -0
- neutron_framework-0.1.0/README.md +101 -0
- neutron_framework-0.1.0/benchmarks/.gitignore +8 -0
- neutron_framework-0.1.0/benchmarks/README.md +134 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/__init__.py +0 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/common.py +104 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/fastapi_app.py +74 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/litestar_app.py +106 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/neutron_app.py +99 -0
- neutron_framework-0.1.0/benchmarks/bench_apps/starlette_app.py +79 -0
- neutron_framework-0.1.0/benchmarks/client.mjs +53 -0
- neutron_framework-0.1.0/benchmarks/measure_noise.py +172 -0
- neutron_framework-0.1.0/benchmarks/requirements-bench.txt +59 -0
- neutron_framework-0.1.0/benchmarks/run_bench.py +563 -0
- neutron_framework-0.1.0/neutron/__init__.py +72 -0
- neutron_framework-0.1.0/neutron/__main__.py +5 -0
- neutron_framework-0.1.0/neutron/ai/__init__.py +39 -0
- neutron_framework-0.1.0/neutron/ai/agent.py +205 -0
- neutron_framework-0.1.0/neutron/ai/mcp.py +299 -0
- neutron_framework-0.1.0/neutron/ai/memory.py +202 -0
- neutron_framework-0.1.0/neutron/ai/providers.py +443 -0
- neutron_framework-0.1.0/neutron/ai/rag.py +212 -0
- neutron_framework-0.1.0/neutron/ai/structured.py +75 -0
- neutron_framework-0.1.0/neutron/ai/tools.py +146 -0
- neutron_framework-0.1.0/neutron/ai/workflow.py +187 -0
- neutron_framework-0.1.0/neutron/app.py +574 -0
- neutron_framework-0.1.0/neutron/auth/__init__.py +37 -0
- neutron_framework-0.1.0/neutron/auth/apikey.py +116 -0
- neutron_framework-0.1.0/neutron/auth/csrf.py +243 -0
- neutron_framework-0.1.0/neutron/auth/jwt.py +268 -0
- neutron_framework-0.1.0/neutron/auth/oauth.py +568 -0
- neutron_framework-0.1.0/neutron/auth/password.py +106 -0
- neutron_framework-0.1.0/neutron/auth/rbac.py +128 -0
- neutron_framework-0.1.0/neutron/auth/session.py +192 -0
- neutron_framework-0.1.0/neutron/cache/__init__.py +9 -0
- neutron_framework-0.1.0/neutron/cache/http.py +221 -0
- neutron_framework-0.1.0/neutron/cache/tiered.py +139 -0
- neutron_framework-0.1.0/neutron/cli.py +384 -0
- neutron_framework-0.1.0/neutron/config.py +88 -0
- neutron_framework-0.1.0/neutron/depends.py +30 -0
- neutron_framework-0.1.0/neutron/error.py +137 -0
- neutron_framework-0.1.0/neutron/handler.py +426 -0
- neutron_framework-0.1.0/neutron/jobs/__init__.py +9 -0
- neutron_framework-0.1.0/neutron/jobs/queue.py +626 -0
- neutron_framework-0.1.0/neutron/middleware.py +548 -0
- neutron_framework-0.1.0/neutron/nucleus/__init__.py +46 -0
- neutron_framework-0.1.0/neutron/nucleus/_exec.py +58 -0
- neutron_framework-0.1.0/neutron/nucleus/blob.py +165 -0
- neutron_framework-0.1.0/neutron/nucleus/cdc.py +81 -0
- neutron_framework-0.1.0/neutron/nucleus/client.py +229 -0
- neutron_framework-0.1.0/neutron/nucleus/columnar.py +82 -0
- neutron_framework-0.1.0/neutron/nucleus/datalog.py +73 -0
- neutron_framework-0.1.0/neutron/nucleus/document.py +307 -0
- neutron_framework-0.1.0/neutron/nucleus/fts.py +111 -0
- neutron_framework-0.1.0/neutron/nucleus/geo.py +220 -0
- neutron_framework-0.1.0/neutron/nucleus/graph.py +184 -0
- neutron_framework-0.1.0/neutron/nucleus/kv.py +304 -0
- neutron_framework-0.1.0/neutron/nucleus/migrate.py +172 -0
- neutron_framework-0.1.0/neutron/nucleus/pubsub.py +115 -0
- neutron_framework-0.1.0/neutron/nucleus/retry.py +137 -0
- neutron_framework-0.1.0/neutron/nucleus/sql.py +71 -0
- neutron_framework-0.1.0/neutron/nucleus/streams.py +171 -0
- neutron_framework-0.1.0/neutron/nucleus/timeseries.py +179 -0
- neutron_framework-0.1.0/neutron/nucleus/tx.py +105 -0
- neutron_framework-0.1.0/neutron/nucleus/vector.py +179 -0
- neutron_framework-0.1.0/neutron/openapi.py +371 -0
- neutron_framework-0.1.0/neutron/realtime/__init__.py +10 -0
- neutron_framework-0.1.0/neutron/realtime/sse.py +125 -0
- neutron_framework-0.1.0/neutron/realtime/websocket.py +136 -0
- neutron_framework-0.1.0/neutron/response.py +81 -0
- neutron_framework-0.1.0/neutron/router.py +237 -0
- neutron_framework-0.1.0/neutron/test/__init__.py +128 -0
- neutron_framework-0.1.0/pyproject.toml +93 -0
- neutron_framework-0.1.0/tests/__init__.py +0 -0
- neutron_framework-0.1.0/tests/conftest.py +46 -0
- neutron_framework-0.1.0/tests/test_ai.py +1173 -0
- neutron_framework-0.1.0/tests/test_app.py +308 -0
- neutron_framework-0.1.0/tests/test_auth.py +534 -0
- neutron_framework-0.1.0/tests/test_cache.py +364 -0
- neutron_framework-0.1.0/tests/test_cli.py +197 -0
- neutron_framework-0.1.0/tests/test_config.py +119 -0
- neutron_framework-0.1.0/tests/test_depends.py +98 -0
- neutron_framework-0.1.0/tests/test_error.py +78 -0
- neutron_framework-0.1.0/tests/test_handler.py +134 -0
- neutron_framework-0.1.0/tests/test_health_contract.py +40 -0
- neutron_framework-0.1.0/tests/test_jobs.py +188 -0
- neutron_framework-0.1.0/tests/test_jobs_durable.py +283 -0
- neutron_framework-0.1.0/tests/test_middleware.py +614 -0
- neutron_framework-0.1.0/tests/test_migrate.py +117 -0
- neutron_framework-0.1.0/tests/test_migrate_live.py +70 -0
- neutron_framework-0.1.0/tests/test_nucleus_live.py +82 -0
- neutron_framework-0.1.0/tests/test_nucleus_models.py +1414 -0
- neutron_framework-0.1.0/tests/test_nucleus_retry.py +133 -0
- neutron_framework-0.1.0/tests/test_oauth.py +593 -0
- neutron_framework-0.1.0/tests/test_openapi.py +352 -0
- neutron_framework-0.1.0/tests/test_realtime.py +137 -0
- neutron_framework-0.1.0/tests/test_response.py +171 -0
- neutron_framework-0.1.0/tests/test_router.py +130 -0
- neutron_framework-0.1.0/tests/test_shutdown.py +265 -0
- neutron_framework-0.1.0/tests/test_sync_test_client.py +91 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Build artifacts
|
|
2
|
+
target/
|
|
3
|
+
dist/
|
|
4
|
+
build/
|
|
5
|
+
.next/
|
|
6
|
+
.svelte-kit/
|
|
7
|
+
.solid/
|
|
8
|
+
out/
|
|
9
|
+
|
|
10
|
+
# Dependencies
|
|
11
|
+
node_modules/
|
|
12
|
+
.pnpm-store/
|
|
13
|
+
|
|
14
|
+
# Environment & secrets
|
|
15
|
+
.env
|
|
16
|
+
.env.*
|
|
17
|
+
!.env.example
|
|
18
|
+
|
|
19
|
+
# IDE / OS
|
|
20
|
+
.DS_Store
|
|
21
|
+
Thumbs.db
|
|
22
|
+
*.swp
|
|
23
|
+
*.swo
|
|
24
|
+
.vscode/settings.json
|
|
25
|
+
.idea/
|
|
26
|
+
|
|
27
|
+
# Logs
|
|
28
|
+
*.log
|
|
29
|
+
server_err.log
|
|
30
|
+
|
|
31
|
+
# Temporary files
|
|
32
|
+
*.tmp
|
|
33
|
+
*.bak
|
|
34
|
+
|
|
35
|
+
# Compiled Mojo outputs
|
|
36
|
+
/tmp/test_*
|
|
37
|
+
|
|
38
|
+
# Archive — planning docs & research
|
|
39
|
+
archive/
|
|
40
|
+
**/ARCHITECTURE.md
|
|
41
|
+
**/PLAN.md
|
|
42
|
+
**/STATUS.md
|
|
43
|
+
**/TODO-NEXT.md
|
|
44
|
+
# Exception: the framework-excellence program's master plan is a tracked deliverable.
|
|
45
|
+
!docs/framework-excellence/PLAN.md
|
|
46
|
+
**/EXECUTION.md
|
|
47
|
+
**/CHECKLIST.md
|
|
48
|
+
**/NEUTRON_FINISH_CHECKLIST.md
|
|
49
|
+
**/BENCHMARK_UPDATE.md
|
|
50
|
+
**/competitive-analysis*.md
|
|
51
|
+
**/PARITY-COMPARISON.md
|
|
52
|
+
**/COMPETITOR-GAPS.md
|
|
53
|
+
**/AUDIT-REPORT.md
|
|
54
|
+
**/ai-ml-database-research.md
|
|
55
|
+
**/SPRINT-*.md
|
|
56
|
+
**/SPRINTS-*.md
|
|
57
|
+
**/IMPLEMENTATION-COMPLETE.md
|
|
58
|
+
**/IMPLEMENTATION_PLAN.md
|
|
59
|
+
**/COMPLETION_REPORT.md
|
|
60
|
+
**/ENGINEERING_EFFORT_ANALYSIS.md
|
|
61
|
+
**/PROJECT_STATUS_*.md
|
|
62
|
+
**/ONE_WEEK_RELEASE_PLAN.md
|
|
63
|
+
**/TECHNICAL_DEEP_DIVE.md
|
|
64
|
+
**/FULL_STACK_ANALYSIS.md
|
|
65
|
+
**/MULTI_LANGUAGE_CLIENT_ANALYSIS.md
|
|
66
|
+
**/NUCLEUS_CLIENT_SPEC.md
|
|
67
|
+
**/ORM_CLIENT_STUDIO_DECISION.md
|
|
68
|
+
**/NEUTRON-VS-REMIX.md
|
|
69
|
+
**/NEUTRON-FEATURE-AUDIT.md
|
|
70
|
+
**/ECOSYSTEM_*.md
|
|
71
|
+
**/DOCS_API_ECOSYSTEM.md
|
|
72
|
+
**/rust-PLAN.md
|
|
73
|
+
**/DEFER-EXAMPLE.md
|
|
74
|
+
**/URGENT-NOTE.md
|
|
75
|
+
**/QUICK-REFERENCE.md
|
|
76
|
+
**/ASTRO6-NEXTJS16-FEATURES.md
|
|
77
|
+
**/SVELTEKIT-SOLIDJS-FEATURES.md
|
|
78
|
+
**/REMIX-FEATURES-TO-ADOPT.md
|
|
79
|
+
|
|
80
|
+
# Vercel parity / product strategy research (local only)
|
|
81
|
+
/docs/VERCEL_PARITY_BACKLOG.md
|
|
82
|
+
/docs/design/
|
|
83
|
+
|
|
84
|
+
# Planning & audit docs
|
|
85
|
+
**/NUCLEUS-AUDIT.md
|
|
86
|
+
**/NUCLEUS-ROADMAP.md
|
|
87
|
+
LAUNCH_PROMPTS.md
|
|
88
|
+
|
|
89
|
+
# Benchmark & debug artifacts
|
|
90
|
+
**/benchmark_results.json
|
|
91
|
+
**/compete_results.json
|
|
92
|
+
**/clippy_out.txt
|
|
93
|
+
**/clippy_remain.txt
|
|
94
|
+
|
|
95
|
+
# Deprecated
|
|
96
|
+
mobile-preview/
|
|
97
|
+
|
|
98
|
+
# Third-party benchmark apps are tracked like every other subject app — an
|
|
99
|
+
# ignored subject is a benchmark row nobody else can reproduce. Their own
|
|
100
|
+
# .gitignore files keep node_modules and build output out.
|
|
101
|
+
|
|
102
|
+
# Observe (separate project)
|
|
103
|
+
typescript/apps/observe/
|
|
104
|
+
|
|
105
|
+
# Zig build artifacts
|
|
106
|
+
zig/.zig-cache/
|
|
107
|
+
zig/zig-out/
|
|
108
|
+
|
|
109
|
+
# Mojo validation reports, research, and internal specs
|
|
110
|
+
mojo/reports/
|
|
111
|
+
mojo/study/
|
|
112
|
+
mojo/specs/
|
|
113
|
+
|
|
114
|
+
# NOT ignored: typescript/.turbo-ls-normalized.json. It looks like turbo cache
|
|
115
|
+
# and was filed here as "Turbo internal", but it is the authored BASELINE that
|
|
116
|
+
# `pnpm run ci:workspace` compares the workspace graph against. Ignoring it made
|
|
117
|
+
# the check fail on every CI run with "Missing snapshot file" — a gate that can
|
|
118
|
+
# only pass on the laptop that generated it is not a gate.
|
|
119
|
+
|
|
120
|
+
# Scratch / dev tooling files
|
|
121
|
+
**/do_edit.py
|
|
122
|
+
**/edit_distributed.py
|
|
123
|
+
**/coord_lines.py
|
|
124
|
+
**/coord_methods.rs
|
|
125
|
+
|
|
126
|
+
# Rust framework (rust/) — the SOURCE is tracked. Only the cargo build output is
|
|
127
|
+
# ignored. (Earlier this was `/rust/` under the mistaken belief the source lived
|
|
128
|
+
# in `rs/`; `rs/` was renamed to `rust/` in 6079213, so `/rust/` was silently
|
|
129
|
+
# excluding the entire framework from version control. Fixed to ignore only target/.)
|
|
130
|
+
/rust/target/
|
|
131
|
+
|
|
132
|
+
# Site build output (source is tracked, dist is not)
|
|
133
|
+
typescript/apps/site/dist/
|
|
134
|
+
typescript/apps/site/.neutron/
|
|
135
|
+
# Same for the playground: .neutron/runtime/entry.node.ts is emitted by
|
|
136
|
+
# `neutron-ts build`, so a tracked copy goes stale the moment the codegen
|
|
137
|
+
# changes and dirties the tree on every build.
|
|
138
|
+
typescript/apps/playground/.neutron/
|
|
139
|
+
|
|
140
|
+
# Claude internal
|
|
141
|
+
.claude/
|
|
142
|
+
|
|
143
|
+
# Python
|
|
144
|
+
__pycache__/
|
|
145
|
+
*.pyc
|
|
146
|
+
*.pyo
|
|
147
|
+
.venv/
|
|
148
|
+
venv/
|
|
149
|
+
|
|
150
|
+
# Rust — track the framework + engine lockfiles for reproducible builds.
|
|
151
|
+
# (The `!rs/Cargo.lock` exception was stale: `rs/` was renamed to `rust/` in
|
|
152
|
+
# 6079213, so the framework lockfile silently went untracked.)
|
|
153
|
+
Cargo.lock
|
|
154
|
+
!rust/Cargo.lock
|
|
155
|
+
!nucleus/Cargo.lock
|
|
156
|
+
# Database files
|
|
157
|
+
*.db
|
|
158
|
+
|
|
159
|
+
# Rust build artifacts (added after filter-repo cleanup of history)
|
|
160
|
+
**/target/
|
|
161
|
+
**/debug/
|
|
162
|
+
*.rlib
|
|
163
|
+
*.rmeta
|
|
164
|
+
*.rcgu.o
|
|
165
|
+
|
|
166
|
+
# ---------------------------------------------------------------------------
|
|
167
|
+
# Working docs, notes and context — local only, never committed
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
# Everything above this block is a DENYLIST OF EXACT FILENAMES, added reactively
|
|
170
|
+
# one name at a time. That shape cannot hold: a working note is tracked by
|
|
171
|
+
# default until somebody remembers to add its exact name here, and the rule only
|
|
172
|
+
# ever arrives after the file already exists. It also does nothing to a file that
|
|
173
|
+
# is already tracked -- `.gitignore` does not untrack -- which is how
|
|
174
|
+
# `nucleus/PARITY-COMPARISON.md` sat public on the GitHub mirror from 2026-07-20
|
|
175
|
+
# while both the ignore list and the document's own first line called it
|
|
176
|
+
# local-only.
|
|
177
|
+
#
|
|
178
|
+
# The patterns below are CONVENTIONS instead: name a note in any of these shapes
|
|
179
|
+
# and it is ignored the moment it is created, without an edit here. Prefer them
|
|
180
|
+
# for anything new.
|
|
181
|
+
#
|
|
182
|
+
# `.github/scripts/check_ignored_not_tracked.py` enforces the whole file: it
|
|
183
|
+
# fails if any tracked path matches an ignore rule, so intent and reality cannot
|
|
184
|
+
# drift apart again silently.
|
|
185
|
+
|
|
186
|
+
# Private planning trees. `_internal/` is its own private git repo (Forgejo
|
|
187
|
+
# `Tyler/neutron-internal`) — gitignored here so the public repo never sees it,
|
|
188
|
+
# versioned there so it is not single-copy on one laptop.
|
|
189
|
+
/_internal/
|
|
190
|
+
**/_internal/
|
|
191
|
+
**/_notes/
|
|
192
|
+
**/_scratch/
|
|
193
|
+
**/.notes/
|
|
194
|
+
|
|
195
|
+
# Note/context/session filename conventions
|
|
196
|
+
**/INTERNAL.md
|
|
197
|
+
**/NOTES.md
|
|
198
|
+
**/*_NOTES.md
|
|
199
|
+
**/*-NOTES.md
|
|
200
|
+
**/NOTES-*.md
|
|
201
|
+
**/SESSION_*.md
|
|
202
|
+
**/SESSION-*.md
|
|
203
|
+
**/HANDOFF*.md
|
|
204
|
+
**/*_HANDOFF.md
|
|
205
|
+
**/SCRATCH*.md
|
|
206
|
+
**/WIP*.md
|
|
207
|
+
**/DRAFT*.md
|
|
208
|
+
**/TODO.md
|
|
209
|
+
**/TODO-*.md
|
|
210
|
+
**/BRAINSTORM*.md
|
|
211
|
+
**/RESEARCH-*.md
|
|
212
|
+
**/*-RESEARCH.md
|
|
213
|
+
**/POSTMORTEM*.md
|
|
214
|
+
**/RETRO*.md
|
|
215
|
+
**/DECISIONS.md
|
|
216
|
+
**/OPEN_WORK.md
|
|
217
|
+
**/PROGRESS.md
|
|
218
|
+
**/ORCHESTRATION.md
|
|
219
|
+
**/GROUND_TRUTH.md
|
|
220
|
+
|
|
221
|
+
# The universal escape hatch: any file may be made local-only by adding `.local`
|
|
222
|
+
# before its extension. Use this instead of extending the denylist above.
|
|
223
|
+
**/*.local.md
|
|
224
|
+
**/*.local.txt
|
|
225
|
+
**/*.local.json
|
|
226
|
+
**/*.local.*
|
|
227
|
+
|
|
228
|
+
uv.lock
|
|
229
|
+
|
|
230
|
+
# Conformance executor build output. `go build ./...` in the executor directory
|
|
231
|
+
# drops a binary named after its module; it is a 10 MB artifact of running the
|
|
232
|
+
# suite, not part of it.
|
|
233
|
+
conformance/live/executors/go/neutron-live-conformance-go
|
|
234
|
+
conformance/live/executors/rust/target/
|
|
235
|
+
|
|
236
|
+
# Zig conformance executor build output.
|
|
237
|
+
conformance/live/executors/zig/.zig-cache/
|
|
238
|
+
conformance/live/executors/zig/zig-out/
|
|
239
|
+
uuid
|
|
240
|
+
status
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Neutron
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: neutron-framework
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The AI application development framework for Python
|
|
5
|
+
Project-URL: Homepage, https://neutron.build/
|
|
6
|
+
Project-URL: Documentation, https://neutron.build/docs/python/overview
|
|
7
|
+
Project-URL: Repository, https://github.com/neutron-build/neutron
|
|
8
|
+
Project-URL: Issues, https://github.com/neutron-build/neutron/issues
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Requires-Dist: asyncpg>=0.29.0
|
|
13
|
+
Requires-Dist: cyclopts>=3.0
|
|
14
|
+
Requires-Dist: httpx>=0.27.0
|
|
15
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: starlette>=0.38.0
|
|
18
|
+
Requires-Dist: structlog>=24.0
|
|
19
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
20
|
+
Provides-Extra: ai
|
|
21
|
+
Requires-Dist: httpx>=0.27.0; extra == 'ai'
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: argon2-cffi>=23.1.0; extra == 'all'
|
|
24
|
+
Requires-Dist: granian>=2.0.0; extra == 'all'
|
|
25
|
+
Requires-Dist: httpx>=0.27.0; extra == 'all'
|
|
26
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'all'
|
|
27
|
+
Requires-Dist: rich>=13.0; extra == 'all'
|
|
28
|
+
Provides-Extra: crypto
|
|
29
|
+
Requires-Dist: argon2-cffi>=23.1.0; extra == 'crypto'
|
|
30
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'crypto'
|
|
31
|
+
Provides-Extra: granian
|
|
32
|
+
Requires-Dist: granian>=2.0.0; extra == 'granian'
|
|
33
|
+
Provides-Extra: rich
|
|
34
|
+
Requires-Dist: rich>=13.0; extra == 'rich'
|
|
35
|
+
Provides-Extra: test
|
|
36
|
+
Requires-Dist: argon2-cffi>=23.1.0; extra == 'test'
|
|
37
|
+
Requires-Dist: editables>=0.5; extra == 'test'
|
|
38
|
+
Requires-Dist: httpx>=0.27.0; extra == 'test'
|
|
39
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'test'
|
|
40
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
|
|
41
|
+
Requires-Dist: pytest>=8.0; extra == 'test'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# neutron-framework
|
|
45
|
+
|
|
46
|
+
The AI application development framework for Python — Starlette underneath,
|
|
47
|
+
Pydantic throughout, with a first-class client for [Nucleus](https://github.com/neutron-build/neutron/tree/main/nucleus), the
|
|
48
|
+
multi-model database the rest of Neutron is built on.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install neutron-framework
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> The distribution is **`neutron-framework`**, not `neutron` — that name on PyPI
|
|
55
|
+
> belongs to OpenStack's networking service.
|
|
56
|
+
|
|
57
|
+
## A first app
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from pydantic import BaseModel
|
|
61
|
+
from neutron import App, Router
|
|
62
|
+
|
|
63
|
+
app = App(title="My API", version="1.0.0")
|
|
64
|
+
router = Router()
|
|
65
|
+
|
|
66
|
+
class User(BaseModel):
|
|
67
|
+
id: int
|
|
68
|
+
name: str
|
|
69
|
+
email: str
|
|
70
|
+
|
|
71
|
+
@router.get("/users/{user_id}")
|
|
72
|
+
async def get_user(user_id: int) -> User:
|
|
73
|
+
return await app.db.sql.query_one(
|
|
74
|
+
User, "SELECT * FROM users WHERE id = $1", user_id
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
app.include_router(router)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Return a Pydantic model and you get validation, serialisation and an OpenAPI
|
|
81
|
+
3.1 schema from the same declaration. `GET /health`, `GET /openapi.json` and
|
|
82
|
+
`GET /docs` are mounted for you.
|
|
83
|
+
|
|
84
|
+
## What ships
|
|
85
|
+
|
|
86
|
+
| Area | Module |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Routing, handlers, dependency injection | `neutron/router.py`, `handler.py`, `depends.py` |
|
|
89
|
+
| Middleware (the contract's 10-layer order) | `neutron/middleware.py`, `default_stack()` |
|
|
90
|
+
| Errors as RFC 7807 problem+json | `neutron/error.py` |
|
|
91
|
+
| OpenAPI 3.1 generation | `neutron/openapi.py` |
|
|
92
|
+
| Nucleus client — all 14 data models | `neutron/nucleus/` |
|
|
93
|
+
| AI: providers, agents, RAG, MCP | `neutron/ai/` |
|
|
94
|
+
| Auth, cache, jobs, realtime | `neutron/auth/`, `cache/`, `jobs/`, `realtime/` |
|
|
95
|
+
| CLI (`python -m neutron`) | `neutron/cli.py` |
|
|
96
|
+
| Test helpers | `neutron/test/` |
|
|
97
|
+
|
|
98
|
+
## Extras
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install "neutron-framework[ai]" # AI providers, agents, RAG
|
|
102
|
+
pip install "neutron-framework[crypto]" # password hashing
|
|
103
|
+
pip install "neutron-framework[granian]" # the Granian server
|
|
104
|
+
pip install "neutron-framework[rich]" # richer CLI output
|
|
105
|
+
pip install "neutron-framework[all]" # everything above
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`[test]` is the development extra and is what CI installs.
|
|
109
|
+
|
|
110
|
+
## Nucleus
|
|
111
|
+
|
|
112
|
+
One pgwire connection reaches every data model; the non-relational models are
|
|
113
|
+
SQL functions rather than separate services or ports.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from neutron.nucleus import NucleusClient
|
|
117
|
+
|
|
118
|
+
db = await NucleusClient.connect("postgresql://localhost:5432/mydb")
|
|
119
|
+
|
|
120
|
+
await db.kv.set("session:abc", "user-1", ttl=3600)
|
|
121
|
+
await db.vector.search("docs", embedding, k=5)
|
|
122
|
+
await db.document.insert("events", {"kind": "signup"})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Any PostgreSQL client works against Nucleus, so `asyncpg` and `psycopg` remain
|
|
126
|
+
available if you would rather not use this client at all.
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
Published docs — overview, quickstart, routing, middleware, database, realtime,
|
|
131
|
+
deployment — start at **https://neutron.build/docs/python/overview**. The wire-level
|
|
132
|
+
contract every Neutron SDK implements is
|
|
133
|
+
[`FRAMEWORK_CONTRACT.md`](https://github.com/neutron-build/neutron/blob/main/FRAMEWORK_CONTRACT.md); this SDK scores 12/12 on
|
|
134
|
+
its conformance matrix.
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install -e ".[test]"
|
|
140
|
+
pytest
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Live-database tests skip unless `NEUTRON_TEST_DATABASE_URL` points at a running
|
|
144
|
+
Nucleus instance.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# neutron-framework
|
|
2
|
+
|
|
3
|
+
The AI application development framework for Python — Starlette underneath,
|
|
4
|
+
Pydantic throughout, with a first-class client for [Nucleus](https://github.com/neutron-build/neutron/tree/main/nucleus), the
|
|
5
|
+
multi-model database the rest of Neutron is built on.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install neutron-framework
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> The distribution is **`neutron-framework`**, not `neutron` — that name on PyPI
|
|
12
|
+
> belongs to OpenStack's networking service.
|
|
13
|
+
|
|
14
|
+
## A first app
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from pydantic import BaseModel
|
|
18
|
+
from neutron import App, Router
|
|
19
|
+
|
|
20
|
+
app = App(title="My API", version="1.0.0")
|
|
21
|
+
router = Router()
|
|
22
|
+
|
|
23
|
+
class User(BaseModel):
|
|
24
|
+
id: int
|
|
25
|
+
name: str
|
|
26
|
+
email: str
|
|
27
|
+
|
|
28
|
+
@router.get("/users/{user_id}")
|
|
29
|
+
async def get_user(user_id: int) -> User:
|
|
30
|
+
return await app.db.sql.query_one(
|
|
31
|
+
User, "SELECT * FROM users WHERE id = $1", user_id
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
app.include_router(router)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Return a Pydantic model and you get validation, serialisation and an OpenAPI
|
|
38
|
+
3.1 schema from the same declaration. `GET /health`, `GET /openapi.json` and
|
|
39
|
+
`GET /docs` are mounted for you.
|
|
40
|
+
|
|
41
|
+
## What ships
|
|
42
|
+
|
|
43
|
+
| Area | Module |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Routing, handlers, dependency injection | `neutron/router.py`, `handler.py`, `depends.py` |
|
|
46
|
+
| Middleware (the contract's 10-layer order) | `neutron/middleware.py`, `default_stack()` |
|
|
47
|
+
| Errors as RFC 7807 problem+json | `neutron/error.py` |
|
|
48
|
+
| OpenAPI 3.1 generation | `neutron/openapi.py` |
|
|
49
|
+
| Nucleus client — all 14 data models | `neutron/nucleus/` |
|
|
50
|
+
| AI: providers, agents, RAG, MCP | `neutron/ai/` |
|
|
51
|
+
| Auth, cache, jobs, realtime | `neutron/auth/`, `cache/`, `jobs/`, `realtime/` |
|
|
52
|
+
| CLI (`python -m neutron`) | `neutron/cli.py` |
|
|
53
|
+
| Test helpers | `neutron/test/` |
|
|
54
|
+
|
|
55
|
+
## Extras
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install "neutron-framework[ai]" # AI providers, agents, RAG
|
|
59
|
+
pip install "neutron-framework[crypto]" # password hashing
|
|
60
|
+
pip install "neutron-framework[granian]" # the Granian server
|
|
61
|
+
pip install "neutron-framework[rich]" # richer CLI output
|
|
62
|
+
pip install "neutron-framework[all]" # everything above
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`[test]` is the development extra and is what CI installs.
|
|
66
|
+
|
|
67
|
+
## Nucleus
|
|
68
|
+
|
|
69
|
+
One pgwire connection reaches every data model; the non-relational models are
|
|
70
|
+
SQL functions rather than separate services or ports.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from neutron.nucleus import NucleusClient
|
|
74
|
+
|
|
75
|
+
db = await NucleusClient.connect("postgresql://localhost:5432/mydb")
|
|
76
|
+
|
|
77
|
+
await db.kv.set("session:abc", "user-1", ttl=3600)
|
|
78
|
+
await db.vector.search("docs", embedding, k=5)
|
|
79
|
+
await db.document.insert("events", {"kind": "signup"})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Any PostgreSQL client works against Nucleus, so `asyncpg` and `psycopg` remain
|
|
83
|
+
available if you would rather not use this client at all.
|
|
84
|
+
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
Published docs — overview, quickstart, routing, middleware, database, realtime,
|
|
88
|
+
deployment — start at **https://neutron.build/docs/python/overview**. The wire-level
|
|
89
|
+
contract every Neutron SDK implements is
|
|
90
|
+
[`FRAMEWORK_CONTRACT.md`](https://github.com/neutron-build/neutron/blob/main/FRAMEWORK_CONTRACT.md); this SDK scores 12/12 on
|
|
91
|
+
its conformance matrix.
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install -e ".[test]"
|
|
97
|
+
pytest
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Live-database tests skip unless `NEUTRON_TEST_DATABASE_URL` points at a running
|
|
101
|
+
Nucleus instance.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Generated by run_bench.py / measure_noise.py. Machine-specific throughput
|
|
2
|
+
# numbers do not belong in the repository: the reproducible artifact is the
|
|
3
|
+
# harness plus the pinned environment in requirements-bench.txt, not any
|
|
4
|
+
# individual figure measured on one laptop. Committing them is how a number
|
|
5
|
+
# nobody can reproduce ends up quoted.
|
|
6
|
+
results/
|
|
7
|
+
.venv-bench/
|
|
8
|
+
__pycache__/
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Python ASGI Benchmark Protocol
|
|
2
|
+
|
|
3
|
+
Measures `neutron-py` against its real peer set — **FastAPI, Starlette,
|
|
4
|
+
Litestar** — on the same eight scenarios the TypeScript harness uses
|
|
5
|
+
(`typescript/benchmarks/run-comparison.mjs`), with the same client
|
|
6
|
+
(autocannon), so the two suites share vocabulary and scenario shapes.
|
|
7
|
+
|
|
8
|
+
## What it tests
|
|
9
|
+
|
|
10
|
+
- Frameworks (5 rows):
|
|
11
|
+
- `neutron` — `App()` with no user middleware (routing/serialization
|
|
12
|
+
overhead on top of the Starlette it wraps)
|
|
13
|
+
- `neutron-default` — `App(middleware=default_stack())`, the documented
|
|
14
|
+
production posture: a uuid4 request-id plus a structlog event per request
|
|
15
|
+
- `starlette` — bare Starlette, the floor both neutron-py and FastAPI sit on
|
|
16
|
+
- `fastapi` — `FastAPI()` defaults, pydantic-validated body
|
|
17
|
+
- `litestar` — `Litestar()` defaults, pydantic body via DTO
|
|
18
|
+
- Scenarios (exact ports of the TS routes; see `bench_apps/common.py` for the
|
|
19
|
+
provenance of every constant):
|
|
20
|
+
- `static`: `GET /` (constant HTML)
|
|
21
|
+
- `dynamic`: `GET /users/1` (dict lookup + render)
|
|
22
|
+
- `compute`: `GET /compute` (140k-iteration arithmetic loop)
|
|
23
|
+
- `big`: `GET /big` (400 rows rendered per request, ~16 KB HTML)
|
|
24
|
+
- `mutate`: `POST /api/mutate` with `{"seed":13,"repeat":6000}`
|
|
25
|
+
- `login`: `GET /login` (constant HTML)
|
|
26
|
+
- `protected`: `GET /protected` with `Authorization: Bearer valid-token`
|
|
27
|
+
- `session-refresh`: `POST /api/session/refresh` (auth check, body `{}`)
|
|
28
|
+
- Parity probes run against every app before any measurement: status codes,
|
|
29
|
+
byte-identical bodies, content types, and the negative-auth 401 paths.
|
|
30
|
+
`compute` and `mutate` return values are asserted equal to the TypeScript
|
|
31
|
+
implementation's values (JS and Python verified to produce 719963 and
|
|
32
|
+
258368509 respectively).
|
|
33
|
+
|
|
34
|
+
## Fairness model
|
|
35
|
+
|
|
36
|
+
- Same server for everyone: one uvicorn worker, `--no-access-log`, default
|
|
37
|
+
uvloop + httptools, app stdout/stderr to DEVNULL.
|
|
38
|
+
- Same client for everyone: autocannon (borrowed read-only from
|
|
39
|
+
`typescript/benchmarks/node_modules`; override with `AUTOCANNON_MODULE`),
|
|
40
|
+
100 connections, HTTP/1.1, pipelining 1.
|
|
41
|
+
- Frameworks run as shipped: FastAPI and Litestar keep their default
|
|
42
|
+
openapi/docs routes (not measured); `neutron-default`'s per-request logging
|
|
43
|
+
cost is measured and reported as its own row rather than hidden.
|
|
44
|
+
- The TS harness measures SSR frameworks rendering HTML; these are ASGI apps
|
|
45
|
+
doing the same per-route work. In-suite comparisons are apples-to-apples;
|
|
46
|
+
cross-suite (TS vs Python) numbers are directional only.
|
|
47
|
+
|
|
48
|
+
## Error policy
|
|
49
|
+
|
|
50
|
+
Every run asserts zero socket errors, zero timeouts, and zero non-2xx
|
|
51
|
+
responses. Violations are recorded, excluded from medians, printed, and fail
|
|
52
|
+
the invocation (exit 1). A framework serving 500s fast cannot look like a
|
|
53
|
+
win — this is the exact defect that produced the bad Nucleus numbers.
|
|
54
|
+
|
|
55
|
+
## Run it
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# one-time setup (venv lives inside python/benchmarks)
|
|
59
|
+
uv venv benchmarks/.venv-bench --python 3.12
|
|
60
|
+
uv pip install --python benchmarks/.venv-bench/bin/python \
|
|
61
|
+
-e ".[crypto]" fastapi "litestar[standard]" "uvicorn[standard]" httpx editables
|
|
62
|
+
# peer versions are frozen in benchmarks/requirements-bench.txt — a rerun
|
|
63
|
+
# should install from that file, not from latest
|
|
64
|
+
|
|
65
|
+
cd python/benchmarks
|
|
66
|
+
.venv-bench/bin/python run_bench.py # main matrix
|
|
67
|
+
.venv-bench/bin/python measure_noise.py --repeats 6 # noise floor + gate check
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
If `typescript/benchmarks/node_modules` is absent (it is a borrowed install,
|
|
71
|
+
not a dependency of this suite), point `AUTOCANNON_MODULE` at any autocannon
|
|
72
|
+
8.x — e.g. `npm install autocannon@8.0.0` in a scratch dir and export
|
|
73
|
+
`AUTOCANNON_MODULE=<dir>/node_modules/autocannon`. The recorded provenance
|
|
74
|
+
follows the override, so the artifact still names the client it used.
|
|
75
|
+
|
|
76
|
+
Tunables (local defaults, NOT the TS CI profile): `PYBENCH_CONNECTIONS`
|
|
77
|
+
(100), `PYBENCH_DURATION` (5), `PYBENCH_WARMUP` (2), `PYBENCH_RUNS` (3),
|
|
78
|
+
`PYBENCH_FRAMEWORKS`, `PYBENCH_SCENARIOS`, `PYBENCH_PORT`.
|
|
79
|
+
|
|
80
|
+
Outputs: `results/run-<ts>.json`, `results/latest.json`,
|
|
81
|
+
`results/noise-<ts>.json` — every file carries a provenance block (machine,
|
|
82
|
+
Python, package versions, client, profile, exclusions). Raw per-run rows are
|
|
83
|
+
kept, not just medians.
|
|
84
|
+
|
|
85
|
+
## Noise, gates, and honest limits
|
|
86
|
+
|
|
87
|
+
`measure_noise.py` repeats the full matrix with rotated framework order
|
|
88
|
+
(this machine's throughput drifts with warm-up state, so fixed order would
|
|
89
|
+
confound framework with position), computes per-cell medians, and reports the
|
|
90
|
+
worst single-repeat deviation for the neutron rows. That deviation is the
|
|
91
|
+
noise floor. Do not wire a CI regression gate below it. The suggested
|
|
92
|
+
thresholds follow the same derivation as
|
|
93
|
+
`typescript/benchmarks/scripts/measure-gate-noise.mjs`; if the floor is too
|
|
94
|
+
wide for a gate at the current profile, that is the finding — say so, don't
|
|
95
|
+
tune the number.
|
|
96
|
+
|
|
97
|
+
**The floor was measured (2026-08-19, Apple M4 / 10 cores / macOS): no gate
|
|
98
|
+
is possible on this harness on this machine class, so none is wired.**
|
|
99
|
+
Three runs, all 6 repeats of the full matrix:
|
|
100
|
+
|
|
101
|
+
- Quietest attainable window (background load still swung the 1-min loadavg
|
|
102
|
+
from 7 to 35 during the run; a dev laptop is never idle while in use):
|
|
103
|
+
worst single-repeat rps drop on neutron rows **95.4%**, six cells above
|
|
104
|
+
79%.
|
|
105
|
+
- Contaminated window (a concurrent 4-core `rustc` build; loadavg 8 → 98):
|
|
106
|
+
worst drop **100%** — one neutron/compute repeat measured 0 rps with zero
|
|
107
|
+
errors, a green run indistinguishable from a dead framework.
|
|
108
|
+
- The interrupted 2026-08-18 run (4 repeats, "idle-ish"): worst drop
|
|
109
|
+
**76.8%**.
|
|
110
|
+
|
|
111
|
+
A 10x regression is a 90% rps drop — at or below the green-run floor, so a
|
|
112
|
+
threshold high enough to never fire on a green run can never fire on a real
|
|
113
|
+
regression either. A paired within-repeat ratio (neutron/starlette, which
|
|
114
|
+
load bursts should cancel if anything could) deviates up to 257% from its
|
|
115
|
+
own median, so ratio gates are out too. The suggested-threshold column that
|
|
116
|
+
`measure_noise.py` prints is a derivation, not a recommendation: when it
|
|
117
|
+
says 135%, the answer is "no gate", not "gate at 135%".
|
|
118
|
+
|
|
119
|
+
No competitive figures are publishable from this machine either: framework
|
|
120
|
+
medians differ by less than ~26% on every scenario while single cells swing
|
|
121
|
+
1.6x–36x across green repeats of the same framework. Revisit only on a
|
|
122
|
+
machine whose background load is controlled (dedicated runner; the noise
|
|
123
|
+
artifacts now record the per-repeat loadavg precisely so contamination is
|
|
124
|
+
visible in the artifact, not inferred afterwards).
|
|
125
|
+
|
|
126
|
+
## Known caveats
|
|
127
|
+
|
|
128
|
+
- `compute`/`mutate` are GIL-bound pure-Python arithmetic. CPython executes
|
|
129
|
+
these loops ~10x slower than V8 executes the identical TS loops, so those
|
|
130
|
+
two scenarios measure the language runtime, not the framework; the
|
|
131
|
+
framework signal there is small relative to the interpreter cost.
|
|
132
|
+
- Single machine, single worker, loopback. Numbers are not comparable to
|
|
133
|
+
other machines; the reproducible artifact is the harness plus the pinned
|
|
134
|
+
environment, not any individual figure.
|
|
File without changes
|