tachyon-api 1.2.0__tar.gz → 1.3.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.
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/PKG-INFO +158 -56
- tachyon_api-1.3.0/README.md +436 -0
- tachyon_api-1.3.0/pyproject.toml +75 -0
- tachyon_api-1.3.0/setup.py +55 -0
- tachyon_api-1.3.0/tachyon_api/app/_404.py +17 -0
- tachyon_api-1.3.0/tachyon_api/app/_405.py +7 -0
- tachyon_api-1.3.0/tachyon_api/app/__init__.py +239 -0
- tachyon_api-1.3.0/tachyon_api/app/_asgi_entry.py +33 -0
- tachyon_api-1.3.0/tachyon_api/app/_asgi_handler.py +14 -0
- tachyon_api-1.3.0/tachyon_api/app/_docs_routes.py +43 -0
- tachyon_api-1.3.0/tachyon_api/app/_docs_schemas.py +43 -0
- tachyon_api-1.3.0/tachyon_api/app/_exception_table.py +66 -0
- tachyon_api-1.3.0/tachyon_api/app/_exception_table.pyx +74 -0
- tachyon_api-1.3.0/tachyon_api/app/_fast_asgi_factory.py +61 -0
- tachyon_api-1.3.0/tachyon_api/app/_handler_factory.py +69 -0
- tachyon_api-1.3.0/tachyon_api/app/_http_dispatch.py +20 -0
- tachyon_api-1.3.0/tachyon_api/app/_mw_stack.py +27 -0
- tachyon_api-1.3.0/tachyon_api/app/_registry.py +20 -0
- tachyon_api-1.3.0/tachyon_api/app/_route_installer.py +41 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/core/websocket.py +3 -1
- tachyon_api-1.3.0/tachyon_api/openapi/__init__.py +28 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_config.py +51 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_factory.py +56 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_format_map.py +12 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_generator.py +60 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_info.py +52 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_param_schemas.py +40 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_redoc_html.py +37 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_route_builder.py +174 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_safe_json.py +15 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_scalar_html.py +39 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_server.py +16 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_struct_schemas.py +81 -0
- tachyon_api-1.3.0/tachyon_api/openapi/_swagger_html.py +46 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/__init__.py +28 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/_base.py +16 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/_missing.py +16 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/_missing.pyx +19 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body.pxd +15 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body.py +61 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body.pyx +60 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body_limit.pxd +10 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body_limit.py +36 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/body_limit.pyx +38 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/cookie.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/cookie.py +18 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/cookie.pyx +14 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/file.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/file.py +26 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/file.pyx +23 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/form.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/form.py +17 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/form.pyx +14 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/header.pxd +12 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/header.py +18 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/header.pyx +18 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/path.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/path.py +40 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/path.pyx +91 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query.py +26 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query.pyx +80 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query_list.pxd +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query_list.py +53 -0
- tachyon_api-1.3.0/tachyon_api/processing/_extractors/query_list.pyx +54 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/compiler.py +10 -2
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/compiler.pyx +21 -4
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/__init__.py +6 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_callable_factory.py +55 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_circular_detector.py +23 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_circular_detector.pyx +25 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_class_factory.py +32 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_class_factory.pyx +35 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_override_lookup.py +30 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_override_lookup.pyx +31 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_resolver.py +101 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_resolver.pyx +89 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_scope_cache.py +45 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_scope_cache.pyx +36 -0
- tachyon_api-1.3.0/tachyon_api/processing/dependencies/_sig_cache.py +20 -0
- tachyon_api-1.3.0/tachyon_api/processing/parameters.py +145 -0
- tachyon_api-1.3.0/tachyon_api/processing/parameters.pyx +186 -0
- tachyon_api-1.3.0/tachyon_api/responses/__init__.py +44 -0
- tachyon_api-1.3.0/tachyon_api/responses/_bytes_response.py +32 -0
- tachyon_api-1.3.0/tachyon_api/responses/_bytes_response.pyx +41 -0
- tachyon_api-1.3.0/tachyon_api/responses/_caches.py +29 -0
- tachyon_api-1.3.0/tachyon_api/responses/_constants.py +9 -0
- tachyon_api-1.3.0/tachyon_api/responses/_error.py +25 -0
- tachyon_api-1.3.0/tachyon_api/responses/_internal_error.py +51 -0
- tachyon_api-1.3.0/tachyon_api/responses/_internal_error.pyx +53 -0
- tachyon_api-1.3.0/tachyon_api/responses/_json_response.py +44 -0
- tachyon_api-1.3.0/tachyon_api/responses/_json_response.pyx +55 -0
- tachyon_api-1.3.0/tachyon_api/responses/_success.py +10 -0
- tachyon_api-1.3.0/tachyon_api/responses/_validation.py +33 -0
- tachyon_api-1.3.0/tachyon_api/responses/_wire.py +26 -0
- tachyon_api-1.3.0/tachyon_api/security/__init__.py +21 -0
- tachyon_api-1.3.0/tachyon_api/security/_api_key_base.py +30 -0
- tachyon_api-1.3.0/tachyon_api/security/_api_key_cookie.py +16 -0
- tachyon_api-1.3.0/tachyon_api/security/_api_key_header.py +16 -0
- tachyon_api-1.3.0/tachyon_api/security/_api_key_query.py +21 -0
- tachyon_api-1.3.0/tachyon_api/security/_basic_credentials.py +11 -0
- tachyon_api-1.3.0/tachyon_api/security/_bearer_credentials.py +11 -0
- tachyon_api-1.3.0/tachyon_api/security/_bearer_parser.py +16 -0
- tachyon_api-1.3.0/tachyon_api/security/_bearer_parser.pyx +29 -0
- tachyon_api-1.3.0/tachyon_api/security/_http_basic.py +50 -0
- tachyon_api-1.3.0/tachyon_api/security/_http_bearer.py +29 -0
- tachyon_api-1.3.0/tachyon_api/security/_oauth2_bearer.py +32 -0
- tachyon_api-1.2.0/README.md +0 -337
- tachyon_api-1.2.0/pyproject.toml +0 -46
- tachyon_api-1.2.0/setup.py +0 -78
- tachyon_api-1.2.0/tachyon_api/_server_fast.c +0 -9232
- tachyon_api-1.2.0/tachyon_api/app.py +0 -477
- tachyon_api-1.2.0/tachyon_api/openapi.py +0 -500
- tachyon_api-1.2.0/tachyon_api/processing/dependencies.py +0 -132
- tachyon_api-1.2.0/tachyon_api/processing/parameters.py +0 -266
- tachyon_api-1.2.0/tachyon_api/processing/parameters.pyx +0 -351
- tachyon_api-1.2.0/tachyon_api/responses.py +0 -209
- tachyon_api-1.2.0/tachyon_api/security.py +0 -169
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/LICENSE +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/MANIFEST.in +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/_server_fast.pyx +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/background.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cache.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/__main__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/generate.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/lint.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/new.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/openapi.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/routes.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/run.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/commands/skill.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/main.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/templates/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/templates/ai_skill.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/templates/project.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/templates/service.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/cli/utils.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/core/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/core/lifecycle.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/di.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/exceptions.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/files.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/middlewares/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/middlewares/core.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/middlewares/cors.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/middlewares/logger.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/middlewares/security_headers.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/models.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/params.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/dispatch.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/dispatch.pyx +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/response_processor.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/response_processor.pyx +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/scope.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/processing/scope.pyx +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/router.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/routing/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/routing/trie.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/routing/trie.pyx +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/server.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/testing.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/utils/__init__.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/utils/type_converter.py +0 -0
- {tachyon_api-1.2.0 → tachyon_api-1.3.0}/tachyon_api/utils/type_utils.py +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: tachyon-api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: A lightweight, FastAPI-inspired web framework
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Author: Juan Manuel Panozzo Zénere
|
|
7
8
|
Author-email: jm.panozzozenere@gmail.com
|
|
8
9
|
Requires-Python: >=3.10,<4.0
|
|
@@ -12,7 +13,9 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
12
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
17
|
Provides-Extra: fast
|
|
18
|
+
Requires-Dist: httptools (>=0.6.0)
|
|
16
19
|
Requires-Dist: msgspec (>=0.19.0,<0.20.0)
|
|
17
20
|
Requires-Dist: orjson (>=3.11.1,<4.0.0)
|
|
18
21
|
Requires-Dist: python-multipart (>=0.0.20,<0.0.21)
|
|
@@ -23,10 +26,10 @@ Description-Content-Type: text/markdown
|
|
|
23
26
|
|
|
24
27
|
# 🚀 Tachyon API
|
|
25
28
|
|
|
26
|
-

|
|
27
30
|

|
|
28
31
|

|
|
29
|
-

|
|
30
33
|

|
|
31
34
|
|
|
32
35
|
**A lightweight, high-performance API framework for Python with the elegance of FastAPI and the speed of light.**
|
|
@@ -59,7 +62,7 @@ def search(q: str = Query(...), limit: int = Query(10)):
|
|
|
59
62
|
|
|
60
63
|
```bash
|
|
61
64
|
pip install tachyon-api
|
|
62
|
-
|
|
65
|
+
tachyon run # uvloop + httptools + reload, served at :8000
|
|
63
66
|
```
|
|
64
67
|
|
|
65
68
|
📖 **Docs:** http://localhost:8000/docs
|
|
@@ -68,37 +71,55 @@ uvicorn app:app --reload
|
|
|
68
71
|
|
|
69
72
|
## ⚡ Performance
|
|
70
73
|
|
|
71
|
-
Benchmarked against **FastAPI 0.136.1 (Pydantic v2)** · 1 worker · 100 concurrent connections · uvloop + httptools · Cython extensions
|
|
74
|
+
Benchmarked against **FastAPI 0.136.1 (Pydantic v2)** · 1 worker · 100 concurrent connections · uvloop + httptools · precompiled Cython extensions (shipped by default — see below)
|
|
72
75
|
|
|
73
76
|
| Scenario | FastAPI | Tachyon | Speedup |
|
|
74
77
|
|---|---:|---:|---:|
|
|
75
|
-
| Hello World | 10,
|
|
76
|
-
| Path + query params | 7,
|
|
77
|
-
| Body validation (Struct) | 8,
|
|
78
|
-
| Nested body (complex Struct) | 8,
|
|
79
|
-
| Response model serialization | 6,
|
|
80
|
-
| Header param + auth | 8,
|
|
81
|
-
| Dependency injection | 6,
|
|
82
|
-
| Multiple query params | 6,
|
|
83
|
-
| **Total throughput** | **
|
|
78
|
+
| Hello World | 10,314 req/s | **49,755 req/s** | **4.82x** |
|
|
79
|
+
| Path + query params | 7,166 req/s | **37,598 req/s** | **5.25x** |
|
|
80
|
+
| Body validation (Struct) | 8,371 req/s | **40,916 req/s** | **4.89x** |
|
|
81
|
+
| Nested body (complex Struct) | 8,027 req/s | **39,994 req/s** | **4.98x** |
|
|
82
|
+
| Response model serialization | 6,343 req/s | **47,561 req/s** | **7.50x** |
|
|
83
|
+
| Header param + auth | 8,701 req/s | **45,415 req/s** | **5.22x** |
|
|
84
|
+
| Dependency injection | 6,449 req/s | **45,610 req/s** | **7.07x** |
|
|
85
|
+
| Multiple query params | 6,264 req/s | **34,111 req/s** | **5.45x** |
|
|
86
|
+
| **Total throughput** | **61,635 req/s** | **340,960 req/s** | **5.53x** |
|
|
84
87
|
|
|
85
88
|
**Latency:** ~2.3ms (Tachyon) vs ~13ms (FastAPI) on average.
|
|
86
89
|
|
|
87
90
|
> Benchmark code in [`benchmark/`](./benchmark/). Run with `bash benchmark/run_benchmark.sh`.
|
|
88
91
|
|
|
89
|
-
###
|
|
92
|
+
### Precompiled wheels — zero setup
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
`pip install tachyon-api` ships **prebuilt wheels with all 27 Cython extensions already compiled** for:
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
| Platform | Architectures | CPython |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| Linux | x86_64, aarch64 | 3.10 · 3.11 · 3.12 · 3.13 |
|
|
99
|
+
| macOS | arm64 (Apple Silicon) | 3.10 · 3.11 · 3.12 · 3.13 |
|
|
100
|
+
| Windows | x86_64 | 3.10 · 3.11 · 3.12 · 3.13 |
|
|
101
|
+
|
|
102
|
+
No manual build step. No Cython required. The numbers above are what you get out of the box.
|
|
103
|
+
|
|
104
|
+
> **Not on the list?** (macOS Intel, Alpine, etc.) `pip` falls back to the sdist and compiles from `.pyx` source — requires a C compiler and `pip install tachyon-api[fast]` (which pulls in Cython). If compilation fails, the framework still works: runtime falls back to the pure-Python siblings of every `.pyx` module automatically.
|
|
97
105
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
### Compiled vs pure-Python delta
|
|
107
|
+
|
|
108
|
+
Same code, same workload — the only difference is whether the 27 Cython `.so` extensions are loaded:
|
|
109
|
+
|
|
110
|
+
| Scenario | Compiled | Pure-Python | Δ |
|
|
111
|
+
|---|---:|---:|---:|
|
|
112
|
+
| Hello World | 49,755 req/s | 47,899 req/s | +3.9% |
|
|
113
|
+
| Path + query params | 37,598 req/s | 31,901 req/s | **+17.9%** |
|
|
114
|
+
| Body — simple Struct | 40,916 req/s | 35,623 req/s | **+14.9%** |
|
|
115
|
+
| Body — nested Struct | 39,994 req/s | 35,204 req/s | **+13.6%** |
|
|
116
|
+
| Response model | 47,561 req/s | 40,604 req/s | **+17.1%** |
|
|
117
|
+
| Header param + auth | 45,415 req/s | 39,380 req/s | **+15.3%** |
|
|
118
|
+
| **Dependency injection** | 45,610 req/s | 38,552 req/s | **+18.3%** |
|
|
119
|
+
| Multiple query params | 34,111 req/s | 29,803 req/s | **+14.5%** |
|
|
120
|
+
| **TOTAL** | **340,960 req/s** | **298,966 req/s** | **+14.0%** |
|
|
121
|
+
|
|
122
|
+
The biggest wins concentrate on real framework work — DI resolution (+18.3%), path/query parsing (+17.9%), response model (+17.1%), and validation (+13–15%). Hello-world barely moves (+3.9%): the framework is already a tiny slice of that request.
|
|
102
123
|
|
|
103
124
|
### Why is Tachyon faster?
|
|
104
125
|
|
|
@@ -118,15 +139,16 @@ python setup.py build_ext --inplace # compile extensions (required step)
|
|
|
118
139
|
| Category | Features |
|
|
119
140
|
|----------|----------|
|
|
120
141
|
| **Core** | Decorators API, Routers, Middlewares, ASGI compatible |
|
|
121
|
-
| **Parameters** | Path, Query, Body, Header, Cookie, Form, File (all with `alias=`) |
|
|
122
|
-
| **Validation** | msgspec Struct (ultra-fast), automatic 422 errors, body size limit |
|
|
123
|
-
| **DI** | `@injectable` (
|
|
124
|
-
| **Security** | HTTPBearer, HTTPBasic, OAuth2, API Keys |
|
|
125
|
-
| **Async** | Background Tasks, WebSockets |
|
|
126
|
-
| **Performance** | orjson serialization, `@cache` decorator, endpoint pre-compilation |
|
|
127
|
-
| **Docs** | OpenAPI 3.0, Scalar UI, Swagger, ReDoc (XSS-safe HTML generation) |
|
|
128
|
-
| **CLI** | Project scaffolding, code generation, linting |
|
|
129
|
-
| **Testing** | `TachyonTestClient
|
|
142
|
+
| **Parameters** | Path, Query, Body (incl. `Body(List[Struct])`), Header, Cookie, Form, File (all with `alias=`) |
|
|
143
|
+
| **Validation** | msgspec Struct (ultra-fast), automatic 422 errors, configurable body size limit (default 2 MB) |
|
|
144
|
+
| **DI** | `@injectable` (3 scopes: singleton / **request** / **transient**), `Depends()` (sync + async), circular dep detection |
|
|
145
|
+
| **Security** | HTTPBearer, HTTPBasic, OAuth2, API Keys (Header / Query / Cookie), `SecurityHeadersMiddleware` (X-Frame-Options, CSP, HSTS, …) |
|
|
146
|
+
| **Async** | Background Tasks (failures logged, not silenced), WebSockets with **typed path params + DI** |
|
|
147
|
+
| **Performance** | orjson serialization, `@cache` decorator, endpoint pre-compilation, 27 precompiled Cython extensions (shipped by default) |
|
|
148
|
+
| **Docs** | OpenAPI 3.0 (incl. `List[Struct]` arrays + `multipart/form-data`), Scalar UI, Swagger, ReDoc (XSS-safe HTML generation) |
|
|
149
|
+
| **CLI** | Project scaffolding, code generation, linting, AI-agent skill installer |
|
|
150
|
+
| **Testing** | `TachyonTestClient` (sync), `create_client()` (async, full httpx kwargs), `dependency_overrides` |
|
|
151
|
+
| **Architecture** | Atomic SRP modules across `app/`, `processing/`, `responses/`, `openapi/`, `security/` — 27 compiled to `.so` for the hot path (v1.2.x refactor + v1.2.9 Cython sprint) |
|
|
130
152
|
|
|
131
153
|
---
|
|
132
154
|
|
|
@@ -149,6 +171,7 @@ python setup.py build_ext --inplace # compile extensions (required step)
|
|
|
149
171
|
| [Request Lifecycle](./docs/13-request-lifecycle.md) | How requests are processed |
|
|
150
172
|
| [Migration from FastAPI](./docs/14-migration-fastapi.md) | Migration guide |
|
|
151
173
|
| [Best Practices](./docs/15-best-practices.md) | Recommended patterns |
|
|
174
|
+
| [Cython Build](./docs/16-cython-build.md) | Precompiled wheels, source builds, and the `.py`/`.pyx` fallback model |
|
|
152
175
|
|
|
153
176
|
---
|
|
154
177
|
|
|
@@ -159,16 +182,19 @@ A complete example demonstrating all Tachyon features is available in [`example/
|
|
|
159
182
|
```bash
|
|
160
183
|
cd example
|
|
161
184
|
pip install -r requirements.txt
|
|
162
|
-
|
|
185
|
+
tachyon run example.app:app
|
|
163
186
|
```
|
|
164
187
|
|
|
165
|
-
The KYC Demo
|
|
166
|
-
- 🔐 JWT Authentication
|
|
167
|
-
- 👤 Customer CRUD
|
|
188
|
+
The KYC Demo exercises every v1.2.x feature:
|
|
189
|
+
- 🔐 JWT Authentication + API Keys
|
|
190
|
+
- 👤 Customer CRUD + bulk endpoint (`Body(List[Struct])`)
|
|
168
191
|
- 📋 KYC Verification with Background Tasks
|
|
169
|
-
- 📁 Document Uploads
|
|
170
|
-
- 🌐 WebSocket
|
|
171
|
-
-
|
|
192
|
+
- 📁 Document Uploads (`multipart/form-data`)
|
|
193
|
+
- 🌐 WebSocket — legacy plain-string + modern DI-injected with `room_id: uuid.UUID`
|
|
194
|
+
- 💉 DI scopes — `singleton` (services), `request` (correlation context), `transient` (ID generator)
|
|
195
|
+
- 🛡️ Security headers + opt-in CORS allow-list
|
|
196
|
+
- 🚨 Custom exception handler for the `KYCException` hierarchy
|
|
197
|
+
- 🧪 17 tests (`pytest example/tests/`), including async tests via `create_client`
|
|
172
198
|
|
|
173
199
|
**Demo credentials:** `demo@example.com` / `demo123`
|
|
174
200
|
|
|
@@ -187,19 +213,71 @@ The KYC Demo implements:
|
|
|
187
213
|
|
|
188
214
|
---
|
|
189
215
|
|
|
216
|
+
## 🏛️ Architecture
|
|
217
|
+
|
|
218
|
+
Tachyon's request hot path is a thin chain of composed collaborators — every
|
|
219
|
+
piece is single-responsibility and ready for Cython compilation:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
client
|
|
223
|
+
│
|
|
224
|
+
├─→ Tachyon.__call__ (ASGI entry — sets scope["app"])
|
|
225
|
+
│ │
|
|
226
|
+
│ ├─→ ASGIEntry lazy build of HTTP app
|
|
227
|
+
│ │
|
|
228
|
+
│ ├─→ HTTPDispatcher HTTP → trie · WS/lifespan → Starlette
|
|
229
|
+
│ │
|
|
230
|
+
│ ├─→ MiddlewareStack user-registered middlewares (CORS, Security…)
|
|
231
|
+
│ │
|
|
232
|
+
│ └─→ TachyonDispatcher (Cython cdef) ← radix trie match O(k)
|
|
233
|
+
│ │
|
|
234
|
+
│ ├─→ _ASGIHandler (no-param fast path, 2 sends only)
|
|
235
|
+
│ │
|
|
236
|
+
│ └─→ handler closure
|
|
237
|
+
│ ├─→ ParameterPipeline → 8 atomic extractors
|
|
238
|
+
│ │ (body / query / query-list / header / cookie / form / file / path)
|
|
239
|
+
│ ├─→ DependencyResolver → OverrideLookup / ScopeCache /
|
|
240
|
+
│ │ ClassFactory / CallableFactory
|
|
241
|
+
│ ├─→ ResponseProcessor (msgspec encode if Struct)
|
|
242
|
+
│ └─→ ExceptionTable (walks subclass handlers)
|
|
243
|
+
│
|
|
244
|
+
└─→ TachyonJSONResponse | TachyonBytesResponse | _InternalErrorResponse
|
|
245
|
+
(pre-built ASGI dicts, zero extra allocations per response)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The v1.2.x SRP refactor decomposed the monolithic hot path into atomic modules
|
|
249
|
+
with `__slots__` and full type hints — direct `cdef class` candidates. The
|
|
250
|
+
v1.2.9 Cython sprint then compiled 27 of them to `.so`, keeping every `.py`
|
|
251
|
+
sibling as a transparent fallback (Python prefers `.so` automatically).
|
|
252
|
+
|
|
253
|
+
👉 [Full architecture documentation](./docs/02-architecture.md)
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
190
257
|
## 💉 Dependency Injection
|
|
191
258
|
|
|
192
259
|
```python
|
|
193
260
|
from tachyon_api import injectable, Depends
|
|
194
261
|
|
|
195
|
-
@injectable
|
|
196
|
-
class
|
|
197
|
-
def
|
|
198
|
-
|
|
262
|
+
@injectable # singleton (default) — one per app
|
|
263
|
+
class DB:
|
|
264
|
+
def __init__(self):
|
|
265
|
+
self.pool = "..."
|
|
266
|
+
|
|
267
|
+
@injectable(scope="request") # one per HTTP request
|
|
268
|
+
class RequestContext:
|
|
269
|
+
def __init__(self):
|
|
270
|
+
import uuid
|
|
271
|
+
self.correlation_id = str(uuid.uuid4())
|
|
272
|
+
|
|
273
|
+
@injectable(scope="transient") # new instance every time it's injected
|
|
274
|
+
class IdGenerator:
|
|
275
|
+
def __init__(self):
|
|
276
|
+
self._seq = 0
|
|
199
277
|
|
|
200
278
|
@app.get("/users/{id}")
|
|
201
|
-
def get_user(id: str,
|
|
202
|
-
return
|
|
279
|
+
def get_user(id: str, db: DB = Depends(), ctx: RequestContext = Depends()):
|
|
280
|
+
return {"id": id, "trace": ctx.correlation_id}
|
|
203
281
|
```
|
|
204
282
|
|
|
205
283
|
👉 [Full DI documentation](./docs/03-dependency-injection.md)
|
|
@@ -240,11 +318,22 @@ def notify(background_tasks: BackgroundTasks):
|
|
|
240
318
|
## 🌐 WebSockets
|
|
241
319
|
|
|
242
320
|
```python
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
321
|
+
import uuid
|
|
322
|
+
from tachyon_api import injectable, Depends
|
|
323
|
+
|
|
324
|
+
@injectable
|
|
325
|
+
class RoomBroadcaster:
|
|
326
|
+
async def join(self, ws, room_key: str): ...
|
|
327
|
+
|
|
328
|
+
@app.websocket("/ws/rooms/{room_id}") # typed UUID path param
|
|
329
|
+
async def room(
|
|
330
|
+
websocket,
|
|
331
|
+
room_id: uuid.UUID, # auto-converted; 1008 on mismatch
|
|
332
|
+
broadcaster: RoomBroadcaster = Depends(), # @injectable DI in WS
|
|
333
|
+
):
|
|
334
|
+
await broadcaster.join(websocket, str(room_id))
|
|
335
|
+
while True:
|
|
336
|
+
await websocket.send_json({"room": str(room_id)})
|
|
248
337
|
```
|
|
249
338
|
|
|
250
339
|
👉 [Full WebSockets documentation](./docs/10-websockets.md)
|
|
@@ -295,12 +384,23 @@ Installs knowledge about `Body()` requirement, `Struct` vs BaseModel, DI pattern
|
|
|
295
384
|
## 🧪 Testing
|
|
296
385
|
|
|
297
386
|
```python
|
|
387
|
+
# Sync — Starlette TestClient compatible
|
|
298
388
|
from tachyon_api.testing import TachyonTestClient
|
|
299
389
|
|
|
300
390
|
def test_hello():
|
|
301
391
|
client = TachyonTestClient(app)
|
|
302
|
-
|
|
303
|
-
|
|
392
|
+
assert client.get("/").status_code == 200
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# Async — httpx.AsyncClient over ASGI transport
|
|
396
|
+
import pytest
|
|
397
|
+
from tachyon_api.testing import create_client
|
|
398
|
+
|
|
399
|
+
@pytest.mark.asyncio
|
|
400
|
+
async def test_hello_async():
|
|
401
|
+
async with create_client(app, headers={"X-Trace": "abc"}) as client:
|
|
402
|
+
response = await client.get("/")
|
|
403
|
+
assert response.status_code == 200
|
|
304
404
|
```
|
|
305
405
|
|
|
306
406
|
```bash
|
|
@@ -315,8 +415,8 @@ pytest tests/ -v
|
|
|
315
415
|
|
|
316
416
|
| Feature | Tachyon | FastAPI |
|
|
317
417
|
|---------|---------|---------|
|
|
318
|
-
| **Throughput** | ~
|
|
319
|
-
| **Latency** | ~2.
|
|
418
|
+
| **Throughput** | ~341k req/s total | ~62k req/s total |
|
|
419
|
+
| **Latency** | ~2.3ms avg | ~14ms avg |
|
|
320
420
|
| **Routing** | Radix trie O(k) | Regex scan O(N) |
|
|
321
421
|
| **Serialization** | msgspec + orjson | Pydantic v2 |
|
|
322
422
|
| **Request compilation** | Once at startup | Per request |
|
|
@@ -354,6 +454,8 @@ Upcoming:
|
|
|
354
454
|
- Response streaming
|
|
355
455
|
- GraphQL support
|
|
356
456
|
- Multi-worker benchmarks
|
|
457
|
+
- Benchmark suite vs Litestar / BlackSheep / Robyn
|
|
458
|
+
- SQLAlchemy async integration guide
|
|
357
459
|
|
|
358
460
|
---
|
|
359
461
|
|