hypern 0.3.13__cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl → 0.3.15__cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.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.
- hypern/application.py +12 -140
- hypern/auth/__init__.py +6 -0
- hypern/auth/decorators.py +41 -0
- hypern/auth/jwt.py +37 -0
- hypern/auth/middleware.py +31 -0
- hypern/auth/providers.py +36 -0
- hypern/datastructures.py +54 -3
- hypern/hypern.cpython-311-s390x-linux-gnu.so +0 -0
- hypern/hypern.pyi +1 -0
- hypern/openapi/schemas.py +4 -3
- hypern/routing/parser.py +0 -6
- hypern/routing/route.py +0 -8
- {hypern-0.3.13.dist-info → hypern-0.3.15.dist-info}/METADATA +16 -16
- {hypern-0.3.13.dist-info → hypern-0.3.15.dist-info}/RECORD +58 -55
- {hypern-0.3.13.dist-info → hypern-0.3.15.dist-info}/WHEEL +1 -1
- hypern/auth/authorization.py +0 -2
- {hypern-0.3.13.dist-info → hypern-0.3.15.dist-info}/licenses/LICENSE +0 -0
hypern/application.py
CHANGED
@@ -10,7 +10,7 @@ import psutil
|
|
10
10
|
from typing_extensions import Annotated, Doc
|
11
11
|
|
12
12
|
from hypern.args_parser import ArgsConfig
|
13
|
-
from hypern.datastructures import
|
13
|
+
from hypern.datastructures import SwaggerConfig
|
14
14
|
from hypern.enum import HTTPMethod
|
15
15
|
from hypern.hypern import DatabaseConfig, FunctionInfo, MiddlewareConfig, Router, Server, WebsocketRouter, Scheduler
|
16
16
|
from hypern.hypern import Route as InternalRoute
|
@@ -91,121 +91,11 @@ class Hypern:
|
|
91
91
|
"""
|
92
92
|
),
|
93
93
|
] = None,
|
94
|
-
|
95
|
-
|
94
|
+
swagger_config: Annotated[
|
95
|
+
SwaggerConfig | None,
|
96
96
|
Doc(
|
97
97
|
"""
|
98
|
-
|
99
|
-
|
100
|
-
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
101
|
-
|
102
|
-
Read more in the
|
103
|
-
"""
|
104
|
-
),
|
105
|
-
] = "Hypern",
|
106
|
-
summary: Annotated[
|
107
|
-
str | None,
|
108
|
-
Doc(
|
109
|
-
""""
|
110
|
-
A short summary of the API.
|
111
|
-
|
112
|
-
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
113
|
-
"""
|
114
|
-
),
|
115
|
-
] = None,
|
116
|
-
description: Annotated[
|
117
|
-
str,
|
118
|
-
Doc(
|
119
|
-
"""
|
120
|
-
A description of the API. Supports Markdown (using
|
121
|
-
[CommonMark syntax](https://commonmark.org/)).
|
122
|
-
|
123
|
-
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
124
|
-
"""
|
125
|
-
),
|
126
|
-
] = "",
|
127
|
-
version: Annotated[
|
128
|
-
str,
|
129
|
-
Doc(
|
130
|
-
"""
|
131
|
-
The version of the API.
|
132
|
-
|
133
|
-
**Note** This is the version of your application, not the version of
|
134
|
-
the OpenAPI specification nor the version of Application being used.
|
135
|
-
|
136
|
-
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
137
|
-
"""
|
138
|
-
),
|
139
|
-
] = "0.0.1",
|
140
|
-
contact: Annotated[
|
141
|
-
Contact | None,
|
142
|
-
Doc(
|
143
|
-
"""
|
144
|
-
A dictionary with the contact information for the exposed API.
|
145
|
-
|
146
|
-
It can contain several fields.
|
147
|
-
|
148
|
-
* `name`: (`str`) The name of the contact person/organization.
|
149
|
-
* `url`: (`str`) A URL pointing to the contact information. MUST be in
|
150
|
-
the format of a URL.
|
151
|
-
* `email`: (`str`) The email address of the contact person/organization.
|
152
|
-
MUST be in the format of an email address.
|
153
|
-
"""
|
154
|
-
),
|
155
|
-
] = None,
|
156
|
-
openapi_url: Annotated[
|
157
|
-
str | None,
|
158
|
-
Doc(
|
159
|
-
"""
|
160
|
-
The URL where the OpenAPI schema will be served from.
|
161
|
-
|
162
|
-
If you set it to `None`, no OpenAPI schema will be served publicly, and
|
163
|
-
the default automatic endpoints `/docs` and `/redoc` will also be
|
164
|
-
disabled.
|
165
|
-
"""
|
166
|
-
),
|
167
|
-
] = "/openapi.json",
|
168
|
-
docs_url: Annotated[
|
169
|
-
str | None,
|
170
|
-
Doc(
|
171
|
-
"""
|
172
|
-
The path to the automatic interactive API documentation.
|
173
|
-
It is handled in the browser by Swagger UI.
|
174
|
-
|
175
|
-
The default URL is `/docs`. You can disable it by setting it to `None`.
|
176
|
-
|
177
|
-
If `openapi_url` is set to `None`, this will be automatically disabled.
|
178
|
-
"""
|
179
|
-
),
|
180
|
-
] = "/docs",
|
181
|
-
license_info: Annotated[
|
182
|
-
License | None,
|
183
|
-
Doc(
|
184
|
-
"""
|
185
|
-
A dictionary with the license information for the exposed API.
|
186
|
-
|
187
|
-
It can contain several fields.
|
188
|
-
|
189
|
-
* `name`: (`str`) **REQUIRED** (if a `license_info` is set). The
|
190
|
-
license name used for the API.
|
191
|
-
* `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression
|
192
|
-
for the API. The `identifier` field is mutually exclusive of the `url`
|
193
|
-
field. Available since OpenAPI 3.1.0
|
194
|
-
* `url`: (`str`) A URL to the license used for the API. This MUST be
|
195
|
-
the format of a URL.
|
196
|
-
|
197
|
-
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
198
|
-
|
199
|
-
**Example**
|
200
|
-
|
201
|
-
```python
|
202
|
-
app = Hypern(
|
203
|
-
license_info={
|
204
|
-
"name": "Apache 2.0",
|
205
|
-
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
|
206
|
-
}
|
207
|
-
)
|
208
|
-
```
|
98
|
+
A dictionary with the configuration for the Swagger UI documentation.
|
209
99
|
"""
|
210
100
|
),
|
211
101
|
] = None,
|
@@ -241,6 +131,7 @@ class Hypern:
|
|
241
131
|
self.shutdown_handler = None
|
242
132
|
self.database_config = database_config
|
243
133
|
self.thread_config = ThreadConfigurator().get_config()
|
134
|
+
self.swagger_config = swagger_config
|
244
135
|
|
245
136
|
for route in routes or []:
|
246
137
|
self.router.extend_route(route())
|
@@ -249,25 +140,12 @@ class Hypern:
|
|
249
140
|
for route in websocket_route.routes:
|
250
141
|
self.websocket_router.add_route(route)
|
251
142
|
|
252
|
-
if
|
253
|
-
self.__add_openapi(
|
254
|
-
info=Info(
|
255
|
-
title=title,
|
256
|
-
summary=summary,
|
257
|
-
description=description,
|
258
|
-
version=version,
|
259
|
-
contact=contact,
|
260
|
-
license=license_info,
|
261
|
-
),
|
262
|
-
openapi_url=openapi_url,
|
263
|
-
docs_url=docs_url,
|
264
|
-
)
|
143
|
+
if swagger_config:
|
144
|
+
self.__add_openapi(config=swagger_config)
|
265
145
|
|
266
146
|
def __add_openapi(
|
267
147
|
self,
|
268
|
-
|
269
|
-
openapi_url: str,
|
270
|
-
docs_url: str,
|
148
|
+
config: SwaggerConfig,
|
271
149
|
):
|
272
150
|
"""
|
273
151
|
Adds OpenAPI schema and documentation routes to the application.
|
@@ -285,25 +163,19 @@ class Hypern:
|
|
285
163
|
"""
|
286
164
|
|
287
165
|
def schema(*args, **kwargs):
|
288
|
-
schemas = SchemaGenerator(
|
289
|
-
{
|
290
|
-
"openapi": "3.0.0",
|
291
|
-
"info": info.model_dump(),
|
292
|
-
"components": {"securitySchemes": {}},
|
293
|
-
}
|
294
|
-
)
|
166
|
+
schemas = SchemaGenerator(config=config)
|
295
167
|
return JSONResponse(content=orjson.dumps(schemas.get_schema(self)))
|
296
168
|
|
297
169
|
def template_render(*args, **kwargs):
|
298
170
|
swagger = SwaggerUI(
|
299
171
|
title="Swagger",
|
300
|
-
openapi_url=openapi_url,
|
172
|
+
openapi_url=config.openapi_url,
|
301
173
|
)
|
302
174
|
template = swagger.get_html_content()
|
303
175
|
return HTMLResponse(template)
|
304
176
|
|
305
|
-
self.add_route(HTTPMethod.GET, openapi_url, schema)
|
306
|
-
self.add_route(HTTPMethod.GET, docs_url, template_render)
|
177
|
+
self.add_route(HTTPMethod.GET, config.openapi_url, schema)
|
178
|
+
self.add_route(HTTPMethod.GET, config.docs_url, template_render)
|
307
179
|
|
308
180
|
def inject(self, key: str, value: Any):
|
309
181
|
"""
|
hypern/auth/__init__.py
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
import asyncio
|
2
|
+
from functools import wraps
|
3
|
+
from typing import Any, Callable, List, Optional
|
4
|
+
|
5
|
+
from hypern.hypern import Request, Response
|
6
|
+
from hypern.response import JSONResponse
|
7
|
+
|
8
|
+
|
9
|
+
def requires_auth(roles: Optional[List[str]] = None):
|
10
|
+
"""
|
11
|
+
A decorator to enforce authentication and authorization on an endpoint.
|
12
|
+
|
13
|
+
Args:
|
14
|
+
roles (Optional[List[str]]): A list of roles that are allowed to access the endpoint. If None, any authenticated user can access.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
Callable: The decorated function with authentication and authorization checks.
|
18
|
+
|
19
|
+
The decorator checks if the request has an 'auth' attribute. If not, it returns a 401 Unauthorized response.
|
20
|
+
If roles are specified, it checks if the user's role is in the allowed roles. If not, it returns a 403 Forbidden response.
|
21
|
+
If the function being decorated is a coroutine, it awaits the function call.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def decorator(func: Callable) -> Callable:
|
25
|
+
@wraps(func)
|
26
|
+
async def wrapper(self, request: Request, *args: Any, **kwargs: Any) -> Response:
|
27
|
+
request.auth = {}
|
28
|
+
if not hasattr(request, "auth"):
|
29
|
+
return JSONResponse({"error": "Authentication required"}, status_code=401)
|
30
|
+
|
31
|
+
if roles and "role" in request.auth:
|
32
|
+
if request.auth["role"] not in roles:
|
33
|
+
return JSONResponse({"error": "Insufficient permissions"}, status_code=403)
|
34
|
+
# check function is awaitable
|
35
|
+
if asyncio.iscoroutinefunction(func):
|
36
|
+
return await func(self, request, *args, **kwargs)
|
37
|
+
return func(self, request, *args, **kwargs)
|
38
|
+
|
39
|
+
return wrapper
|
40
|
+
|
41
|
+
return decorator
|
hypern/auth/jwt.py
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# hypern/auth/jwt.py
|
2
|
+
from datetime import datetime, timedelta, timezone
|
3
|
+
from typing import Any, Dict, Optional
|
4
|
+
|
5
|
+
import jwt
|
6
|
+
from pydantic import BaseModel
|
7
|
+
|
8
|
+
|
9
|
+
class JWTConfig(BaseModel):
|
10
|
+
secret_key: str
|
11
|
+
algorithm: str = "HS256"
|
12
|
+
access_token_expire_minutes: int = 30
|
13
|
+
refresh_token_expire_days: int = 7
|
14
|
+
|
15
|
+
|
16
|
+
class JWTAuth:
|
17
|
+
def __init__(self, config: JWTConfig):
|
18
|
+
self.config = config
|
19
|
+
|
20
|
+
def create_access_token(self, data: Dict[str, Any]) -> str:
|
21
|
+
expire = datetime.now(tz=timezone.utc) + timedelta(minutes=self.config.access_token_expire_minutes)
|
22
|
+
to_encode = data.copy()
|
23
|
+
to_encode.update({"exp": expire, "type": "access"})
|
24
|
+
return jwt.encode(to_encode, self.config.secret_key, algorithm=self.config.algorithm)
|
25
|
+
|
26
|
+
def create_refresh_token(self, data: Dict[str, Any]) -> str:
|
27
|
+
expire = datetime.now(tz=timezone.utc) + timedelta(days=self.config.refresh_token_expire_days)
|
28
|
+
to_encode = data.copy()
|
29
|
+
to_encode.update({"exp": expire, "type": "refresh"})
|
30
|
+
return jwt.encode(to_encode, self.config.secret_key, algorithm=self.config.algorithm)
|
31
|
+
|
32
|
+
def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
|
33
|
+
try:
|
34
|
+
payload = jwt.decode(token, self.config.secret_key, algorithms=[self.config.algorithm])
|
35
|
+
return payload
|
36
|
+
except jwt.PyJWTError:
|
37
|
+
return None
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# hypern/auth/middleware.py
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from hypern.hypern import Request
|
5
|
+
from hypern.response import JSONResponse
|
6
|
+
from hypern.middleware.base import Middleware
|
7
|
+
|
8
|
+
from .jwt import JWTAuth
|
9
|
+
|
10
|
+
|
11
|
+
class AuthMiddleware(Middleware):
|
12
|
+
def __init__(self, jwt_auth: JWTAuth, exclude_paths: Optional[List[str]] = None):
|
13
|
+
self.jwt_auth = jwt_auth
|
14
|
+
self.exclude_paths = exclude_paths or []
|
15
|
+
|
16
|
+
async def before_request(self, request: Request):
|
17
|
+
if request.path in self.exclude_paths:
|
18
|
+
return None
|
19
|
+
|
20
|
+
auth_header = request.headers.get("Authorization")
|
21
|
+
if not auth_header or not auth_header.startswith("Bearer "):
|
22
|
+
return JSONResponse({"error": "Invalid authentication"}, status_code=401)
|
23
|
+
|
24
|
+
token = auth_header.split(" ")[1]
|
25
|
+
payload = self.jwt_auth.verify_token(token)
|
26
|
+
|
27
|
+
if not payload:
|
28
|
+
return JSONResponse({"error": "Invalid token"}, status_code=401)
|
29
|
+
|
30
|
+
request.auth = payload
|
31
|
+
return None
|
hypern/auth/providers.py
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
from typing import Dict
|
2
|
+
from dataclasses import dataclass
|
3
|
+
|
4
|
+
|
5
|
+
@dataclass
|
6
|
+
class OAuth2Provider:
|
7
|
+
name: str
|
8
|
+
client_id: str
|
9
|
+
client_secret: str
|
10
|
+
authorize_url: str
|
11
|
+
token_url: str
|
12
|
+
scopes: Dict[str, str]
|
13
|
+
|
14
|
+
|
15
|
+
class OAuth2Providers:
|
16
|
+
@staticmethod
|
17
|
+
def github(client_id: str, client_secret: str) -> OAuth2Provider:
|
18
|
+
return OAuth2Provider(
|
19
|
+
name="GitHub",
|
20
|
+
client_id=client_id,
|
21
|
+
client_secret=client_secret,
|
22
|
+
authorize_url="https://github.com/login/oauth/authorize",
|
23
|
+
token_url="https://github.com/login/oauth/access_token",
|
24
|
+
scopes={"user": "Read user information", "repo": "Access repositories"},
|
25
|
+
)
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def google(client_id: str, client_secret: str) -> OAuth2Provider:
|
29
|
+
return OAuth2Provider(
|
30
|
+
name="Google",
|
31
|
+
client_id=client_id,
|
32
|
+
client_secret=client_secret,
|
33
|
+
authorize_url="https://accounts.google.com/o/oauth2/v2/auth",
|
34
|
+
token_url="https://oauth2.googleapis.com/token",
|
35
|
+
scopes={"profile": "Read user profile", "email": "Read user email"},
|
36
|
+
)
|
hypern/datastructures.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import Optional, Dict
|
2
2
|
from pydantic import BaseModel, AnyUrl
|
3
|
+
from dataclasses import dataclass, field
|
3
4
|
|
4
5
|
|
5
6
|
class BaseModelWithConfig(BaseModel):
|
@@ -19,9 +20,59 @@ class License(BaseModelWithConfig):
|
|
19
20
|
|
20
21
|
|
21
22
|
class Info(BaseModelWithConfig):
|
22
|
-
title: str
|
23
|
+
title: str = "Swagger Document"
|
24
|
+
version: str = "0.0.1"
|
23
25
|
summary: Optional[str] = None
|
24
26
|
description: Optional[str] = None
|
25
27
|
contact: Optional[Contact] = None
|
26
28
|
license: Optional[License] = None
|
27
|
-
|
29
|
+
|
30
|
+
|
31
|
+
@dataclass
|
32
|
+
class OAuth2Flow:
|
33
|
+
authorizationUrl: Optional[str] = None
|
34
|
+
tokenUrl: Optional[str] = None
|
35
|
+
refreshUrl: Optional[str] = None
|
36
|
+
scopes: Dict[str, str] = field(default_factory=dict)
|
37
|
+
|
38
|
+
|
39
|
+
@dataclass
|
40
|
+
class OAuth2Config:
|
41
|
+
flows: Dict[str, OAuth2Flow]
|
42
|
+
description: str = "OAuth2 authentication"
|
43
|
+
|
44
|
+
|
45
|
+
@dataclass
|
46
|
+
class SwaggerConfig:
|
47
|
+
info: Info
|
48
|
+
oauth2_config: Optional[OAuth2Config] = None
|
49
|
+
openapi_url: str = "/openapi.json"
|
50
|
+
docs_url: str = "/docs"
|
51
|
+
|
52
|
+
def get_security_schemes(self) -> Dict:
|
53
|
+
if not self.oauth2_config:
|
54
|
+
return {}
|
55
|
+
|
56
|
+
security_schemes = {"oauth2": {"type": "oauth2", "description": self.oauth2_config.description, "flows": {}}}
|
57
|
+
|
58
|
+
for flow_name, flow in self.oauth2_config.flows.items():
|
59
|
+
flow_config = {}
|
60
|
+
if flow.authorizationUrl:
|
61
|
+
flow_config["authorizationUrl"] = flow.authorizationUrl
|
62
|
+
if flow.tokenUrl:
|
63
|
+
flow_config["tokenUrl"] = flow.tokenUrl
|
64
|
+
if flow.refreshUrl:
|
65
|
+
flow_config["refreshUrl"] = flow.refreshUrl
|
66
|
+
flow_config["scopes"] = flow.scopes
|
67
|
+
security_schemes["oauth2"]["flows"][flow_name] = flow_config
|
68
|
+
|
69
|
+
return security_schemes
|
70
|
+
|
71
|
+
def get_openapi_schema(self) -> Dict:
|
72
|
+
schema = {
|
73
|
+
"openapi": "3.0.3",
|
74
|
+
"info": self.info.model_dump(),
|
75
|
+
"components": {"securitySchemes": self.get_security_schemes()},
|
76
|
+
"security": [{"oauth2": []}] if self.oauth2_config else [],
|
77
|
+
}
|
78
|
+
return schema
|
Binary file
|
hypern/hypern.pyi
CHANGED
hypern/openapi/schemas.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
from __future__ import annotations
|
3
3
|
|
4
4
|
from hypern.hypern import BaseSchemaGenerator, Route as InternalRoute
|
5
|
+
from hypern.datastructures import SwaggerConfig
|
5
6
|
import typing
|
6
7
|
import orjson
|
7
8
|
|
@@ -13,8 +14,8 @@ class EndpointInfo(typing.NamedTuple):
|
|
13
14
|
|
14
15
|
|
15
16
|
class SchemaGenerator(BaseSchemaGenerator):
|
16
|
-
def __init__(self,
|
17
|
-
self.
|
17
|
+
def __init__(self, config: SwaggerConfig) -> None:
|
18
|
+
self.config = config
|
18
19
|
|
19
20
|
def get_endpoints(self, routes: list[InternalRoute]) -> list[EndpointInfo]:
|
20
21
|
"""
|
@@ -35,7 +36,7 @@ class SchemaGenerator(BaseSchemaGenerator):
|
|
35
36
|
return endpoints_info
|
36
37
|
|
37
38
|
def get_schema(self, app) -> dict[str, typing.Any]:
|
38
|
-
schema =
|
39
|
+
schema = self.config.get_openapi_schema()
|
39
40
|
schema.setdefault("paths", {})
|
40
41
|
for route in app.router.routes:
|
41
42
|
parsed = self.parse_docstring(route.doc)
|
hypern/routing/parser.py
CHANGED
@@ -8,7 +8,6 @@ import orjson
|
|
8
8
|
from pydantic import BaseModel, ValidationError
|
9
9
|
from pydash import get
|
10
10
|
|
11
|
-
from hypern.auth.authorization import Authorization
|
12
11
|
from hypern.exceptions import BadRequestException
|
13
12
|
from hypern.exceptions import ValidationException
|
14
13
|
from hypern.hypern import Request
|
@@ -84,11 +83,6 @@ class InputHandler:
|
|
84
83
|
kwargs[name] = await self.parse_pydantic_model(name, ptype)
|
85
84
|
continue
|
86
85
|
|
87
|
-
# Handle Authorization
|
88
|
-
if isinstance(ptype, type) and issubclass(ptype, Authorization):
|
89
|
-
kwargs[name] = await ptype().validate(self.request)
|
90
|
-
continue
|
91
|
-
|
92
86
|
# Handle special parameters
|
93
87
|
special_value = await self.handle_special_params(name)
|
94
88
|
if special_value is not None:
|
hypern/routing/route.py
CHANGED
@@ -8,8 +8,6 @@ import yaml # type: ignore
|
|
8
8
|
from pydantic import BaseModel
|
9
9
|
from pydantic.fields import FieldInfo
|
10
10
|
|
11
|
-
from hypern.auth.authorization import Authorization
|
12
|
-
|
13
11
|
from hypern.enum import HTTPMethod
|
14
12
|
from hypern.hypern import FunctionInfo, Request
|
15
13
|
|
@@ -176,11 +174,6 @@ class Route:
|
|
176
174
|
}
|
177
175
|
self.functional_handlers = []
|
178
176
|
|
179
|
-
def _process_authorization(self, item: type, docs: Dict) -> None:
|
180
|
-
if isinstance(item, type) and issubclass(item, Authorization):
|
181
|
-
auth_obj = item()
|
182
|
-
docs["security"] = [{auth_obj.name: []}]
|
183
|
-
|
184
177
|
def _process_model_params(self, key: str, item: type, docs: Dict) -> None:
|
185
178
|
if not (isinstance(item, type) and issubclass(item, BaseModel)):
|
186
179
|
return
|
@@ -210,7 +203,6 @@ class Route:
|
|
210
203
|
_docs: Dict = {"summary": summary, "tags": self.tags, "responses": [], "name": self.name}
|
211
204
|
|
212
205
|
for key, item in _inputs_dict.items():
|
213
|
-
self._process_authorization(item, _docs)
|
214
206
|
self._process_model_params(key, item, _docs)
|
215
207
|
|
216
208
|
self._process_response(signature.return_annotation, _docs)
|
@@ -1,24 +1,24 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hypern
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.15
|
4
4
|
Classifier: Programming Language :: Rust
|
5
5
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
6
6
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
7
|
-
Requires-Dist: sqlalchemy[asyncio]
|
8
|
-
Requires-Dist: pyjwt
|
9
|
-
Requires-Dist: pydash
|
10
|
-
Requires-Dist: sentry-sdk
|
11
|
-
Requires-Dist: celery
|
12
|
-
Requires-Dist: psycopg
|
13
|
-
Requires-Dist: pyyaml
|
14
|
-
Requires-Dist: orjson
|
15
|
-
Requires-Dist: multiprocess
|
16
|
-
Requires-Dist: uvloop
|
17
|
-
Requires-Dist: watchdog
|
18
|
-
Requires-Dist: psutil
|
19
|
-
Requires-Dist: msgpack
|
20
|
-
Requires-Dist: redis
|
21
|
-
Requires-Dist: pydantic
|
7
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.31
|
8
|
+
Requires-Dist: pyjwt==2.8.0
|
9
|
+
Requires-Dist: pydash==8.0.3
|
10
|
+
Requires-Dist: sentry-sdk==2.11.0
|
11
|
+
Requires-Dist: celery==5.4.0
|
12
|
+
Requires-Dist: psycopg==3.2.3
|
13
|
+
Requires-Dist: pyyaml==6.0.2
|
14
|
+
Requires-Dist: orjson==3.10.11
|
15
|
+
Requires-Dist: multiprocess==0.70.17
|
16
|
+
Requires-Dist: uvloop==0.21.0 ; platform_machine != 'armv7l' and platform_python_implementation == 'CPython' and sys_platform != 'win32'
|
17
|
+
Requires-Dist: watchdog==6.0.0
|
18
|
+
Requires-Dist: psutil==6.1.0
|
19
|
+
Requires-Dist: msgpack==1.1.0
|
20
|
+
Requires-Dist: redis==5.2.1
|
21
|
+
Requires-Dist: pydantic==2.10.4
|
22
22
|
License-File: LICENSE
|
23
23
|
Summary: A Fast Async Python backend with a Rust runtime.
|
24
24
|
Author-email: Martin Dang <vannghiem848@gmail.com>
|
@@ -1,71 +1,74 @@
|
|
1
|
-
hypern-0.3.
|
2
|
-
hypern-0.3.
|
3
|
-
hypern-0.3.
|
4
|
-
hypern/
|
5
|
-
hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1
|
+
hypern-0.3.15.dist-info/METADATA,sha256=jwBlqCAtibNdltKg6m0bYu7lywh8IeS3JD_JZT2hvdY,3992
|
2
|
+
hypern-0.3.15.dist-info/WHEEL,sha256=Vmeos7Nl4a2Pb7_0k0H15Q_fymkIK3XQKvyS1-Y7doA,127
|
3
|
+
hypern-0.3.15.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
|
4
|
+
hypern/hypern.pyi,sha256=1o1ONZ4utz78DB4yi_vas_BGqIveJPYVKCSezntvEgY,8743
|
6
5
|
hypern/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
hypern/
|
8
|
-
hypern/
|
9
|
-
hypern/gateway/gateway.py,sha256=rAZrS9db55tQGUfEfVNIKw6EetBdHAcSXyrC7rLfCZ8,1434
|
10
|
-
hypern/gateway/aggregator.py,sha256=Z4LnsDlVDtlPlhsSKu8jCD0UsbztXOLu6UAVtkgJwQk,1100
|
11
|
-
hypern/gateway/__init__.py,sha256=4wyCK49W_sTBCh0hkTdEli6kdRUFu9UBxncV6EXBxwA,229
|
12
|
-
hypern/routing/queue.py,sha256=Yus-49N4xc7O5S3YYxqL0muFLypu_Zgd0u2SADFh-Uk,7001
|
6
|
+
hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
hypern/enum.py,sha256=6sLKuH5fQwc-XpSjf_Z9-lQpi3Id5xqAnl3ihvLF-8Y,551
|
13
8
|
hypern/routing/endpoint.py,sha256=AWLHLQNlSGR8IGU6xM0RP-1kP06OJQzqpbXKSiZEzEo,996
|
14
|
-
hypern/routing/
|
15
|
-
hypern/routing/route.py,sha256=Xbws-l5FooG9s_BLgmjqGfgJvapuMhrHYPN8qPb6iag,10196
|
16
|
-
hypern/routing/parser.py,sha256=iYaTAcZCeHgx2QpQSbQ7kQPhDOJQw5DJA6HFk2bqlhM,3320
|
9
|
+
hypern/routing/queue.py,sha256=Yus-49N4xc7O5S3YYxqL0muFLypu_Zgd0u2SADFh-Uk,7001
|
17
10
|
hypern/routing/__init__.py,sha256=FvmUQlSraZ91q9AFGkgj3ELIep1jiKZLBCDrXIVf5DI,157
|
11
|
+
hypern/routing/route.py,sha256=DFBTq_S_Uwjl4DaoXH6cQ_VwqXEw-cEuZp5-4AcL_d8,9865
|
12
|
+
hypern/routing/parser.py,sha256=fnrsrZrxODhYNLuGP2WGDJyexve_gmTyuBz3qZCnzeU,3062
|
13
|
+
hypern/routing/dispatcher.py,sha256=8_JuxyyOMiCqY3WsqcjSzUTpYjIGbvzGtI8j9T-fIkA,2391
|
18
14
|
hypern/args_parser.py,sha256=hRlZe6VOZUutynVPXzCS8Mpn_Qp36MDDV0hFLNjM5YM,2149
|
19
|
-
hypern/datastructures.py,sha256=q0jWNQBDVcwxIeD9-s9N266rA7aIYn6nAtN4z0Neogk,616
|
20
|
-
hypern/database/sqlalchemy/repository.py,sha256=YShEl1DqRXtYwNnn1F3YVfXX-TEdoNRjDEWIO_3Lu2s,9226
|
21
|
-
hypern/database/sqlalchemy/config.py,sha256=AyeDJnWtq42NFLX65T0w04yhX7l9x8t6lXFq8U4WgfE,2580
|
22
|
-
hypern/database/sqlalchemy/__init__.py,sha256=U_9q6L3V7VIRN-neeN5mVb1z6wKf7_GjWptgUl8-xxI,150
|
23
|
-
hypern/database/sqlx/query.py,sha256=_SRoXXXdVZ_kRLcvrYCtxmIbpb1GE3BpBg4rseHhctc,32442
|
24
|
-
hypern/database/sqlx/migrate.py,sha256=gHoZFUPop7OGp_cVic8pKiVnnV1-j2oUAJ9lXVfBBAA,9479
|
25
|
-
hypern/database/sqlx/model.py,sha256=5liN9IP6cKZhW2SZqQE5ynFNCPVkGL9_xoyPu5PAyjQ,3927
|
26
|
-
hypern/database/sqlx/__init__.py,sha256=1GJLdJfh1Dgy6o1tyl6Aus431rhrX4shhE53M9FLQl0,609
|
27
|
-
hypern/database/sqlx/field.py,sha256=C7vxo6VvCeOWxG3-GFrwe23xC4AiZ3fGqOzZTDbkC8c,8875
|
28
|
-
hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
|
-
hypern/application.py,sha256=TlMbzJc3F0ZTymAzA-hOtxXYmEuhGeckB0iIirYBxnI,17595
|
30
15
|
hypern/i18n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
-
hypern/
|
32
|
-
hypern/
|
16
|
+
hypern/worker.py,sha256=_m0NV-Srn4NGi65UciOOg3t4Bk6wGm0PMG4_1EYi6Zk,9487
|
17
|
+
hypern/reload.py,sha256=Y2pjHHh8Zv0z-pRkBPLezKiowRblb1ZJ7yI_oE55D4U,1523
|
18
|
+
hypern/application.py,sha256=4Ba-nnyAT0Ri0RY0OQz6ynedcO1xOWKdbjKgsTgCyis,13279
|
33
19
|
hypern/logging/__init__.py,sha256=lzYSz0382eIM3CvP0sZ6RbEEwYZwfeJEJh9cxQA6Rws,49
|
34
|
-
hypern/
|
20
|
+
hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
|
21
|
+
hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
+
hypern/caching/backend.py,sha256=Tj66YSepGUvpXrwC04gSdJzs45IepHA2hNlMtnRVB6c,798
|
23
|
+
hypern/caching/redis_backend.py,sha256=nRkAq07B248iFljn9TxE4tadYUeM8RqqERZWzEpfk7E,5767
|
24
|
+
hypern/caching/strategies.py,sha256=VU0FpYmIK6rEjjJSwRXPrprYdo0d2u1s9OxB3OAvs3g,7080
|
25
|
+
hypern/caching/__init__.py,sha256=I7X3bmdEHeHs80kjAI1s0mMlVD7RKmw9I-QupaTAIWo,346
|
26
|
+
hypern/config.py,sha256=Ksn2LnHU0yhtGUjnac9bNjqtxl7IcPKmMdbDfZYm7Jo,7911
|
27
|
+
hypern/processpool.py,sha256=N7KFG2ZJm-YlF-QzfUfQsorWsV3yav_HsyDLVWDGEJk,3623
|
28
|
+
hypern/__init__.py,sha256=LsEtm_FRdyAx0Eh51hjPXr_SH9BCyyIzNeBGTN76rRM,778
|
29
|
+
hypern/exceptions/http.py,sha256=N98kHaQtH4x9EW6Gavrcr-Ll_-HDvsDSaRAX1sNuN4A,3150
|
35
30
|
hypern/exceptions/base.py,sha256=_tt42Tuy_7oXR-THhJ00lZFsCJMKWbArJyTlF-kcgH4,1955
|
36
|
-
hypern/exceptions/
|
31
|
+
hypern/exceptions/errors.py,sha256=mt6ZXUGHFZ_FfyP7sZFj4XT6amb5G-1Fa_26rH7BSWc,842
|
37
32
|
hypern/exceptions/__init__.py,sha256=t4GhxGHjOPgPQ34f0MycMjoRGw5u3TRb3OcTDYc4Orw,936
|
33
|
+
hypern/exceptions/common.py,sha256=p9cx3PC6Azn0WAz7jCH02DEoLRLCCvKqNrL-dGhMGSQ,215
|
38
34
|
hypern/exceptions/formatters.py,sha256=51krRQIUq3uvwvcQm81mYPifdp2r2ckwC98pXI5v_P8,2330
|
39
|
-
hypern/
|
40
|
-
hypern/ws/channel.py,sha256=TWaqowshz3WZRdg7ApBdFtVAlZW0OsVqoOHoFtXaZrk,3103
|
41
|
-
hypern/ws/route.py,sha256=8YPTf1fsF46oCyqoXePC3mEbhjNVFDp8rqyWSsBHhBA,777
|
42
|
-
hypern/ws/room.py,sha256=9u6gLq1WY4hn9_yEniavaY0yetFbQzgya_g6VPN-cgg,2522
|
43
|
-
hypern/ws/heartbeat.py,sha256=PIrYWnQn8VxQjfDXDmtMymMl-wN5MQ_Q6oHfAjPWznU,2787
|
44
|
-
hypern/ws/__init__.py,sha256=iUYERiHxs7HCmHj7CS5iG2XewKAJgW7w8kqxSORu_N8,127
|
45
|
-
hypern/config.py,sha256=Ksn2LnHU0yhtGUjnac9bNjqtxl7IcPKmMdbDfZYm7Jo,7911
|
46
|
-
hypern/openapi/schemas.py,sha256=Hg8G4aPZ1xXJTKFWhx8BgwRsDt2yw-v0N6LVjJ_qBHU,1547
|
47
|
-
hypern/openapi/swagger.py,sha256=E5fHYUfFa77zQsCyQGf_vnqJVpl4_KI5qsKFHdgJEdw,61
|
48
|
-
hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
|
49
|
-
hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
|
-
hypern/enum.py,sha256=6sLKuH5fQwc-XpSjf_Z9-lQpi3Id5xqAnl3ihvLF-8Y,551
|
51
|
-
hypern/middleware/limit.py,sha256=oWNt-XqYdORJuJMgg8pLYoEpHVm1cZBOPatxk8g7Nao,8075
|
52
|
-
hypern/middleware/cache.py,sha256=b4hRh1smFwhJE789hZ0p4TlkQ8ZjYR-7fXg9rI7uvbc,7406
|
35
|
+
hypern/datastructures.py,sha256=OqJSklqNWb06jY_x7bJSIRzN6Cj-OewVUXqwhsX8AHY,2251
|
53
36
|
hypern/middleware/compress.py,sha256=2eyxkYMgmsL6klbcTqr7WK0rFTo0grU0ZKQF15pVUBI,3041
|
54
37
|
hypern/middleware/base.py,sha256=IXmEe7x_X5YykBsxTpko6ApsvNmVqfZ7IHBgJSSEWnY,356
|
55
38
|
hypern/middleware/cors.py,sha256=q8Ts_znqApdUJYSJyLlRIbYKxxTQy6WNnJD6Kqbl32I,1759
|
39
|
+
hypern/middleware/i18n.py,sha256=s82nQo6kKClZ0s3G3jsy87VRfwxpBDbASB_ErjRL3O0,15
|
40
|
+
hypern/middleware/limit.py,sha256=oWNt-XqYdORJuJMgg8pLYoEpHVm1cZBOPatxk8g7Nao,8075
|
41
|
+
hypern/middleware/cache.py,sha256=b4hRh1smFwhJE789hZ0p4TlkQ8ZjYR-7fXg9rI7uvbc,7406
|
56
42
|
hypern/middleware/__init__.py,sha256=sPmefKAy8-XeSg6BhkZBjqV8zgreeNLxikyyM6aDFT8,476
|
57
43
|
hypern/middleware/security.py,sha256=hPYsilqhF9mRCX7DzOQw4AKh0y5k5FL0cM_zQdb9tiA,7491
|
58
|
-
hypern/
|
59
|
-
hypern/
|
60
|
-
hypern/
|
61
|
-
hypern/
|
62
|
-
hypern/
|
63
|
-
hypern/
|
64
|
-
hypern/
|
65
|
-
hypern/
|
66
|
-
hypern/
|
67
|
-
hypern/
|
44
|
+
hypern/database/sqlx/field.py,sha256=C7vxo6VvCeOWxG3-GFrwe23xC4AiZ3fGqOzZTDbkC8c,8875
|
45
|
+
hypern/database/sqlx/model.py,sha256=5liN9IP6cKZhW2SZqQE5ynFNCPVkGL9_xoyPu5PAyjQ,3927
|
46
|
+
hypern/database/sqlx/query.py,sha256=_SRoXXXdVZ_kRLcvrYCtxmIbpb1GE3BpBg4rseHhctc,32442
|
47
|
+
hypern/database/sqlx/__init__.py,sha256=1GJLdJfh1Dgy6o1tyl6Aus431rhrX4shhE53M9FLQl0,609
|
48
|
+
hypern/database/sqlx/migrate.py,sha256=gHoZFUPop7OGp_cVic8pKiVnnV1-j2oUAJ9lXVfBBAA,9479
|
49
|
+
hypern/database/sqlalchemy/repository.py,sha256=YShEl1DqRXtYwNnn1F3YVfXX-TEdoNRjDEWIO_3Lu2s,9226
|
50
|
+
hypern/database/sqlalchemy/config.py,sha256=AyeDJnWtq42NFLX65T0w04yhX7l9x8t6lXFq8U4WgfE,2580
|
51
|
+
hypern/database/sqlalchemy/__init__.py,sha256=U_9q6L3V7VIRN-neeN5mVb1z6wKf7_GjWptgUl8-xxI,150
|
52
|
+
hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
+
hypern/auth/decorators.py,sha256=GE6301SA3E-jbIOUWilN4qQItEAhsOxuuO5DiODekaM,1683
|
54
|
+
hypern/auth/middleware.py,sha256=fxzam9puG22m8GfPLUGl1PH20CXD8CMXWuD070VCjVw,1004
|
55
|
+
hypern/auth/jwt.py,sha256=0WWGvx4SGxBjwVLZuJHu-VBBtGTDsYzFrC6qblTpA8M,1382
|
56
|
+
hypern/auth/__init__.py,sha256=jkZdBU_MPOlY2telFamf42JxvAyiLS6rZEY5bMfgFIQ,210
|
57
|
+
hypern/auth/providers.py,sha256=lgpsELn2FjkYnwiJ5NusCqs8j0DmT8wGQOuwh0AC0xM,1144
|
58
|
+
hypern/openapi/swagger.py,sha256=E5fHYUfFa77zQsCyQGf_vnqJVpl4_KI5qsKFHdgJEdw,61
|
59
|
+
hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
|
60
|
+
hypern/openapi/schemas.py,sha256=Vln43RVQrjdzTHQrgO8kx28K_YNUygClEHs0VLDXl_0,1582
|
61
|
+
hypern/ws/heartbeat.py,sha256=PIrYWnQn8VxQjfDXDmtMymMl-wN5MQ_Q6oHfAjPWznU,2787
|
62
|
+
hypern/ws/channel.py,sha256=TWaqowshz3WZRdg7ApBdFtVAlZW0OsVqoOHoFtXaZrk,3103
|
63
|
+
hypern/ws/__init__.py,sha256=iUYERiHxs7HCmHj7CS5iG2XewKAJgW7w8kqxSORu_N8,127
|
64
|
+
hypern/ws/room.py,sha256=9u6gLq1WY4hn9_yEniavaY0yetFbQzgya_g6VPN-cgg,2522
|
65
|
+
hypern/ws/route.py,sha256=8YPTf1fsF46oCyqoXePC3mEbhjNVFDp8rqyWSsBHhBA,777
|
66
|
+
hypern/gateway/gateway.py,sha256=rAZrS9db55tQGUfEfVNIKw6EetBdHAcSXyrC7rLfCZ8,1434
|
67
|
+
hypern/gateway/proxy.py,sha256=cgMFJ6znUMWRDgPgnRz7HmPT6UUY6Z09-8HAxkCWGgk,2403
|
68
|
+
hypern/gateway/aggregator.py,sha256=Z4LnsDlVDtlPlhsSKu8jCD0UsbztXOLu6UAVtkgJwQk,1100
|
69
|
+
hypern/gateway/service.py,sha256=kxKTBZN0ZjuNEp8uwFldQWql-g1q1AECXUjKZsICdLg,1649
|
70
|
+
hypern/gateway/__init__.py,sha256=4wyCK49W_sTBCh0hkTdEli6kdRUFu9UBxncV6EXBxwA,229
|
68
71
|
hypern/response/response.py,sha256=qa-jmce1PpMezn0GRO6hR5SV0O-y8BspBAm6MdPcreQ,4699
|
69
72
|
hypern/response/__init__.py,sha256=9z99BDgASpG404GK8LGkOsXgac0wFwH_cQOTI5Ju-1U,223
|
70
|
-
hypern/hypern.cpython-311-s390x-linux-gnu.so,sha256=
|
71
|
-
hypern-0.3.
|
73
|
+
hypern/hypern.cpython-311-s390x-linux-gnu.so,sha256=Gv6Ef6P9GzMWz_CjRHvhQ9Dl0ZpYn2fzhkZt9XW-MSo,14842848
|
74
|
+
hypern-0.3.15.dist-info/RECORD,,
|
hypern/auth/authorization.py
DELETED
File without changes
|