tachyon-api 0.5.5__py3-none-any.whl → 0.5.9__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.
Potentially problematic release.
This version of tachyon-api might be problematic. Click here for more details.
- tachyon_api/__init__.py +20 -0
- tachyon_api/app.py +385 -172
- tachyon_api/cache.py +270 -0
- tachyon_api/middlewares/__init__.py +0 -1
- tachyon_api/middlewares/cors.py +29 -12
- tachyon_api/middlewares/logger.py +6 -2
- tachyon_api/openapi.py +110 -28
- tachyon_api/responses.py +46 -3
- tachyon_api/utils/__init__.py +14 -0
- tachyon_api/utils/type_converter.py +113 -0
- tachyon_api/utils/type_utils.py +111 -0
- tachyon_api-0.5.9.dist-info/METADATA +146 -0
- tachyon_api-0.5.9.dist-info/RECORD +20 -0
- tachyon_api-0.5.5.dist-info/METADATA +0 -239
- tachyon_api-0.5.5.dist-info/RECORD +0 -16
- {tachyon_api-0.5.5.dist-info → tachyon_api-0.5.9.dist-info}/LICENSE +0 -0
- {tachyon_api-0.5.5.dist-info → tachyon_api-0.5.9.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tachyon API - Type Converter
|
|
3
|
+
|
|
4
|
+
This module provides functionality for converting string values to appropriate Python types
|
|
5
|
+
with proper error handling. Used primarily for converting URL parameters and query strings
|
|
6
|
+
to typed values expected by endpoint functions.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Type, Union, Any
|
|
10
|
+
from starlette.responses import JSONResponse
|
|
11
|
+
|
|
12
|
+
from ..responses import validation_error_response
|
|
13
|
+
from .type_utils import TypeUtils
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TypeConverter:
|
|
17
|
+
"""
|
|
18
|
+
Handles conversion of string values to target Python types.
|
|
19
|
+
|
|
20
|
+
This class provides methods to convert string representations of values
|
|
21
|
+
(typically from URL parameters or query strings) to their appropriate
|
|
22
|
+
Python types with comprehensive error handling.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def convert_value(
|
|
27
|
+
value_str: str,
|
|
28
|
+
target_type: Type,
|
|
29
|
+
param_name: str,
|
|
30
|
+
is_path_param: bool = False,
|
|
31
|
+
) -> Union[Any, JSONResponse]:
|
|
32
|
+
"""
|
|
33
|
+
Convert a string value to the target type with appropriate error handling.
|
|
34
|
+
|
|
35
|
+
This method handles type conversion for query and path parameters,
|
|
36
|
+
including special handling for boolean values and proper error responses.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
value_str: The string value to convert
|
|
40
|
+
target_type: The target Python type to convert to
|
|
41
|
+
param_name: Name of the parameter (for error messages)
|
|
42
|
+
is_path_param: Whether this is a path parameter (affects error response)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The converted value, or a JSONResponse with appropriate error code
|
|
46
|
+
|
|
47
|
+
Note:
|
|
48
|
+
- Boolean conversion accepts: "true", "1", "t", "yes" (case-insensitive)
|
|
49
|
+
- Path parameter errors return 404, query parameter errors return 422
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
>>> TypeConverter.convert_value("123", int, "limit")
|
|
53
|
+
123
|
|
54
|
+
>>> TypeConverter.convert_value("true", bool, "active")
|
|
55
|
+
True
|
|
56
|
+
>>> TypeConverter.convert_value("invalid", int, "limit")
|
|
57
|
+
JSONResponse({"success": False, "error": "Invalid value for integer conversion", ...})
|
|
58
|
+
"""
|
|
59
|
+
# Unwrap Optional/Union[T, None]
|
|
60
|
+
target_type, _ = TypeUtils.unwrap_optional(target_type)
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
if target_type is bool:
|
|
64
|
+
return value_str.lower() in ("true", "1", "t", "yes")
|
|
65
|
+
elif target_type is not str:
|
|
66
|
+
return target_type(value_str)
|
|
67
|
+
else:
|
|
68
|
+
return value_str
|
|
69
|
+
except (ValueError, TypeError):
|
|
70
|
+
if is_path_param:
|
|
71
|
+
return JSONResponse({"detail": "Not Found"}, status_code=404)
|
|
72
|
+
else:
|
|
73
|
+
type_name = TypeUtils.get_type_name(target_type)
|
|
74
|
+
return validation_error_response(
|
|
75
|
+
f"Invalid value for {type_name} conversion"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def convert_list_values(
|
|
80
|
+
values: list[str], item_type: Type, param_name: str, is_path_param: bool = False
|
|
81
|
+
) -> Union[list[Any], JSONResponse]:
|
|
82
|
+
"""
|
|
83
|
+
Convert a list of string values to the target item type.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
values: List of string values to convert
|
|
87
|
+
item_type: Target type for each item
|
|
88
|
+
param_name: Parameter name for error messages
|
|
89
|
+
is_path_param: Whether this is a path parameter
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
List of converted values or error response
|
|
93
|
+
"""
|
|
94
|
+
base_item_type, item_is_optional = TypeUtils.unwrap_optional(item_type)
|
|
95
|
+
converted_list = []
|
|
96
|
+
|
|
97
|
+
for value_str in values:
|
|
98
|
+
# Handle null/empty values for optional items
|
|
99
|
+
if item_is_optional and (value_str == "" or value_str.lower() == "null"):
|
|
100
|
+
converted_list.append(None)
|
|
101
|
+
continue
|
|
102
|
+
|
|
103
|
+
converted_value = TypeConverter.convert_value(
|
|
104
|
+
value_str, base_item_type, param_name, is_path_param
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# If conversion failed, return the error response
|
|
108
|
+
if isinstance(converted_value, JSONResponse):
|
|
109
|
+
return converted_value
|
|
110
|
+
|
|
111
|
+
converted_list.append(converted_value)
|
|
112
|
+
|
|
113
|
+
return converted_list
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tachyon API - Type Utilities
|
|
3
|
+
|
|
4
|
+
This module provides utility functions for working with Python types,
|
|
5
|
+
particularly for handling Optional types, Union types, and generic types
|
|
6
|
+
used throughout the Tachyon framework.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typing
|
|
10
|
+
from typing import Type, Tuple, Union
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TypeUtils:
|
|
14
|
+
"""
|
|
15
|
+
Utility class for type inspection and manipulation.
|
|
16
|
+
|
|
17
|
+
Provides static methods to analyze Python type annotations,
|
|
18
|
+
particularly useful for handling Optional[T], Union types,
|
|
19
|
+
and generic types in parameter processing.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def unwrap_optional(python_type: Type) -> Tuple[Type, bool]:
|
|
24
|
+
"""
|
|
25
|
+
Unwrap Optional[T] types to get the inner type and optionality flag.
|
|
26
|
+
|
|
27
|
+
This method analyzes a type annotation and determines if it represents
|
|
28
|
+
an Optional type (Union[T, None]). It returns the inner type and a
|
|
29
|
+
boolean indicating whether the type is optional.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
python_type: The type annotation to analyze
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Tuple containing:
|
|
36
|
+
- inner_type: The unwrapped type (T from Optional[T])
|
|
37
|
+
- is_optional: Boolean indicating if the type was Optional
|
|
38
|
+
|
|
39
|
+
Examples:
|
|
40
|
+
>>> TypeUtils.unwrap_optional(Optional[str])
|
|
41
|
+
(str, True)
|
|
42
|
+
>>> TypeUtils.unwrap_optional(str)
|
|
43
|
+
(str, False)
|
|
44
|
+
>>> TypeUtils.unwrap_optional(Union[int, None])
|
|
45
|
+
(int, True)
|
|
46
|
+
"""
|
|
47
|
+
origin = typing.get_origin(python_type)
|
|
48
|
+
args = typing.get_args(python_type)
|
|
49
|
+
|
|
50
|
+
if origin is Union and args:
|
|
51
|
+
non_none = [a for a in args if a is not type(None)] # noqa: E721
|
|
52
|
+
if len(non_none) == 1:
|
|
53
|
+
return non_none[0], True
|
|
54
|
+
|
|
55
|
+
return python_type, False
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def is_list_type(python_type: Type) -> Tuple[bool, Type]:
|
|
59
|
+
"""
|
|
60
|
+
Check if a type is a List type and extract the item type.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
python_type: The type annotation to check
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Tuple containing:
|
|
67
|
+
- is_list: Boolean indicating if the type is a List
|
|
68
|
+
- item_type: The type of list items (str if not a list or no args)
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
>>> TypeUtils.is_list_type(List[str])
|
|
72
|
+
(True, str)
|
|
73
|
+
>>> TypeUtils.is_list_type(str)
|
|
74
|
+
(False, str)
|
|
75
|
+
"""
|
|
76
|
+
origin = typing.get_origin(python_type)
|
|
77
|
+
args = typing.get_args(python_type)
|
|
78
|
+
|
|
79
|
+
if origin in (list, typing.List):
|
|
80
|
+
item_type = args[0] if args else str
|
|
81
|
+
return True, item_type
|
|
82
|
+
|
|
83
|
+
return False, str
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def get_type_name(python_type: Type) -> str:
|
|
87
|
+
"""
|
|
88
|
+
Get a human-readable name for a type.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
python_type: The type to get the name for
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
Human-readable type name
|
|
95
|
+
|
|
96
|
+
Examples:
|
|
97
|
+
>>> TypeUtils.get_type_name(int)
|
|
98
|
+
'integer'
|
|
99
|
+
>>> TypeUtils.get_type_name(str)
|
|
100
|
+
'string'
|
|
101
|
+
"""
|
|
102
|
+
if python_type is int:
|
|
103
|
+
return "integer"
|
|
104
|
+
elif python_type is str:
|
|
105
|
+
return "string"
|
|
106
|
+
elif python_type is bool:
|
|
107
|
+
return "boolean"
|
|
108
|
+
elif python_type is float:
|
|
109
|
+
return "number"
|
|
110
|
+
else:
|
|
111
|
+
return getattr(python_type, "__name__", str(python_type))
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: tachyon-api
|
|
3
|
+
Version: 0.5.9
|
|
4
|
+
Summary: A lightweight, FastAPI-inspired web framework
|
|
5
|
+
License: GPL-3.0-or-later
|
|
6
|
+
Author: Juan Manuel Panozzo Zénere
|
|
7
|
+
Author-email: jm.panozzozenere@gmail.com
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: msgspec (>=0.19.0,<0.20.0)
|
|
16
|
+
Requires-Dist: orjson (>=3.11.1,<4.0.0)
|
|
17
|
+
Requires-Dist: starlette (>=0.47.2,<0.48.0)
|
|
18
|
+
Requires-Dist: typer (>=0.16.0,<0.17.0)
|
|
19
|
+
Requires-Dist: uvicorn (>=0.35.0,<0.36.0)
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# 🚀 Tachyon API
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+

|
|
26
|
+

|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
**A lightweight, high-performance API framework for Python with the elegance of FastAPI and the speed of light.**
|
|
30
|
+
|
|
31
|
+
Tachyon API combines the intuitive decorator-based syntax you love with minimal dependencies and maximal performance. Built with Test-Driven Development from the ground up, it offers a cleaner, faster alternative with full ASGI compatibility.
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from tachyon_api import Tachyon
|
|
35
|
+
from tachyon_api.models import Struct
|
|
36
|
+
|
|
37
|
+
app = Tachyon()
|
|
38
|
+
|
|
39
|
+
class User(Struct):
|
|
40
|
+
name: str
|
|
41
|
+
age: int
|
|
42
|
+
|
|
43
|
+
@app.get("/")
|
|
44
|
+
def hello_world():
|
|
45
|
+
return {"message": "Tachyon is running at lightspeed!"}
|
|
46
|
+
|
|
47
|
+
@app.post("/users")
|
|
48
|
+
def create_user(user: User):
|
|
49
|
+
return {"created": user.name}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## ✨ Features
|
|
53
|
+
|
|
54
|
+
- 🔍 Intuitive API (decorators) and minimal core
|
|
55
|
+
- 🧩 Implicit & explicit DI
|
|
56
|
+
- 📚 OpenAPI with Scalar, Swagger, ReDoc
|
|
57
|
+
- 🛠️ Router system
|
|
58
|
+
- 🔄 Middlewares (class + decorator)
|
|
59
|
+
- 🧠 Cache decorator with TTL (in-memory, Redis, Memcached)
|
|
60
|
+
- 🚀 High-performance JSON (msgspec + orjson)
|
|
61
|
+
- 🧾 Unified error format (422/500) + global exception handler (500)
|
|
62
|
+
- 🧰 Default JSON response (TachyonJSONResponse)
|
|
63
|
+
- 🔒 End-to-end safety: request Body validation + typed response_model
|
|
64
|
+
- 📘 Deep OpenAPI schemas: nested Structs, Optional/List (nullable/array), formats (uuid, date-time)
|
|
65
|
+
|
|
66
|
+
## 🧪 Test-Driven Development
|
|
67
|
+
|
|
68
|
+
Tachyon API is built with TDD principles at its core. The test suite covers routing, DI, params, body validation, responses, OpenAPI generation, caching, and example flows.
|
|
69
|
+
|
|
70
|
+
## 🔌 Core Dependencies
|
|
71
|
+
|
|
72
|
+
- Starlette (ASGI)
|
|
73
|
+
- msgspec (validation/serialization)
|
|
74
|
+
- orjson (fast JSON)
|
|
75
|
+
- uvicorn (server)
|
|
76
|
+
|
|
77
|
+
## 💉 Dependency Injection System
|
|
78
|
+
|
|
79
|
+
- Implicit injection: annotate with registered types
|
|
80
|
+
- Explicit injection: Depends() for clarity and control
|
|
81
|
+
|
|
82
|
+
## 🔄 Middleware Support
|
|
83
|
+
|
|
84
|
+
- Built-in: CORSMiddleware and LoggerMiddleware
|
|
85
|
+
- Use app.add_middleware(...) or @app.middleware()
|
|
86
|
+
|
|
87
|
+
## ⚡ Cache with TTL
|
|
88
|
+
|
|
89
|
+
- @cache(TTL=...) on routes and functions
|
|
90
|
+
- Per-app config and pluggable backends (InMemory, Redis, Memcached)
|
|
91
|
+
|
|
92
|
+
## 📚 Example Application
|
|
93
|
+
|
|
94
|
+
The example demonstrates clean architecture, routers, middlewares, caching, end-to-end safety, and global exception handling:
|
|
95
|
+
|
|
96
|
+
- /orjson-demo: default JSON powered by orjson
|
|
97
|
+
- /api/v1/users/e2e: Body + response_model, unified errors and deep OpenAPI schemas
|
|
98
|
+
- /error-demo: triggers an unhandled exception to showcase the global handler (structured 500)
|
|
99
|
+
|
|
100
|
+
Run the example:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
cd example
|
|
104
|
+
python app.py
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Docs at /docs (Scalar), /swagger, /redoc.
|
|
108
|
+
|
|
109
|
+
## ✅ Response models, OpenAPI params, and deep schemas
|
|
110
|
+
|
|
111
|
+
- Response models: set response_model=YourStruct to validate/convert outputs via msgspec before serializing.
|
|
112
|
+
- Parameter schemas: Optional[T] → nullable: true; List[T] → type: array with items.
|
|
113
|
+
- Deep schemas: nested Struct components, Optional/List items, and formats (uuid, date-time) are generated and referenced in components.
|
|
114
|
+
|
|
115
|
+
## 🧾 Default JSON response and unified error format
|
|
116
|
+
|
|
117
|
+
- Default response: TachyonJSONResponse serializes complex types (UUID/date/datetime, Struct) via orjson and centralized encoders.
|
|
118
|
+
- 422 Validation: { success: false, error, code: VALIDATION_ERROR, [errors] }.
|
|
119
|
+
- 500 Response model: { success: false, error: "Response validation error: ...", detail, code: RESPONSE_VALIDATION_ERROR }.
|
|
120
|
+
- 500 Unhandled exceptions (global): { success: false, error: "Internal Server Error", code: INTERNAL_SERVER_ERROR }.
|
|
121
|
+
|
|
122
|
+
## 📝 Contributing
|
|
123
|
+
|
|
124
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
125
|
+
|
|
126
|
+
1. Fork the repository
|
|
127
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
128
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
129
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
130
|
+
5. Open a Pull Request
|
|
131
|
+
|
|
132
|
+
## 📜 License
|
|
133
|
+
|
|
134
|
+
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
|
135
|
+
|
|
136
|
+
## 🔮 Roadmap
|
|
137
|
+
|
|
138
|
+
- Exception system and global handlers
|
|
139
|
+
- CLI, scaffolding, and code quality tooling
|
|
140
|
+
- Authentication middleware and benchmarks
|
|
141
|
+
- More examples and deployment guides
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
*Built with 💜 by developers, for developers*
|
|
146
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
tachyon_api/__init__.py,sha256=CEg69nSVW9iCLYgqVNvSr_7EICb9nrLuaDVxKlpm430,1207
|
|
2
|
+
tachyon_api/app.py,sha256=iHMn6A2Be1RCSYAoQ6vSfW_21rUNrY3pkjuIHThRx2c,35329
|
|
3
|
+
tachyon_api/cache.py,sha256=IIdg9yTiNuc9CEgV33yLXz9ssmHqI9IiqMilRbM-aZ8,8312
|
|
4
|
+
tachyon_api/di.py,sha256=FyFghfUjU0OaE_lW2BqItgsZWXFbLvwFsvVywqFjl6c,1505
|
|
5
|
+
tachyon_api/middlewares/__init__.py,sha256=kxZ6afQocHKsUG9xyaVFHlGUzmxqo7kZEm-GhfxY5NQ,120
|
|
6
|
+
tachyon_api/middlewares/core.py,sha256=-dJTrI6KJbQzatopCUC5lau_JIZpl063697qdE4W0SY,1440
|
|
7
|
+
tachyon_api/middlewares/cors.py,sha256=IzaedBdUCOYsQpMhZRN3mAzDevvQVnKDYzMrqY56bNA,6068
|
|
8
|
+
tachyon_api/middlewares/logger.py,sha256=TcYcfBuc8iBGZZIW6aMvJ_foFD7by9vM_EsHnhH9E_Y,4908
|
|
9
|
+
tachyon_api/models.py,sha256=9pA5_ddMAcWW2dErAgeyG926NFezfCU68uuhW0qGMs4,2224
|
|
10
|
+
tachyon_api/openapi.py,sha256=qXme5RCn-px4LH6mJ8LE8eKev1ZLrGCyNCMDhZRy86w,14493
|
|
11
|
+
tachyon_api/params.py,sha256=gLGIsFEGr33_G0kakpqOFHRrf86w3egFJAjquZp3Lo0,2810
|
|
12
|
+
tachyon_api/responses.py,sha256=vFH8RsQxsuOoaSE6hBh1_UhXC_jdFyBdeYyMYDtIuDg,2945
|
|
13
|
+
tachyon_api/router.py,sha256=TlzgJ-UAfxBAQKy4YNVQIBObIDNzlebQ4G9qxsswJQ0,4204
|
|
14
|
+
tachyon_api/utils/__init__.py,sha256=O-GmW5oTbG10TRz2q3NCzAQD3FBZrUn65qf8mywM47M,347
|
|
15
|
+
tachyon_api/utils/type_converter.py,sha256=l0akBnETvPBqhS_utzCWO65AiQ7cTxzkSL7Juo9p7sA,4151
|
|
16
|
+
tachyon_api/utils/type_utils.py,sha256=Bovpofif-gH6Q-ehmZrauMMHWSypQgiu6tsjHV3UtTU,3351
|
|
17
|
+
tachyon_api-0.5.9.dist-info/LICENSE,sha256=UZXUTSuWBt8V377-2_YE4ug9t6rcBAKrfOVhIBQ8zhk,712
|
|
18
|
+
tachyon_api-0.5.9.dist-info/METADATA,sha256=sgcY1FjH0_HMqAvA1iBA1o686tfnxyyU-8BnnJ-3rek,5262
|
|
19
|
+
tachyon_api-0.5.9.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
20
|
+
tachyon_api-0.5.9.dist-info/RECORD,,
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: tachyon-api
|
|
3
|
-
Version: 0.5.5
|
|
4
|
-
Summary: A lightweight, FastAPI-inspired web framework
|
|
5
|
-
License: GPL-3.0-or-later
|
|
6
|
-
Author: Juan Manuel Panozzo Zénere
|
|
7
|
-
Author-email: jm.panozzozenere@gmail.com
|
|
8
|
-
Requires-Python: >=3.10,<4.0
|
|
9
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Requires-Dist: msgspec (>=0.19.0,<0.20.0)
|
|
16
|
-
Requires-Dist: orjson (>=3.11.1,<4.0.0)
|
|
17
|
-
Requires-Dist: ruff (>=0.12.7,<0.13.0)
|
|
18
|
-
Requires-Dist: starlette (>=0.47.2,<0.48.0)
|
|
19
|
-
Requires-Dist: typer (>=0.16.0,<0.17.0)
|
|
20
|
-
Requires-Dist: uvicorn (>=0.35.0,<0.36.0)
|
|
21
|
-
Description-Content-Type: text/markdown
|
|
22
|
-
|
|
23
|
-
# 🚀 Tachyon API
|
|
24
|
-
|
|
25
|
-

|
|
26
|
-

|
|
27
|
-

|
|
28
|
-

|
|
29
|
-
|
|
30
|
-
**A lightweight, high-performance API framework for Python with the elegance of FastAPI and the speed of light.**
|
|
31
|
-
|
|
32
|
-
Tachyon API combines the intuitive decorator-based syntax you love with minimal dependencies and maximal performance. Built with Test-Driven Development from the ground up, it offers a cleaner, faster alternative with full ASGI compatibility.
|
|
33
|
-
|
|
34
|
-
```python
|
|
35
|
-
from tachyon_api import Tachyon
|
|
36
|
-
from tachyon_api.models import Struct
|
|
37
|
-
|
|
38
|
-
app = Tachyon()
|
|
39
|
-
|
|
40
|
-
class User(Struct):
|
|
41
|
-
name: str
|
|
42
|
-
age: int
|
|
43
|
-
|
|
44
|
-
@app.get("/")
|
|
45
|
-
def hello_world():
|
|
46
|
-
return {"message": "Tachyon is running at lightspeed!"}
|
|
47
|
-
|
|
48
|
-
@app.post("/users")
|
|
49
|
-
def create_user(user: User):
|
|
50
|
-
return {"created": user.name}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## ✨ Features
|
|
54
|
-
|
|
55
|
-
- 🔍 **Intuitive API** - Elegant decorator-based routing inspired by FastAPI
|
|
56
|
-
- 🧩 **Implicit & Explicit Dependency Injection** - Both supported for maximum flexibility
|
|
57
|
-
- 📚 **Automatic OpenAPI Documentation** - With Scalar UI, Swagger UI, and ReDoc support
|
|
58
|
-
- 🛠️ **Router System** - Organize your API endpoints with powerful route grouping
|
|
59
|
-
- 🧪 **Built with TDD** - Comprehensive test suite ensures stability and correctness
|
|
60
|
-
- 🔄 **Middleware Support** - Both class-based and decorator-based approaches
|
|
61
|
-
- 🚀 **High-Performance JSON** - Powered by msgspec and orjson for lightning-fast processing
|
|
62
|
-
- 🪶 **Minimal Dependencies** - Lean core with only what you really need
|
|
63
|
-
|
|
64
|
-
## 📦 Installation
|
|
65
|
-
|
|
66
|
-
Tachyon API is currently in beta. The package will be available on PyPI and Poetry repositories soon!
|
|
67
|
-
|
|
68
|
-
### From source (Currently the only method)
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
git clone https://github.com/jmpanozzoz/tachyon_api.git
|
|
72
|
-
cd tachyon-api
|
|
73
|
-
pip install -r requirements.txt
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
> **Note:** The `pip install tachyon-api` and `poetry add tachyon-api` commands will be available once the package is published to PyPI.
|
|
77
|
-
|
|
78
|
-
## 🔍 Key Differences from FastAPI
|
|
79
|
-
|
|
80
|
-
While inspired by FastAPI's elegant API design, Tachyon API takes a different approach in several key areas:
|
|
81
|
-
|
|
82
|
-
| Feature | Tachyon API | FastAPI |
|
|
83
|
-
|---------|------------|---------|
|
|
84
|
-
| **Core Dependencies** | Minimalist: Starlette + msgspec + orjson | Pydantic + multiple dependencies |
|
|
85
|
-
| **Validation Engine** | msgspec (faster, lighter) | Pydantic (more features, heavier) |
|
|
86
|
-
| **Dependency Injection** | Both implicit and explicit | Primarily explicit |
|
|
87
|
-
| **Middleware Approach** | Dual API (class + decorator) | Class-based |
|
|
88
|
-
| **Development Approach** | Test-Driven from the start | Feature-driven |
|
|
89
|
-
| **Documentation UI** | Scalar UI (default), Swagger, ReDoc | Swagger UI (default), ReDoc |
|
|
90
|
-
| **Size** | Lightweight, focused | Comprehensive, full-featured |
|
|
91
|
-
|
|
92
|
-
## 🧪 Test-Driven Development
|
|
93
|
-
|
|
94
|
-
Tachyon API is built with TDD principles at its core:
|
|
95
|
-
|
|
96
|
-
- Every feature starts with a test
|
|
97
|
-
- Comprehensive test coverage
|
|
98
|
-
- Self-contained test architecture
|
|
99
|
-
- Clear test documentation
|
|
100
|
-
|
|
101
|
-
This ensures stability, maintainability, and prevents regressions as the framework evolves.
|
|
102
|
-
|
|
103
|
-
## 🔌 Core Dependencies
|
|
104
|
-
|
|
105
|
-
Tachyon API maintains a minimal, carefully selected set of dependencies:
|
|
106
|
-
|
|
107
|
-
- **[Starlette](https://www.starlette.io/)**: ASGI framework providing solid foundations
|
|
108
|
-
- **[msgspec](https://jcristharif.com/msgspec/)**: Ultra-fast serialization and validation
|
|
109
|
-
- **[orjson](https://github.com/ijl/orjson)**: High-performance JSON parser
|
|
110
|
-
- **[uvicorn](https://www.uvicorn.org/)**: ASGI server for development and production
|
|
111
|
-
|
|
112
|
-
These were chosen for their performance, lightweight nature, and focused functionality.
|
|
113
|
-
|
|
114
|
-
## 💉 Dependency Injection System
|
|
115
|
-
|
|
116
|
-
Tachyon API offers a flexible dependency injection system:
|
|
117
|
-
|
|
118
|
-
### Implicit Injection
|
|
119
|
-
|
|
120
|
-
```python
|
|
121
|
-
@injectable
|
|
122
|
-
class UserService:
|
|
123
|
-
def __init__(self, repository: UserRepository): # Auto-injected!
|
|
124
|
-
self.repository = repository
|
|
125
|
-
|
|
126
|
-
@app.get("/users/{user_id}")
|
|
127
|
-
def get_user(user_id: int, service: UserService): # Auto-injected!
|
|
128
|
-
return service.get_user(user_id)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Explicit Injection
|
|
132
|
-
|
|
133
|
-
```python
|
|
134
|
-
@app.get("/users/{user_id}")
|
|
135
|
-
def get_user(user_id: int, service: UserService = Depends()):
|
|
136
|
-
return service.get_user(user_id)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## 🔄 Middleware Support
|
|
140
|
-
|
|
141
|
-
Tachyon API supports middlewares in two elegant ways:
|
|
142
|
-
|
|
143
|
-
### Class-based Approach
|
|
144
|
-
|
|
145
|
-
```python
|
|
146
|
-
from tachyon_api.middlewares import CORSMiddleware, LoggerMiddleware
|
|
147
|
-
|
|
148
|
-
# Add built-in CORS middleware
|
|
149
|
-
app.add_middleware(
|
|
150
|
-
CORSMiddleware,
|
|
151
|
-
allow_origins=["*"],
|
|
152
|
-
allow_methods=["*"],
|
|
153
|
-
allow_headers=["*"],
|
|
154
|
-
allow_credentials=False,
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
# Add built-in Logger middleware
|
|
158
|
-
app.add_middleware(
|
|
159
|
-
LoggerMiddleware,
|
|
160
|
-
include_headers=True,
|
|
161
|
-
redact_headers=["authorization"],
|
|
162
|
-
)
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Decorator-based Approach
|
|
166
|
-
|
|
167
|
-
```python
|
|
168
|
-
@app.middleware()
|
|
169
|
-
async def timing_middleware(scope, receive, send, app):
|
|
170
|
-
start_time = time.time()
|
|
171
|
-
await app(scope, receive, send)
|
|
172
|
-
print(f"Request took {time.time() - start_time:.4f}s")
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Built-in Middlewares
|
|
176
|
-
|
|
177
|
-
- CORSMiddleware: Handles preflight requests and injects CORS headers into responses. Highly configurable with allow_origins, allow_methods, allow_headers, allow_credentials, expose_headers, and max_age.
|
|
178
|
-
- LoggerMiddleware: Logs request start/end, duration, status code, and optionally headers and a non-intrusive body preview.
|
|
179
|
-
|
|
180
|
-
Both middlewares are standard ASGI middlewares and can be used with `app.add_middleware(...)`.
|
|
181
|
-
|
|
182
|
-
## 📚 Example Application
|
|
183
|
-
|
|
184
|
-
For a complete example showcasing all features, see the [example directory](./example). It demonstrates:
|
|
185
|
-
|
|
186
|
-
- Clean architecture with models, services, and repositories
|
|
187
|
-
- Router organization
|
|
188
|
-
- Middleware implementation
|
|
189
|
-
- Dependency injection patterns
|
|
190
|
-
- OpenAPI documentation
|
|
191
|
-
|
|
192
|
-
Built-in CORS and Logger middlewares are integrated in the example for convenience. You can toggle settings in `example/app.py`.
|
|
193
|
-
|
|
194
|
-
Run the example with:
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
cd example
|
|
198
|
-
python app.py
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Then visit:
|
|
202
|
-
- **API**: http://localhost:8000/
|
|
203
|
-
- **Documentation**: http://localhost:8000/docs
|
|
204
|
-
|
|
205
|
-
## 📝 Contributing
|
|
206
|
-
|
|
207
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
208
|
-
|
|
209
|
-
1. Fork the repository
|
|
210
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
211
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
212
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
213
|
-
5. Open a Pull Request
|
|
214
|
-
|
|
215
|
-
## 📜 License
|
|
216
|
-
|
|
217
|
-
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
|
218
|
-
|
|
219
|
-
## 🔮 Roadmap
|
|
220
|
-
|
|
221
|
-
- [ ] **Exception System**: Standardized exception handling and error responses
|
|
222
|
-
- [ ] **Environment Management**: Built-in environment variable handling and uvicorn integration
|
|
223
|
-
- [ ] **CLI Tool**: Project scaffolding and service generation
|
|
224
|
-
- Directory structure generation
|
|
225
|
-
- Service and repository templates
|
|
226
|
-
- API endpoint generation
|
|
227
|
-
- [ ] **Code Quality Tools**: Ruff integration for linting and formatting
|
|
228
|
-
- [ ] **Performance Optimization**: Cython compilation for service layer via CLI
|
|
229
|
-
- [ ] **Authentication Middleware**: Built-in auth patterns and middleware
|
|
230
|
-
- [ ] **Performance Benchmarks**: Comparisons against other frameworks
|
|
231
|
-
- [ ] **More Example Applications**: Demonstrating different use cases
|
|
232
|
-
- [ ] **Plugin System**: Extensibility through plugins
|
|
233
|
-
- [ ] **Deployment Guides**: Documentation for various deployment scenarios
|
|
234
|
-
- [ ] **And much more!**
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
*Built with 💜 by developers, for developers*
|
|
239
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
tachyon_api/__init__.py,sha256=MrwA2s-dfpygkU3iY6SghCeuWuF_tNwdWPQ9Onp-pmM,776
|
|
2
|
-
tachyon_api/app.py,sha256=Gt_ufNXdHAOR9lYJ8inLO_n-BuO_8VYmjTsuiab-r-k,24271
|
|
3
|
-
tachyon_api/di.py,sha256=FyFghfUjU0OaE_lW2BqItgsZWXFbLvwFsvVywqFjl6c,1505
|
|
4
|
-
tachyon_api/middlewares/__init__.py,sha256=BR1kqTj2IKdwhvVZCVn9p_rOFS0aOYoaC0bNX0C_0q4,121
|
|
5
|
-
tachyon_api/middlewares/core.py,sha256=-dJTrI6KJbQzatopCUC5lau_JIZpl063697qdE4W0SY,1440
|
|
6
|
-
tachyon_api/middlewares/cors.py,sha256=jZMqfFSz-14dwNIOOMqKaQm8Dypnf0V_WVW_4Uuc4AE,5716
|
|
7
|
-
tachyon_api/middlewares/logger.py,sha256=8W543kmfu7f5LpDQOox8Z4t3QT1knko7bUx7kWLCzWw,4832
|
|
8
|
-
tachyon_api/models.py,sha256=9pA5_ddMAcWW2dErAgeyG926NFezfCU68uuhW0qGMs4,2224
|
|
9
|
-
tachyon_api/openapi.py,sha256=MHrA7DnVW88gyh1fiiLx1-uE1mc-eU4yseD6dCf_wxs,11688
|
|
10
|
-
tachyon_api/params.py,sha256=gLGIsFEGr33_G0kakpqOFHRrf86w3egFJAjquZp3Lo0,2810
|
|
11
|
-
tachyon_api/responses.py,sha256=FaPv4xTXTw4jvyErsA7Gkp0l0POln-0_0bE6rbtsmcE,1574
|
|
12
|
-
tachyon_api/router.py,sha256=TlzgJ-UAfxBAQKy4YNVQIBObIDNzlebQ4G9qxsswJQ0,4204
|
|
13
|
-
tachyon_api-0.5.5.dist-info/LICENSE,sha256=UZXUTSuWBt8V377-2_YE4ug9t6rcBAKrfOVhIBQ8zhk,712
|
|
14
|
-
tachyon_api-0.5.5.dist-info/METADATA,sha256=F2WE9mBCeW6YJaYTaygrRphBpjCWkRLeQ1DjQNGjl2k,8413
|
|
15
|
-
tachyon_api-0.5.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
16
|
-
tachyon_api-0.5.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|