hypern 0.3.4__cp312-cp312-win32.whl → 0.3.6__cp312-cp312-win32.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.
Files changed (40) hide show
  1. hypern/{db → database}/sql/query.py +1 -1
  2. hypern/exceptions/__init__.py +34 -0
  3. hypern/exceptions/base.py +62 -0
  4. hypern/exceptions/common.py +12 -0
  5. hypern/exceptions/errors.py +15 -0
  6. hypern/exceptions/formatters.py +56 -0
  7. hypern/exceptions/http.py +76 -0
  8. hypern/hypern.cp312-win32.pyd +0 -0
  9. hypern/middleware/security.py +6 -6
  10. hypern/processpool.py +24 -6
  11. hypern/response/response.py +8 -0
  12. hypern/routing/dispatcher.py +4 -5
  13. hypern/routing/parser.py +11 -13
  14. {hypern-0.3.4.dist-info → hypern-0.3.6.dist-info}/METADATA +2 -1
  15. {hypern-0.3.4.dist-info → hypern-0.3.6.dist-info}/RECORD +39 -34
  16. hypern/exceptions.py +0 -107
  17. /hypern/{db → database}/__init__.py +0 -0
  18. /hypern/{db → database}/addons/__init__.py +0 -0
  19. /hypern/{db → database}/addons/sqlalchemy/__init__.py +0 -0
  20. /hypern/{db → database}/addons/sqlalchemy/fields/__init__.py +0 -0
  21. /hypern/{db → database}/addons/sqlalchemy/fields/color.py +0 -0
  22. /hypern/{db → database}/addons/sqlalchemy/fields/daterange.py +0 -0
  23. /hypern/{db → database}/addons/sqlalchemy/fields/datetime.py +0 -0
  24. /hypern/{db → database}/addons/sqlalchemy/fields/encrypted.py +0 -0
  25. /hypern/{db → database}/addons/sqlalchemy/fields/password.py +0 -0
  26. /hypern/{db → database}/addons/sqlalchemy/fields/ts_vector.py +0 -0
  27. /hypern/{db → database}/addons/sqlalchemy/fields/unicode.py +0 -0
  28. /hypern/{db → database}/addons/sqlalchemy/repository.py +0 -0
  29. /hypern/{db → database}/nosql/__init__.py +0 -0
  30. /hypern/{db → database}/nosql/addons/__init__.py +0 -0
  31. /hypern/{db → database}/nosql/addons/color.py +0 -0
  32. /hypern/{db → database}/nosql/addons/daterange.py +0 -0
  33. /hypern/{db → database}/nosql/addons/encrypted.py +0 -0
  34. /hypern/{db → database}/nosql/addons/password.py +0 -0
  35. /hypern/{db → database}/nosql/addons/unicode.py +0 -0
  36. /hypern/{db → database}/sql/__init__.py +0 -0
  37. /hypern/{db → database}/sql/field.py +0 -0
  38. /hypern/{db → database}/sql/model.py +0 -0
  39. {hypern-0.3.4.dist-info → hypern-0.3.6.dist-info}/WHEEL +0 -0
  40. {hypern-0.3.4.dist-info → hypern-0.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  from enum import Enum
2
2
  from typing import Any, Dict, List, Tuple, Union
3
- from hypern.db.sql.field import ForeignKey
3
+ from hypern.database.sql.field import ForeignKey
4
4
 
5
5
 
6
6
  class JoinType(Enum):
@@ -0,0 +1,34 @@
1
+ from .base import HTTPException, ResponseFormatter, HypernError
2
+ from .errors import ErrorDefinitions
3
+ from .formatters import SimpleFormatter, DetailedFormatter, LocalizedFormatter
4
+ from .http import (
5
+ BadRequestException,
6
+ UnauthorizedException,
7
+ ForbiddenException,
8
+ NotFoundException,
9
+ ValidationException,
10
+ InternalServerException,
11
+ RateLimitException,
12
+ )
13
+
14
+ from .common import DBFieldValidationError, InvalidPortNumber, OutOfScopeApplicationException
15
+
16
+ __all__ = [
17
+ "HTTPException",
18
+ "ResponseFormatter",
19
+ "HypernError",
20
+ "ErrorDefinitions",
21
+ "SimpleFormatter",
22
+ "DetailedFormatter",
23
+ "LocalizedFormatter",
24
+ "BadRequestException",
25
+ "UnauthorizedException",
26
+ "ForbiddenException",
27
+ "NotFoundException",
28
+ "ValidationException",
29
+ "InternalServerException",
30
+ "RateLimitException",
31
+ "DBFieldValidationError",
32
+ "InvalidPortNumber",
33
+ "OutOfScopeApplicationException",
34
+ ]
@@ -0,0 +1,62 @@
1
+ import uuid
2
+ from abc import ABC, abstractmethod
3
+ from datetime import datetime, timezone
4
+ from http import HTTPStatus
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ class ResponseFormatter(ABC):
9
+ @abstractmethod
10
+ def format_error(self, exception: "HTTPException") -> Dict[str, Any]:
11
+ """Format exception into response dictionary"""
12
+ pass
13
+
14
+
15
+ class DefaultFormatter(ResponseFormatter):
16
+ def format_error(self, exception: "HTTPException") -> Dict[str, Any]:
17
+ return {
18
+ "error": {
19
+ "code": exception.error.code if exception.error else "UNKNOWN_ERROR",
20
+ "message": exception.error.message if exception.error else "Unknown error occurred",
21
+ "details": exception.details or {},
22
+ "timestamp": datetime.now(tz=timezone.utc).isoformat(),
23
+ "request_id": str(uuid.uuid4()),
24
+ },
25
+ "status": exception.status_code,
26
+ }
27
+
28
+
29
+ class HypernError:
30
+ """Base error definition"""
31
+
32
+ def __init__(self, message: str, code: str):
33
+ self.message = message
34
+ self.code = code
35
+
36
+
37
+ class HTTPException(Exception):
38
+ """Base HTTP exception"""
39
+
40
+ _formatter: ResponseFormatter = DefaultFormatter()
41
+
42
+ @classmethod
43
+ def set_formatter(cls, formatter: ResponseFormatter):
44
+ cls._formatter = formatter
45
+
46
+ def __init__(
47
+ self,
48
+ status_code: int = HTTPStatus.BAD_REQUEST,
49
+ error: Optional[HypernError] = None,
50
+ details: Optional[Dict[str, Any]] = None,
51
+ headers: Optional[Dict[str, str]] = None,
52
+ formatter: Optional[ResponseFormatter] = None,
53
+ ):
54
+ self.status_code = status_code
55
+ self.error = error
56
+ self.details = details or {}
57
+ self.headers = headers or {}
58
+ self._instance_formatter = formatter
59
+
60
+ def to_dict(self) -> Dict[str, Any]:
61
+ formatter = self._instance_formatter or self._formatter
62
+ return formatter.format_error(self)
@@ -0,0 +1,12 @@
1
+ class InvalidPortNumber(Exception):
2
+ pass
3
+
4
+
5
+ class OutOfScopeApplicationException(Exception):
6
+ pass
7
+
8
+
9
+ class DBFieldValidationError(ValueError):
10
+ """Custom exception for field validation errors."""
11
+
12
+ pass
@@ -0,0 +1,15 @@
1
+ from .base import HypernError
2
+
3
+
4
+ class ErrorDefinitions:
5
+ """Standard error definitions"""
6
+
7
+ BAD_REQUEST = HypernError(message="Bad request", code="BAD_REQUEST")
8
+ UNAUTHORIZED = HypernError(message="Unauthorized access", code="UNAUTHORIZED")
9
+ FORBIDDEN = HypernError(message="Access forbidden", code="FORBIDDEN")
10
+ NOT_FOUND = HypernError(message="Resource not found", code="NOT_FOUND")
11
+ METHOD_NOT_ALLOWED = HypernError(message="Method not allowed", code="METHOD_NOT_ALLOWED")
12
+ VALIDATION_ERROR = HypernError(message="Validation error", code="VALIDATION_ERROR")
13
+ INTERNAL_ERROR = HypernError(message="Internal server error", code="INTERNAL_SERVER_ERROR")
14
+ CONFLICT = HypernError(message="Resource conflict", code="CONFLICT")
15
+ TOO_MANY_REQUESTS = HypernError(message="Too many requests", code="TOO_MANY_REQUESTS")
@@ -0,0 +1,56 @@
1
+ import uuid
2
+ from datetime import datetime, timezone
3
+ from typing import Any, Dict
4
+
5
+ from .base import HTTPException, ResponseFormatter
6
+
7
+
8
+ class SimpleFormatter(ResponseFormatter):
9
+ def format_error(self, exception: HTTPException) -> Dict[str, Any]:
10
+ return {
11
+ "code": exception.error.code if exception.error else "UNKNOWN_ERROR",
12
+ "message": exception.error.message if exception.error else "Unknown error occurred",
13
+ }
14
+
15
+
16
+ class DetailedFormatter(ResponseFormatter):
17
+ def format_error(self, exception: HTTPException) -> Dict[str, Any]:
18
+ return {
19
+ "status": {"code": exception.status_code, "text": str(exception.status_code)},
20
+ "error": {
21
+ "type": exception.error.code if exception.error else "UNKNOWN_ERROR",
22
+ "message": exception.error.message if exception.error else "Unknown error occurred",
23
+ "details": exception.details or {},
24
+ "timestamp": datetime.now(timezone.utc).isoformat(),
25
+ },
26
+ "request": {"path": exception.path, "id": str(uuid.uuid4())},
27
+ }
28
+
29
+
30
+ class LocalizedFormatter(ResponseFormatter):
31
+ def __init__(self, language: str = "en"):
32
+ self.language = language
33
+ self.translations = {
34
+ "en": {
35
+ "BAD_REQUEST": "Bad request",
36
+ "VALIDATION_ERROR": "Validation error",
37
+ "NOT_FOUND": "Resource not found",
38
+ # Add more translations
39
+ },
40
+ "vi": {
41
+ "BAD_REQUEST": "Yêu cầu không hợp lệ",
42
+ "VALIDATION_ERROR": "Lỗi xác thực",
43
+ "NOT_FOUND": "Không tìm thấy tài nguyên",
44
+ # Add more translations
45
+ },
46
+ }
47
+
48
+ def format_error(self, exception: HTTPException) -> Dict[str, Any]:
49
+ error_code = exception.error.code if exception.error else "UNKNOWN_ERROR"
50
+ translated_message = self.translations.get(self.language, {}).get(error_code, exception.error.message if exception.error else "Unknown error occurred")
51
+
52
+ return {
53
+ "error": {"code": error_code, "message": translated_message, "details": exception.details or {}},
54
+ "status": exception.status_code,
55
+ "timestamp": datetime.now(tz=timezone.utc).isoformat(),
56
+ }
@@ -0,0 +1,76 @@
1
+ from http import HTTPStatus
2
+ from typing import Any, Dict, Optional
3
+
4
+ from .base import HTTPException, ResponseFormatter, HypernError
5
+ from .errors import ErrorDefinitions
6
+
7
+
8
+ class BadRequestException(HTTPException):
9
+ def __init__(
10
+ self,
11
+ error: Optional[HypernError] = ErrorDefinitions.BAD_REQUEST,
12
+ details: Optional[Dict[str, Any]] = None,
13
+ headers: Optional[Dict[str, str]] = None,
14
+ formatter: Optional[ResponseFormatter] = None,
15
+ ):
16
+ super().__init__(status_code=HTTPStatus.BAD_REQUEST, error=error, details=details, headers=headers, formatter=formatter)
17
+
18
+
19
+ class UnauthorizedException(HTTPException):
20
+ def __init__(
21
+ self,
22
+ error: Optional[HypernError] = ErrorDefinitions.UNAUTHORIZED,
23
+ details: Optional[Dict[str, Any]] = None,
24
+ headers: Optional[Dict[str, str]] = None,
25
+ formatter: Optional[ResponseFormatter] = None,
26
+ ):
27
+ super().__init__(status_code=HTTPStatus.UNAUTHORIZED, error=error, details=details, headers=headers, formatter=formatter)
28
+
29
+
30
+ class ForbiddenException(HTTPException):
31
+ def __init__(
32
+ self,
33
+ error: Optional[HypernError] = ErrorDefinitions.FORBIDDEN,
34
+ details: Optional[Dict[str, Any]] = None,
35
+ headers: Optional[Dict[str, str]] = None,
36
+ formatter: Optional[ResponseFormatter] = None,
37
+ ):
38
+ super().__init__(status_code=HTTPStatus.FORBIDDEN, error=error, details=details, headers=headers, formatter=formatter)
39
+
40
+
41
+ class NotFoundException(HTTPException):
42
+ def __init__(
43
+ self,
44
+ error: Optional[HypernError] = ErrorDefinitions.NOT_FOUND,
45
+ details: Optional[Dict[str, Any]] = None,
46
+ headers: Optional[Dict[str, str]] = None,
47
+ formatter: Optional[ResponseFormatter] = None,
48
+ ):
49
+ super().__init__(status_code=HTTPStatus.NOT_FOUND, error=error, details=details, headers=headers, formatter=formatter)
50
+
51
+
52
+ class ValidationException(HTTPException):
53
+ def __init__(self, details: Optional[Dict[str, Any]] = None, headers: Optional[Dict[str, str]] = None, formatter: Optional[ResponseFormatter] = None):
54
+ super().__init__(status_code=HTTPStatus.BAD_REQUEST, error=ErrorDefinitions.VALIDATION_ERROR, details=details, headers=headers, formatter=formatter)
55
+
56
+
57
+ class InternalServerException(HTTPException):
58
+ def __init__(
59
+ self,
60
+ error: Optional[HypernError] = ErrorDefinitions.INTERNAL_ERROR,
61
+ details: Optional[Dict[str, Any]] = None,
62
+ headers: Optional[Dict[str, str]] = None,
63
+ formatter: Optional[ResponseFormatter] = None,
64
+ ):
65
+ super().__init__(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, error=error, details=details, headers=headers, formatter=formatter)
66
+
67
+
68
+ class RateLimitException(HTTPException):
69
+ def __init__(self, retry_after: int, details: Optional[Dict[str, Any]] = None, formatter: Optional[ResponseFormatter] = None):
70
+ super().__init__(
71
+ status_code=HTTPStatus.TOO_MANY_REQUESTS,
72
+ error=ErrorDefinitions.TOO_MANY_REQUESTS,
73
+ details=details,
74
+ headers={"Retry-After": str(retry_after)},
75
+ formatter=formatter,
76
+ )
Binary file
@@ -9,7 +9,7 @@ from typing import Any, Dict, List, Optional
9
9
 
10
10
  import jwt
11
11
 
12
- from hypern.exceptions import Forbidden, Unauthorized
12
+ from hypern.exceptions import ForbiddenException, UnauthorizedException
13
13
  from hypern.hypern import Request, Response
14
14
  from .base import Middleware, MiddlewareConfig
15
15
 
@@ -91,9 +91,9 @@ class SecurityMiddleware(Middleware):
91
91
  payload = jwt.decode(token, self.secur_config.jwt_secret, algorithms=[self.secur_config.jwt_algorithm])
92
92
  return payload
93
93
  except jwt.ExpiredSignatureError:
94
- raise Unauthorized("Token has expired")
94
+ raise UnauthorizedException(details={"message": "Token has expired"})
95
95
  except jwt.InvalidTokenError:
96
- raise Unauthorized("Invalid token")
96
+ raise UnauthorizedException(details={"message": "Invalid token"})
97
97
 
98
98
  def _generate_csrf_token(self, session_id: str) -> str:
99
99
  """Generate a new CSRF token"""
@@ -155,18 +155,18 @@ class SecurityMiddleware(Middleware):
155
155
  if self.secur_config.jwt_auth:
156
156
  auth_header = request.headers.get("Authorization")
157
157
  if not auth_header or not auth_header.startswith("Bearer "):
158
- raise Unauthorized("Missing or invalid authorization header")
158
+ raise UnauthorizedException(details={"message": "Authorization header missing or invalid"})
159
159
  token = auth_header.split(" ")[1]
160
160
  try:
161
161
  request.user = self._verify_jwt_token(token)
162
- except Unauthorized as e:
162
+ except UnauthorizedException as e:
163
163
  return Response(status_code=401, description=str(e))
164
164
 
165
165
  # CSRF protection check
166
166
  if self.secur_config.csrf_protection and request.method in ["POST", "PUT", "DELETE", "PATCH"]:
167
167
  csrf_token = request.headers.get("X-CSRF-Token")
168
168
  if not csrf_token or not self._validate_csrf_token(csrf_token):
169
- raise Forbidden("CSRF token missing or invalid")
169
+ raise ForbiddenException(details={"message": "Invalid CSRF token"})
170
170
 
171
171
  return request
172
172
 
hypern/processpool.py CHANGED
@@ -3,7 +3,7 @@ import os
3
3
  import signal
4
4
  import sys
5
5
  from typing import List
6
-
6
+ from concurrent.futures import ThreadPoolExecutor
7
7
  from multiprocess import Process
8
8
  from watchdog.observers import Observer
9
9
 
@@ -76,7 +76,7 @@ def init_processpool(
76
76
  ) -> List[Process]:
77
77
  process_pool = []
78
78
 
79
- for _ in range(processes):
79
+ for i in range(processes):
80
80
  copied_socket = socket.try_clone()
81
81
  process = Process(
82
82
  target=spawn_process,
@@ -86,25 +86,43 @@ def init_processpool(
86
86
  workers,
87
87
  max_blocking_threads,
88
88
  ),
89
+ name=f"hypern-worker-{i}",
89
90
  )
91
+ process.daemon = True # This is important to avoid zombie processes
90
92
  process.start()
91
93
  process_pool.append(process)
92
94
 
93
95
  return process_pool
94
96
 
95
97
 
96
- def initialize_event_loop():
98
+ class OptimizedEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
99
+ def __init__(self, max_blocking_threads: int):
100
+ super().__init__()
101
+ self.max_blocking_threads = max_blocking_threads
102
+
103
+ def new_event_loop(self):
104
+ loop = super().new_event_loop()
105
+ # Optimize thread pool cho I/O operations
106
+ loop.set_default_executor(ThreadPoolExecutor(max_workers=self.max_blocking_threads, thread_name_prefix="hypern-io"))
107
+ return loop
108
+
109
+
110
+ def initialize_event_loop(max_blocking_threads: int = 100) -> asyncio.AbstractEventLoop:
97
111
  if sys.platform.startswith("win32") or sys.platform.startswith("linux-cross"):
98
112
  loop = asyncio.new_event_loop()
99
113
  asyncio.set_event_loop(loop)
100
- return loop
101
114
  else:
102
115
  import uvloop
103
116
 
104
117
  uvloop.install()
118
+
119
+ asyncio.set_event_loop_policy(OptimizedEventLoopPolicy(max_blocking_threads))
105
120
  loop = uvloop.new_event_loop()
106
121
  asyncio.set_event_loop(loop)
107
- return loop
122
+
123
+ loop.slow_callback_duration = 0.1 # Log warnings for slow callbacks
124
+ loop.set_debug(False) # Disable debug mode
125
+ return loop
108
126
 
109
127
 
110
128
  def spawn_process(
@@ -113,7 +131,7 @@ def spawn_process(
113
131
  workers: int,
114
132
  max_blocking_threads: int,
115
133
  ):
116
- loop = initialize_event_loop()
134
+ loop = initialize_event_loop(max_blocking_threads)
117
135
 
118
136
  try:
119
137
  server.start(socket, workers, max_blocking_threads)
@@ -4,6 +4,7 @@ import typing
4
4
  from urllib.parse import quote
5
5
  from hypern.hypern import Response as InternalResponse, Header
6
6
  import orjson
7
+ import msgpack
7
8
 
8
9
  from hypern.background import BackgroundTask, BackgroundTasks
9
10
 
@@ -132,3 +133,10 @@ class FileResponse(BaseResponse):
132
133
  self.raw_headers["content-disposition"] = f'attachment; filename="{filename}"'
133
134
  self.raw_headers.setdefault("content-type", "application/octet-stream")
134
135
  self.raw_headers.setdefault("content-length", str(len(content)))
136
+
137
+
138
+ @to_response
139
+ class BinaryResponse(BaseResponse):
140
+ def __init__(self, content: bytes):
141
+ super().__init__(status_code=200, media_type="application/x-msgpack", headers={"Content-Type": "application/x-msgpack"})
142
+ self.content = msgpack.packb(content)
@@ -10,7 +10,7 @@ import typing
10
10
  import orjson
11
11
  from pydantic import BaseModel
12
12
 
13
- from hypern.exceptions import BaseException
13
+ from hypern.exceptions import HTTPException
14
14
  from hypern.hypern import Request, Response
15
15
  from hypern.response import JSONResponse
16
16
 
@@ -56,10 +56,9 @@ async def dispatch(handler, request: Request, inject: typing.Dict[str, typing.An
56
56
 
57
57
  except Exception as e:
58
58
  _res: typing.Dict = {"message": "", "error_code": "UNKNOWN_ERROR"}
59
- if isinstance(e, BaseException):
60
- _res["error_code"] = e.error_code
61
- _res["message"] = e.msg
62
- _status = e.status
59
+ if isinstance(e, HTTPException):
60
+ _res = e.to_dict()
61
+ _status = e.status_code
63
62
  else:
64
63
  traceback.print_exc()
65
64
  _res["message"] = str(e)
hypern/routing/parser.py CHANGED
@@ -9,8 +9,8 @@ from pydantic import BaseModel, ValidationError
9
9
  from pydash import get
10
10
 
11
11
  from hypern.auth.authorization import Authorization
12
- from hypern.exceptions import BadRequest
13
- from hypern.exceptions import ValidationError as HypernValidationError
12
+ from hypern.exceptions import BadRequestException
13
+ from hypern.exceptions import ValidationException
14
14
  from hypern.hypern import Request
15
15
 
16
16
 
@@ -28,7 +28,7 @@ class ParamParser:
28
28
 
29
29
  parser = data_parsers.get(param_name)
30
30
  if not parser:
31
- raise BadRequest(msg="Backend Error: Invalid parameter type, must be query_params, path_params or form_data.")
31
+ raise BadRequestException(details={"message": f"Invalid parameter name: {param_name}"})
32
32
  return parser()
33
33
 
34
34
  def _parse_query_params(self) -> dict:
@@ -53,16 +53,14 @@ class InputHandler:
53
53
  return model_class(**data)
54
54
  except ValidationError as e:
55
55
  invalid_fields = orjson.loads(e.json())
56
- raise HypernValidationError(
57
- msg=orjson.dumps(
58
- [
59
- {
60
- "field": get(item, "loc")[0],
61
- "msg": get(item, "msg"),
62
- }
63
- for item in invalid_fields
64
- ]
65
- ).decode("utf-8"),
56
+ raise ValidationException(
57
+ details=[
58
+ {
59
+ "field": get(item, "loc")[0],
60
+ "msg": get(item, "msg"),
61
+ }
62
+ for item in invalid_fields
63
+ ]
66
64
  )
67
65
 
68
66
  async def handle_special_params(self, param_name: str) -> typing.Any:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypern
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -25,6 +25,7 @@ Requires-Dist: cryptography ==43.0.3
25
25
  Requires-Dist: watchdog ==6.0.0
26
26
  Requires-Dist: jsonschema ==4.23.0
27
27
  Requires-Dist: psutil ==6.1.0
28
+ Requires-Dist: msgpack ==1.1.0
28
29
  License-File: LICENSE
29
30
  Summary: A Fast Async Python backend with a Rust runtime.
30
31
  Author-email: Martin Dang <vannghiem848@gmail.com>
@@ -1,6 +1,6 @@
1
- hypern-0.3.4.dist-info/METADATA,sha256=wJ9_iA8bw0-Sc-a3AtzB0aCWhN4iPavHZjQfZgEpats,3819
2
- hypern-0.3.4.dist-info/WHEEL,sha256=SK_cql1gpDHx6aBV-LOSvGbTt4TUC8AJJOzjOP2tdpI,92
3
- hypern-0.3.4.dist-info/licenses/LICENSE,sha256=qbYKAIJLS6jYg5hYncKE7OtWmqOtpVTvKNkwOa0Iwwg,1328
1
+ hypern-0.3.6.dist-info/METADATA,sha256=NZSUrAbL7D7aleTF03qoRJiO2r8cQ7OQdwYlPu9hRoM,3850
2
+ hypern-0.3.6.dist-info/WHEEL,sha256=SK_cql1gpDHx6aBV-LOSvGbTt4TUC8AJJOzjOP2tdpI,92
3
+ hypern-0.3.6.dist-info/licenses/LICENSE,sha256=qbYKAIJLS6jYg5hYncKE7OtWmqOtpVTvKNkwOa0Iwwg,1328
4
4
  hypern/application.py,sha256=DCYFtU8e8NhQtmfaXbUfOxR2_Y3fEn-pzce9OOs6S4U,18396
5
5
  hypern/args_parser.py,sha256=zTfLfBoKBvYWxdPjabTfZsCtYF3La3PT0TD8dfLMeM4,2815
6
6
  hypern/auth/authorization.py,sha256=-NprZsI0np889ZN1fp-MiVFrPoMNzUtatBJaCMtkllM,32
@@ -13,32 +13,37 @@ hypern/caching/__init__.py,sha256=ODO7zMm4iFG8wcvrhKmukryG5wOTW0DnzFvNMfF57Cc,35
13
13
  hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  hypern/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  hypern/config.py,sha256=Jij9eGg5NgC8Un5Lw5i7ghuEMAfkVctdcoE4RaN5LTE,8157
16
+ hypern/database/addons/sqlalchemy/fields/color.py,sha256=Jj8q4lkT0ukKyjVyZjBx7fokGrX7AIJpKOGzwsBpfnU,480
17
+ hypern/database/addons/sqlalchemy/fields/daterange.py,sha256=qEfQN9c4jQdzeXNYKgQ4VIJ3Qc0HXHWRouzNF1se-RA,853
18
+ hypern/database/addons/sqlalchemy/fields/datetime.py,sha256=Bp2jMja2lb_b2WnzRnfbjXXTHBgBTyph1ECsItIwvvg,643
19
+ hypern/database/addons/sqlalchemy/fields/encrypted.py,sha256=pXsg4ImPpK-VkLDruKrv2gUtdp2kajQX7xDbRDxa-SI,1930
20
+ hypern/database/addons/sqlalchemy/fields/password.py,sha256=9pypORygWaINj3oiAOBRIOGgpuA0lcjPq4rh1pqJxq0,5789
21
+ hypern/database/addons/sqlalchemy/fields/ts_vector.py,sha256=bQyXYvQ1bAfFpYcS-sFwM7fU6L1lg9_7nGDRGp0CoUo,1361
22
+ hypern/database/addons/sqlalchemy/fields/unicode.py,sha256=rbqyHlsPUqRDWIjYQSRFF3zkHncnwxo0sdlzqUlcrUw,411
23
+ hypern/database/addons/sqlalchemy/fields/__init__.py,sha256=mLN_AvwgpSAbrWZvVHZuO7ff0gk1T_JbVwd5wug5nlw,359
24
+ hypern/database/addons/sqlalchemy/repository.py,sha256=ue6vWOTrnEPyDevlyh3v-7PU6GSfrZHYKrbXVuoS8UA,9516
25
+ hypern/database/addons/sqlalchemy/__init__.py,sha256=FuY78ubEwtifdQTVHhCrscYaAarlp2urgYBc_R77yt0,2766
26
+ hypern/database/addons/__init__.py,sha256=mdW0P0xvnK8htUk02ujvIaeHXl6w53JjrTS4ioNi1Bw,63
27
+ hypern/database/nosql/addons/color.py,sha256=bAGRuARCAYwZ1nO4jK0lzGYKmavTDtS34BxvrsetF74,446
28
+ hypern/database/nosql/addons/daterange.py,sha256=hGUSoVFqatNY-TB5wjZTq62iZpHpdsyRJIsHxsj1uDs,1192
29
+ hypern/database/nosql/addons/encrypted.py,sha256=B0M-uDqvZHVmIZcFdwcuC2MGsv0pGJFQ1lrOg8klR9U,1741
30
+ hypern/database/nosql/addons/password.py,sha256=jfZxvWFm6nV9EWpXq5Mj-jpqnl9QbokZj9WT14n7dKE,5035
31
+ hypern/database/nosql/addons/unicode.py,sha256=LaDpLfdoTcJuASPE-8fqOVD05H_uOx8gOdnyDn5Iu0c,268
32
+ hypern/database/nosql/addons/__init__.py,sha256=WEtPM8sPHilvga7zxwqvINeTkF0hdcfgPcAnHc4MASE,125
33
+ hypern/database/nosql/__init__.py,sha256=MH9YvlbRlbBCrQVNOdfTaK-hINwJxbJLmxwY9Mei7I8,644
34
+ hypern/database/sql/field.py,sha256=tSs8iaYjy-K6nplJJ-1X4OQddzW76cfBlx9xTrG_NbQ,20073
35
+ hypern/database/sql/model.py,sha256=BLRmOlmfn6ibedR9Bv_rHErSruudJ24B9-nDbRHqWm4,3913
36
+ hypern/database/sql/query.py,sha256=tQ7Wss2NAIqsAH0M-fT5m9DU_MsiBR0DcoyTbS_aatU,33335
37
+ hypern/database/sql/__init__.py,sha256=lCOGNTHaXNSJbuLLIOe2IWWNmX0MFQFPNCl2yytD2Xs,261
38
+ hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
39
  hypern/datastructures.py,sha256=zZGGSP07kPc9KJDf11hX5uYhAyRE-Ck5wezW5QtOVXw,897
17
- hypern/db/addons/sqlalchemy/fields/color.py,sha256=Jj8q4lkT0ukKyjVyZjBx7fokGrX7AIJpKOGzwsBpfnU,480
18
- hypern/db/addons/sqlalchemy/fields/daterange.py,sha256=qEfQN9c4jQdzeXNYKgQ4VIJ3Qc0HXHWRouzNF1se-RA,853
19
- hypern/db/addons/sqlalchemy/fields/datetime.py,sha256=Bp2jMja2lb_b2WnzRnfbjXXTHBgBTyph1ECsItIwvvg,643
20
- hypern/db/addons/sqlalchemy/fields/encrypted.py,sha256=pXsg4ImPpK-VkLDruKrv2gUtdp2kajQX7xDbRDxa-SI,1930
21
- hypern/db/addons/sqlalchemy/fields/password.py,sha256=9pypORygWaINj3oiAOBRIOGgpuA0lcjPq4rh1pqJxq0,5789
22
- hypern/db/addons/sqlalchemy/fields/ts_vector.py,sha256=bQyXYvQ1bAfFpYcS-sFwM7fU6L1lg9_7nGDRGp0CoUo,1361
23
- hypern/db/addons/sqlalchemy/fields/unicode.py,sha256=rbqyHlsPUqRDWIjYQSRFF3zkHncnwxo0sdlzqUlcrUw,411
24
- hypern/db/addons/sqlalchemy/fields/__init__.py,sha256=mLN_AvwgpSAbrWZvVHZuO7ff0gk1T_JbVwd5wug5nlw,359
25
- hypern/db/addons/sqlalchemy/repository.py,sha256=ue6vWOTrnEPyDevlyh3v-7PU6GSfrZHYKrbXVuoS8UA,9516
26
- hypern/db/addons/sqlalchemy/__init__.py,sha256=FuY78ubEwtifdQTVHhCrscYaAarlp2urgYBc_R77yt0,2766
27
- hypern/db/addons/__init__.py,sha256=mdW0P0xvnK8htUk02ujvIaeHXl6w53JjrTS4ioNi1Bw,63
28
- hypern/db/nosql/addons/color.py,sha256=bAGRuARCAYwZ1nO4jK0lzGYKmavTDtS34BxvrsetF74,446
29
- hypern/db/nosql/addons/daterange.py,sha256=hGUSoVFqatNY-TB5wjZTq62iZpHpdsyRJIsHxsj1uDs,1192
30
- hypern/db/nosql/addons/encrypted.py,sha256=B0M-uDqvZHVmIZcFdwcuC2MGsv0pGJFQ1lrOg8klR9U,1741
31
- hypern/db/nosql/addons/password.py,sha256=jfZxvWFm6nV9EWpXq5Mj-jpqnl9QbokZj9WT14n7dKE,5035
32
- hypern/db/nosql/addons/unicode.py,sha256=LaDpLfdoTcJuASPE-8fqOVD05H_uOx8gOdnyDn5Iu0c,268
33
- hypern/db/nosql/addons/__init__.py,sha256=WEtPM8sPHilvga7zxwqvINeTkF0hdcfgPcAnHc4MASE,125
34
- hypern/db/nosql/__init__.py,sha256=MH9YvlbRlbBCrQVNOdfTaK-hINwJxbJLmxwY9Mei7I8,644
35
- hypern/db/sql/field.py,sha256=tSs8iaYjy-K6nplJJ-1X4OQddzW76cfBlx9xTrG_NbQ,20073
36
- hypern/db/sql/model.py,sha256=BLRmOlmfn6ibedR9Bv_rHErSruudJ24B9-nDbRHqWm4,3913
37
- hypern/db/sql/query.py,sha256=MXiphm4pXBz6Axbdoc5rg11XEmw_UahTCdppowyXJxY,33329
38
- hypern/db/sql/__init__.py,sha256=lCOGNTHaXNSJbuLLIOe2IWWNmX0MFQFPNCl2yytD2Xs,261
39
- hypern/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
40
  hypern/enum.py,sha256=KcVziJj7vWvyie0r2rtxhrLzdtkZAsf0DY58oJ4tQl4,360
41
- hypern/exceptions.py,sha256=rWQpWjnkLY51HBpKcWkFaVGCKoC_EiFUPrIBBfLh-eA,2608
41
+ hypern/exceptions/base.py,sha256=5AgfyEea79JjKk5MeAIJ-wy44FG5XEU0Jn3KXKScPiI,2017
42
+ hypern/exceptions/common.py,sha256=0E8wHRRTWjYOmtOCkTDvZ5NMwL6vRW6aiDD9X1eYA30,227
43
+ hypern/exceptions/errors.py,sha256=oAaeTeMgJEpQHspwZDG7B36FD6u6MoLgsxxDTxD7opc,857
44
+ hypern/exceptions/formatters.py,sha256=nHWrsQwG7VVZmcArDL1EYxIlkpNGkS-eCBVjUHZ296I,2386
45
+ hypern/exceptions/http.py,sha256=Q9rpL86SaUYICFZCGQowkhtd5iTS1mT-QQGx-jv7cNE,3226
46
+ hypern/exceptions/__init__.py,sha256=6ud25zPps_mzWUZlMe0Jz_rLjb3wlUNO8rCH01Di6R0,970
42
47
  hypern/gateway/aggregator.py,sha256=N1onAp9gdzpCR-E5VubkVoUjjEmVNxG8gDZx9rhnbXc,1132
43
48
  hypern/gateway/gateway.py,sha256=26K2qvJUR-0JnN4IlhwvSSt7EYcpYrBVDuzZ1ivQQ34,1475
44
49
  hypern/gateway/proxy.py,sha256=w1wcTplDnVrfjn7hb0M0yBVth5TGl88irF-MUYHysQQ,2463
@@ -54,19 +59,19 @@ hypern/middleware/compress.py,sha256=Zph3pQz15YrYB4dMUMbQnfWIFY8ovysgPMepbY_WV9k
54
59
  hypern/middleware/cors.py,sha256=pt5HyTd3J5L9Lvczo2xI8fxLmtntSbJq-CPU0vYXoAI,1800
55
60
  hypern/middleware/i18n.py,sha256=jHzVzjTx1nnjbraZtIVOprrnSaeKMxZB8RuSqRp2I4s,16
56
61
  hypern/middleware/limit.py,sha256=eAYARPjqxq8Ue0TCpnxlVRB5hv7hwBF0PxeD-bG6Sl0,8252
57
- hypern/middleware/security.py,sha256=d9Qf2UNMN8wz-MLnG2wRb0Vgf55_IGZAje5hbc2T_HQ,7539
62
+ hypern/middleware/security.py,sha256=fGBSF7n2iKBtDHE2QW4q_sQE4awYgaYxVUFKsDHkMXg,7675
58
63
  hypern/middleware/__init__.py,sha256=V-Gnv-Jf-14BVuA28z7PN7GBVQ9BBiBdab6-QnTPCfY,493
59
64
  hypern/openapi/schemas.py,sha256=YHfMlPUeP5DzDX5ao3YH8p_25Vvyaf616dh6XDCUZRc,1677
60
65
  hypern/openapi/swagger.py,sha256=naqUY3rFAEYA1ZLIlmDsMYaol0yIm6TVebdkFa5cMTc,64
61
66
  hypern/openapi/__init__.py,sha256=4rEVD8pa0kdSpsy7ZkJ5JY0Z2XF0NGSKDMwYAd7YZpE,141
62
- hypern/processpool.py,sha256=RFV4turo1dBv40NlzzosjwaZLC24igdyq6twY2IXCUE,2968
67
+ hypern/processpool.py,sha256=qEsu9WXWc3_Cl0Frn1jGs7jUJho45zck5L5Ww81Vm70,3883
63
68
  hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
69
  hypern/reload.py,sha256=nfaZCoChrQetHNtIqN4Xzi-a0v-irxSCMhwCK3bCEq0,1569
65
- hypern/response/response.py,sha256=-dnboAraPic8asf503PxwmDuxhNllUO5h97_DGmbER4,4582
70
+ hypern/response/response.py,sha256=Jrkpk5KOmE4WjsAh1G0hUuPHfOPxU6eeR3J2fRIhusU,4871
66
71
  hypern/response/__init__.py,sha256=_w3u3TDNuYx5ejnnN1unqnTY8NlBgUATQi6wepEB_FQ,226
67
- hypern/routing/dispatcher.py,sha256=oQsbOTkjE5roFCl6k58oCW9lEGR_sY5tBoXSJIDgh0w,2508
72
+ hypern/routing/dispatcher.py,sha256=NAVjILlEJjYrixJZ4CO4N1CKkuqbk4TGZOjnQNTTEu4,2461
68
73
  hypern/routing/endpoint.py,sha256=RKVhvqOEGL9IKBXQ3KJgPi9bgJj9gfWC5BdZc5U_atc,1026
69
- hypern/routing/parser.py,sha256=R-4lcN9Ha1iMeAjlqDe8HwkjjMVG-c-ubQLZyWKXj6M,3554
74
+ hypern/routing/parser.py,sha256=0tJVVNwHC3pWDsehwH6SwJv8_gEuDjltVXrNQWbHyrU,3426
70
75
  hypern/routing/queue.py,sha256=NtFBbogU22ddyyX-CuQMip1XFDPZdMCVMIeUCQ-CR6Y,7176
71
76
  hypern/routing/route.py,sha256=IUnWU5ra-0R9rrRDpxJiwiw7vaEefn-We2dZ4EocJGw,10403
72
77
  hypern/routing/__init__.py,sha256=U4xW5fDRsn03z4cVLT4dJHHGGU6SVxyv2DL86LXodeE,162
@@ -80,5 +85,5 @@ hypern/ws/route.py,sha256=fGQ2RC708MPOiiIHPUo8aZ-oK379TTAyQYm4htNA5jM,803
80
85
  hypern/ws/__init__.py,sha256=dhRoRY683_rfPfSPM5qUczfTuyYDeuLOCFxY4hIdKt8,131
81
86
  hypern/ws.py,sha256=F6SA2Z1KVnqTEX8ssvOXqCtudUS4eo30JsiIsvfbHnE,394
82
87
  hypern/__init__.py,sha256=9Ww_aUQ0vJls0tOq7Yw1_TVOCRsa5bHJ-RtnSeComwk,119
83
- hypern/hypern.cp312-win32.pyd,sha256=jJffm7oIt2JsiZrH3M4faieg-Ezb-WoWOH_4ZMt3sog,9813504
84
- hypern-0.3.4.dist-info/RECORD,,
88
+ hypern/hypern.cp312-win32.pyd,sha256=UEZnqNJkk-53t73JL5FWC2oDcmxOUmLAT8rc1R0E4DI,9796096
89
+ hypern-0.3.6.dist-info/RECORD,,
hypern/exceptions.py DELETED
@@ -1,107 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from typing import Any
3
- from hypern.enum import ErrorCode
4
-
5
-
6
- class BaseException(Exception):
7
- def __init__(self, msg: str = "", *args: Any) -> None:
8
- super().__init__(*args)
9
- self.msg = msg
10
- self.status = 400
11
- self.error_code = ErrorCode.UNKNOWN_ERROR
12
-
13
-
14
- class BadRequest(BaseException):
15
- def __init__(
16
- self,
17
- msg: str = "Bad request",
18
- error_code: str = ErrorCode.BAD_REQUEST,
19
- *args: Any,
20
- ) -> None:
21
- super().__init__(msg, *args)
22
- self.error_code = error_code
23
-
24
-
25
- class ValidationError(BaseException):
26
- def __init__(
27
- self,
28
- msg: str = "Validation error",
29
- error_code: str = ErrorCode.VALIDATION_ERROR,
30
- *args: Any,
31
- ) -> None:
32
- super().__init__(msg, *args)
33
- self.error_code = error_code
34
-
35
-
36
- class Forbidden(BaseException):
37
- def __init__(
38
- self,
39
- msg: str = "Forbidden",
40
- error_code: str = ErrorCode.FORBIDDEN,
41
- *args: Any,
42
- ) -> None:
43
- super().__init__(msg, *args)
44
- self.status = 403
45
- self.error_code = error_code
46
-
47
-
48
- class NotFound(BaseException):
49
- def __init__(
50
- self,
51
- msg: str = "NotFound",
52
- error_code: str = ErrorCode.NOT_FOUND,
53
- *args: Any,
54
- ) -> None:
55
- super().__init__(msg, *args)
56
- self.status = 404
57
- self.error_code = error_code
58
-
59
-
60
- class MethodNotAllow(BaseException):
61
- def __init__(
62
- self,
63
- msg: str = "Method not allow",
64
- error_code: str = ErrorCode.METHOD_NOT_ALLOW,
65
- *args: Any,
66
- ) -> None:
67
- super().__init__(msg, *args)
68
- self.status = 405
69
- self.error_code = error_code
70
-
71
-
72
- class InternalServer(BaseException):
73
- def __init__(
74
- self,
75
- msg: str = "Internal server error",
76
- error_code: str = ErrorCode.SERVER_ERROR,
77
- *args: Any,
78
- ) -> None:
79
- super().__init__(msg, *args)
80
- self.status = 500
81
- self.error_code = error_code
82
-
83
-
84
- class Unauthorized(BaseException):
85
- def __init__(
86
- self,
87
- msg: str = "Unauthorized",
88
- error_code: str = ErrorCode.UNAUTHORIZED,
89
- *args: Any,
90
- ) -> None:
91
- super().__init__(msg, *args)
92
- self.status = 401
93
- self.error_code = error_code
94
-
95
-
96
- class InvalidPortNumber(Exception):
97
- pass
98
-
99
-
100
- class OutOfScopeApplicationException(Exception):
101
- pass
102
-
103
-
104
- class DBFieldValidationError(ValueError):
105
- """Custom exception for field validation errors."""
106
-
107
- pass
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes