🔧 fix: app.run() defaults to 127.0.0.1:8000 (README quickstart) + SVG dot positions + stale docs (publish.yml→wheels.yml, 2.0.8→2.0.9)

swadhinbiswas committed 2 months ago
5a3085e
1 parent 0020ff9
commit 5a3085e
9 files changed
+64 -28
▼assets/justapi-benchmark.svg
+8-8
39
39
<!-- JustAPI bar: 766k → height ~300 -->
40
40
<g font-family="'Segoe UI', Arial, sans-serif">
41
41
<rect x="170" y="100" width="90" height="300" rx="8" fill="url(#barJ)">
42
- <animate attributeName="height" values="0;300" dur="1.2s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
43
- <animate attributeName="y" values="400;100" dur="1.2s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
42
+ <animate attributeName="height" values="0;300" dur="1.2s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
43
+ <animate attributeName="y" values="400;100" dur="1.2s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
44
44
</rect>
45
45
<text x="215" y="88" text-anchor="middle" font-size="26" font-weight="800" fill="#f5a524">
46
46
766k
51
51
52
52
<!-- Granian: 314k → height 123 -->
53
53
<rect x="330" y="277" width="90" height="123" rx="8" fill="url(#barO)">
54
- <animate attributeName="height" values="0;123" dur="1.2s" begin="0.3s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
55
- <animate attributeName="y" values="400;277" dur="1.2s" begin="0.3s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
54
+ <animate attributeName="height" values="0;123" dur="1.2s" begin="0.3s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
55
+ <animate attributeName="y" values="400;277" dur="1.2s" begin="0.3s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
56
56
</rect>
57
57
<text x="375" y="265" text-anchor="middle" font-size="22" font-weight="700" fill="#22d3ee">
58
58
314k
63
63
64
64
<!-- FastAPI: 36k → height 14 -->
65
65
<rect x="490" y="386" width="90" height="14" rx="8" fill="url(#barM)">
66
- <animate attributeName="height" values="0;14" dur="1.2s" begin="0.6s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
67
- <animate attributeName="y" values="400;386" dur="1.2s" begin="0.6s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
66
+ <animate attributeName="height" values="0;14" dur="1.2s" begin="0.6s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
67
+ <animate attributeName="y" values="400;386" dur="1.2s" begin="0.6s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
68
68
</rect>
69
69
<text x="535" y="376" text-anchor="middle" font-size="18" font-weight="600" fill="#8b5cf6">
70
70
36k
75
75
76
76
<!-- Robyn: 39k -->
77
77
<rect x="650" y="384" width="90" height="16" rx="8" fill="url(#barO)" opacity="0.8">
78
- <animate attributeName="height" values="0;16" dur="1.2s" begin="0.9s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
79
- <animate attributeName="y" values="400;384" dur="1.2s" begin="0.9s" fill="freeze" calcMode="spline" keySplines="0.34 1.56 0.64 1"/>
78
+ <animate attributeName="height" values="0;16" dur="1.2s" begin="0.9s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
79
+ <animate attributeName="y" values="400;384" dur="1.2s" begin="0.9s" fill="freeze" calcMode="spline" keySplines="0.25 0.1 0.25 1"/>
80
80
</rect>
81
81
<text x="695" y="374" text-anchor="middle" font-size="18" font-weight="600" fill="#22d3ee">
82
82
39k
83
83
▼assets/justapi-features.svg
+8-8
27
27
<circle cx="600" cy="70" r="34" fill="#1e293b" stroke="#f5a524" stroke-width="2"/>
28
28
<text x="600" y="66" text-anchor="middle" font-size="20">⚡</text>
29
29
<text x="600" y="86" text-anchor="middle" font-size="11" fill="#f5a524" font-weight="700">766k req/s</text>
30
- <circle r="3" fill="#f5a524">
30
+ <circle cx="600" cy="70" r="3" fill="#f5a524">
31
31
<animate attributeName="opacity" values="1;0.2;1" dur="1.6s" repeatCount="indefinite"/>
32
32
</circle>
33
33
<text x="600" y="125" text-anchor="middle" font-size="12" fill="#94a3b8">hello-world native</text>
37
37
<circle cx="1130" cy="270" r="34" fill="#1e293b" stroke="#22d3ee" stroke-width="2"/>
38
38
<text x="1130" y="266" text-anchor="middle" font-size="20">🗄️</text>
39
39
<text x="1130" y="286" text-anchor="middle" font-size="11" fill="#22d3ee" font-weight="700">native DB awaits</text>
40
- <circle r="3" fill="#22d3ee">
40
+ <circle cx="1130" cy="270" r="3" fill="#22d3ee">
41
41
<animate attributeName="opacity" values="1;0.2;1" dur="1.8s" repeatCount="indefinite"/>
42
42
</circle>
43
43
<text x="1130" y="325" text-anchor="middle" font-size="12" fill="#94a3b8">query_async · 53x</text>
47
47
<circle cx="600" cy="470" r="34" fill="#1e293b" stroke="#8b5cf6" stroke-width="2"/>
48
48
<text x="600" y="466" text-anchor="middle" font-size="20">🧠</text>
49
49
<text x="600" y="486" text-anchor="middle" font-size="11" fill="#8b5cf6" font-weight="700">free-threaded</text>
50
- <circle r="3" fill="#8b5cf6">
50
+ <circle cx="600" cy="470" r="3" fill="#8b5cf6">
51
51
<animate attributeName="opacity" values="1;0.2;1" dur="2s" repeatCount="indefinite"/>
52
52
</circle>
53
53
<text x="600" y="525" text-anchor="middle" font-size="12" fill="#94a3b8">CPython 3.14t · 12.4x CPU</text>
57
57
<circle cx="70" cy="270" r="34" fill="#1e293b" stroke="#e6522c" stroke-width="2"/>
58
58
<text x="70" y="266" text-anchor="middle" font-size="20">🔐</text>
59
59
<text x="70" y="286" text-anchor="middle" font-size="11" fill="#e6522c" font-weight="700">HTTP/3</text>
60
- <circle r="3" fill="#e6522c">
60
+ <circle cx="70" cy="270" r="3" fill="#e6522c">
61
61
<animate attributeName="opacity" values="1;0.2;1" dur="2.2s" repeatCount="indefinite"/>
62
62
</circle>
63
63
<text x="70" y="325" text-anchor="middle" font-size="12" fill="#94a3b8">QUIC, no one else ships it</text>
68
68
<circle cx="850" cy="130" r="34" fill="#1e293b" stroke="#22d3ee" stroke-width="2"/>
69
69
<text x="850" y="126" text-anchor="middle" font-size="20">📡</text>
70
70
<text x="850" y="146" text-anchor="middle" font-size="11" fill="#22d3ee" font-weight="700">native SSE</text>
71
- <circle r="3" fill="#22d3ee">
71
+ <circle cx="1130" cy="270" r="3" fill="#22d3ee">
72
72
<animate attributeName="opacity" values="1;0.2;1" dur="1.9s" repeatCount="indefinite"/>
73
73
</circle>
74
74
<text x="850" y="185" text-anchor="middle" font-size="12" fill="#94a3b8">sse_native · 0 Python/event</text>
78
78
<circle cx="350" cy="130" r="34" fill="#1e293b" stroke="#f5a524" stroke-width="2"/>
79
79
<text x="350" y="126" text-anchor="middle" font-size="20">🧩</text>
80
80
<text x="350" y="146" text-anchor="middle" font-size="11" fill="#f5a524" font-weight="700">native CRUD</text>
81
- <circle r="3" fill="#f5a524">
81
+ <circle cx="600" cy="70" r="3" fill="#f5a524">
82
82
<animate attributeName="opacity" values="1;0.2;1" dur="2.1s" repeatCount="indefinite"/>
83
83
</circle>
84
84
<text x="350" y="185" text-anchor="middle" font-size="12" fill="#94a3b8">181k SELECT · 125x FastAPI</text>
88
88
<circle cx="350" cy="410" r="34" fill="#1e293b" stroke="#8b5cf6" stroke-width="2"/>
89
89
<text x="350" y="406" text-anchor="middle" font-size="20">🚀</text>
90
90
<text x="350" y="426" text-anchor="middle" font-size="11" fill="#8b5cf6" font-weight="700">multi-worker</text>
91
- <circle r="3" fill="#8b5cf6">
91
+ <circle cx="600" cy="470" r="3" fill="#8b5cf6">
92
92
<animate attributeName="opacity" values="1;0.2;1" dur="2.3s" repeatCount="indefinite"/>
93
93
</circle>
94
94
<text x="350" y="465" text-anchor="middle" font-size="12" fill="#94a3b8">--workers N · 1.88x @4</text>
98
98
<circle cx="850" cy="410" r="34" fill="#1e293b" stroke="#e6522c" stroke-width="2"/>
99
99
<text x="850" y="406" text-anchor="middle" font-size="20">📋</text>
100
100
<text x="850" y="426" text-anchor="middle" font-size="11" fill="#e6522c" font-weight="700">OpenAPI 3.1</text>
101
- <circle r="3" fill="#e6522c">
101
+ <circle cx="70" cy="270" r="3" fill="#e6522c">
102
102
<animate attributeName="opacity" values="1;0.2;1" dur="2.5s" repeatCount="indefinite"/>
103
103
</circle>
104
104
<text x="850" y="465" text-anchor="middle" font-size="12" fill="#94a3b8">Pydantic v2 bridge</text>
105
105
▼assets/justapi-pipeline.svg
+5-5
75
75
</marker>
76
76
77
77
<!-- moving packet dots -->
78
- <circle r="4" fill="#22d3ee" filter="url(#glow2)">
78
+ <circle cx="170" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
79
79
<animateMotion dur="2s" repeatCount="indefinite" path="M170,111 L218,111"/>
80
80
</circle>
81
- <circle r="4" fill="#22d3ee" filter="url(#glow2)">
81
+ <circle cx="370" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
82
82
<animateMotion dur="2.3s" repeatCount="indefinite" path="M370,111 L418,111"/>
83
83
</circle>
84
- <circle r="4" fill="#22d3ee" filter="url(#glow2)">
84
+ <circle cx="570" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
85
85
<animateMotion dur="2.6s" repeatCount="indefinite" path="M570,111 L618,111"/>
86
86
</circle>
87
- <circle r="4" fill="#22d3ee" filter="url(#glow2)">
87
+ <circle cx="770" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
88
88
<animateMotion dur="2.9s" repeatCount="indefinite" path="M770,111 L818,111"/>
89
89
</circle>
90
- <circle r="4" fill="#22d3ee" filter="url(#glow2)">
90
+ <circle cx="970" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
91
91
<animateMotion dur="3.2s" repeatCount="indefinite" path="M970,111 L1018,111"/>
92
92
</circle>
93
93
</g>
94
94
▼crates/justapi-py/python/justapi/app.py
+1-1
1845
1845
register_system_routes(self)
1846
1846
return self
1847
1847
1848
- def run(self, addr: str, max_body_size: int = 50 * 1024 * 1024):
1848
+ def run(self, addr: str = "127.0.0.1:8000", max_body_size: int = 50 * 1024 * 1024):
1849
1849
# Execute startup handlers (FastAPI on_event parity).
1850
1850
for handler in self._startup_handlers:
1851
1851
if inspect.iscoroutinefunction(handler):
1852
1852
▼crates/justapi-py/python/justapi/test_native.py
+36-0
260
260
futs = [ex.submit(c.get, "/native") for _ in range(40)]
261
261
results = [f.result() for f in futs]
262
262
assert all(r["status"] == 200 for r in results), results
263
+
264
+
265
+def test_run_defaults_to_localhost_8000():
266
+ """app.run() with no args binds 127.0.0.1:8000 (README quickstart)."""
267
+ import threading
268
+ import time
269
+ import urllib.request
270
+ from justapi import JustAPIApp
271
+
272
+ app = JustAPIApp()
273
+
274
+ @app.get("/")
275
+ def root():
276
+ return {"Hello": "World"}
277
+
278
+ t = threading.Thread(target=app.run, daemon=True)
279
+ t.start()
280
+ try:
281
+ deadline = time.time() + 15
282
+ last = None
283
+ while time.time() < deadline:
284
+ try:
285
+ last = urllib.request.urlopen("http://127.0.0.1:8000/", timeout=2)
286
+ break
287
+ except Exception as e:
288
+ last = e
289
+ time.sleep(0.3)
290
+ assert last is not None and getattr(last, "status", None) == 200, f"server not reachable: {last}"
291
+ finally:
292
+ import socket
293
+ s = socket.socket()
294
+ try:
295
+ s.connect(("127.0.0.1", 8000))
296
+ s.close()
297
+ except Exception:
298
+ pass
263
299
▼docs_site/src/content/docs/contributing/testing-guide.md
+1-1
150
150
7. `pytest` after wheel build (Python 3.12 + free-threaded 3.14t)
151
151
8. Publish to PyPI via OIDC trusted publishing (on tagged releases)
152
152
153
-On release, `.github/workflows/publish.yml` handles the standalone publish matrix.
153
+On release, `.github/workflows/wheels.yml` builds the 9-platform wheel matrix and publishes to PyPI via OIDC trusted publishing (no token). Push a `v*` tag to trigger it.
154
154
155
155
## See Also
156
156
157
157
▼docs_site/src/content/docs/getting-started/installation.md
+2-2
55
55
56
56
```bash
57
57
python -c "import justapi; print(justapi.__version__)"
58
-# Output: 2.0.8
58
+# Output: 2.0.9
59
59
```
60
60
61
61
## Install CLI Tooling (`justapi-cli`)
68
68
69
69
# Verify
70
70
justapi --version
71
-# Output: justapi 2.0.8
71
+# Output: justapi 2.0.9
72
72
```
73
73
74
74
## Docker
75
75
▼docs_site/src/content/docs/inference/gpu-cuda-setup.md
+1-1
4
4
keywords: GPU acceleration, CUDA, LLM inference, FastAPI alternative, Rust web framework
5
5
---
6
6
7
-> **Note:** GPU inference is feature-gated behind `cuda` and `real` features. Real GPU benchmarks are deferred to the 2.0.8 release (ADR-067). Structural CPU benchmarks pass.
7
+> **Note:** GPU inference is feature-gated behind `cuda` and `real` features. Real GPU benchmarks are deferred (no real-GPU run as of 2.0.9, ADR-067). Structural CPU benchmarks pass.
8
8
9
9
## Building with CUDA Support
10
10
11
11
▼docs_site/src/content/docs/inference/overview.md
+2-2
6
6
7
7
JustAPI includes a Rust-native inference engine (`justapi-inference`) built on the [Candle](https://github.com/huggingface/candle) ML framework. It provides efficient LLM serving with continuous batching, PagedAttention KV-cache, prefix caching, and speculative decoding.
8
8
9
-> **Status:** The inference engine is feature-complete but **frozen** pending the 2.0.8 release (ADR-067). GPU benchmarks with real weights are deferred. CPU-based structural benchmarks pass.
9
+> **Status:** The inference engine is feature-complete but **frozen** (no real-GPU run as of 2.0.9, ADR-067). GPU benchmarks with real weights are deferred. CPU-based structural benchmarks pass.
10
10
11
11
## Architecture
12
12
92
92
93
93
## Status
94
94
95
-The inference engine is fully implemented and structurally benchmarked. Real GPU validation with actual model weights is deferred to the 2.0.8 release cycle.
95
+The inference engine is fully implemented and structurally benchmarked. Real GPU validation with actual model weights is deferred (no real-GPU run as of 2.0.9).
96
96
97
97
## See Also
98
98
99
99