nlbone 0.7.31__py3-none-any.whl → 0.8.0__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.
- nlbone/adapters/i18n/engine.py +22 -17
- nlbone/adapters/i18n/locales/fa-IR.json +0 -5
- nlbone/interfaces/api/exception_handlers.py +123 -71
- nlbone/interfaces/api/exceptions.py +114 -69
- nlbone/interfaces/api/schemas.py +1 -0
- nlbone/utils/flatten_dict.py +9 -0
- {nlbone-0.7.31.dist-info → nlbone-0.8.0.dist-info}/METADATA +1 -1
- {nlbone-0.7.31.dist-info → nlbone-0.8.0.dist-info}/RECORD +11 -10
- {nlbone-0.7.31.dist-info → nlbone-0.8.0.dist-info}/WHEEL +0 -0
- {nlbone-0.7.31.dist-info → nlbone-0.8.0.dist-info}/entry_points.txt +0 -0
- {nlbone-0.7.31.dist-info → nlbone-0.8.0.dist-info}/licenses/LICENSE +0 -0
nlbone/adapters/i18n/engine.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from typing import Dict, Optional
|
|
2
3
|
|
|
4
|
+
from nlbone.adapters.i18n.loaders import BaseLoader
|
|
5
|
+
|
|
3
6
|
from nlbone.core.ports.translation import TranslationPort
|
|
4
|
-
from nlbone.utils.context import get_locale
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class I18nAdapter(TranslationPort):
|
|
@@ -17,19 +19,22 @@ class I18nAdapter(TranslationPort):
|
|
|
17
19
|
self._translations = self.loader.load()
|
|
18
20
|
|
|
19
21
|
def translate(self, key: str, locale: Optional[str] = None, **kwargs) -> str:
|
|
20
|
-
self._ensure_loaded()
|
|
21
|
-
|
|
22
22
|
target_locale = locale or self.default_locale
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
try:
|
|
24
|
+
self._ensure_loaded()
|
|
25
|
+
|
|
26
|
+
locale_data = self._translations.get(target_locale, {})
|
|
27
|
+
text = locale_data.get(key)
|
|
28
|
+
|
|
29
|
+
if text is None:
|
|
30
|
+
text = self._translations.get(self.default_locale, {}).get(key, key)
|
|
31
|
+
|
|
32
|
+
if kwargs:
|
|
33
|
+
try:
|
|
34
|
+
return text.format(**kwargs)
|
|
35
|
+
except KeyError:
|
|
36
|
+
pass
|
|
37
|
+
return text
|
|
38
|
+
except:
|
|
39
|
+
logger.exception("Failed to translate key '{}' to locale '{}'".format(key, target_locale))
|
|
40
|
+
return key
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Any, Mapping, Optional
|
|
3
|
+
from typing import Any, Mapping, Optional, List
|
|
4
4
|
from uuid import uuid4
|
|
5
5
|
|
|
6
6
|
from fastapi import FastAPI, Request
|
|
7
7
|
from fastapi import HTTPException as FastAPIHTTPException
|
|
8
8
|
from fastapi.exceptions import RequestValidationError
|
|
9
9
|
from fastapi.responses import JSONResponse
|
|
10
|
-
from pydantic import ValidationError
|
|
10
|
+
from pydantic import BaseModel, ValidationError
|
|
11
11
|
from starlette.exceptions import HTTPException as StarletteHTTPException
|
|
12
|
-
|
|
13
|
-
from .exceptions import BaseHttpException
|
|
12
|
+
from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR, HTTP_422_UNPROCESSABLE_ENTITY
|
|
14
13
|
|
|
15
14
|
from nlbone.adapters.i18n import translator as _
|
|
16
|
-
|
|
15
|
+
from .exceptions import BaseHttpException, ErrorDetail, UnprocessableEntityException
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ErrorResponse(BaseModel):
|
|
19
|
+
message: str
|
|
20
|
+
errors: List[ErrorDetail]
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
def _ensure_trace_id(request: Request) -> str:
|
|
@@ -22,93 +26,141 @@ def _ensure_trace_id(request: Request) -> str:
|
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
def _json_response(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
trace_id: Optional[str] = None,
|
|
31
|
-
extra: Optional[Mapping[str, Any]] = None,
|
|
29
|
+
request: Request,
|
|
30
|
+
status_code: int,
|
|
31
|
+
content: Any,
|
|
32
|
+
trace_id: Optional[str] = None,
|
|
33
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
32
34
|
) -> JSONResponse:
|
|
33
|
-
payload: dict[str, Any] = {"detail": detail}
|
|
34
|
-
if extra:
|
|
35
|
-
payload.update(extra)
|
|
36
35
|
tid = trace_id or _ensure_trace_id(request)
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
if isinstance(content, dict):
|
|
38
|
+
payload = content
|
|
39
|
+
else:
|
|
40
|
+
payload = content.model_dump(exclude_none=True) if hasattr(content, "model_dump") else content
|
|
41
|
+
|
|
42
|
+
payload["trace_id"] = tid
|
|
39
43
|
|
|
40
44
|
base_headers = {"X-Trace-Id": tid}
|
|
41
45
|
if headers:
|
|
42
46
|
base_headers.update(headers)
|
|
43
47
|
|
|
44
|
-
return JSONResponse(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
return JSONResponse(
|
|
49
|
+
status_code=status_code,
|
|
50
|
+
content=payload,
|
|
51
|
+
headers=base_headers
|
|
52
|
+
)
|
|
48
53
|
|
|
49
54
|
|
|
50
55
|
def install_exception_handlers(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
app: FastAPI,
|
|
57
|
+
*,
|
|
58
|
+
logger: Any = None,
|
|
59
|
+
expose_server_errors: bool = False,
|
|
55
60
|
) -> None:
|
|
61
|
+
async def _log_exception(
|
|
62
|
+
request: Request,
|
|
63
|
+
exc: Exception,
|
|
64
|
+
level: str = "warning",
|
|
65
|
+
extra: Optional[dict] = None
|
|
66
|
+
):
|
|
67
|
+
if not logger:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
log_payload = {
|
|
71
|
+
"path": request.url.path,
|
|
72
|
+
"method": request.method,
|
|
73
|
+
**extra
|
|
74
|
+
} if extra else {"path": request.url.path}
|
|
75
|
+
|
|
76
|
+
log_method = getattr(logger, level, logger.warning)
|
|
77
|
+
log_method(str(exc), extra=log_payload)
|
|
78
|
+
|
|
56
79
|
@app.exception_handler(BaseHttpException)
|
|
57
80
|
async def _handle_base_http_exception(request: Request, exc: BaseHttpException):
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
await _log_exception(request, exc, extra={"status": exc.status_code, "detail": exc.message})
|
|
82
|
+
|
|
83
|
+
locale = getattr(request.state, "locale", None)
|
|
84
|
+
|
|
85
|
+
main_message = _(exc.message, locale=locale)
|
|
86
|
+
|
|
87
|
+
translated_errors = []
|
|
88
|
+
if exc.errors:
|
|
89
|
+
for err in exc.errors:
|
|
90
|
+
err_copy = err.model_copy()
|
|
91
|
+
if err_copy.message:
|
|
92
|
+
err_copy.message = _(err_copy.message, locale=locale)
|
|
93
|
+
translated_errors.append(err_copy)
|
|
94
|
+
|
|
95
|
+
response_model = ErrorResponse(
|
|
96
|
+
message=main_message,
|
|
97
|
+
errors=translated_errors
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return _json_response(request, exc.status_code, content=response_model)
|
|
75
101
|
|
|
76
|
-
@app.exception_handler(StarletteHTTPException)
|
|
77
|
-
async def _handle_starlette_http_exception(request: Request, exc: StarletteHTTPException):
|
|
78
|
-
if logger:
|
|
79
|
-
logger.warning(
|
|
80
|
-
"starlette_http_error",
|
|
81
|
-
extra={"status": exc.status_code, "detail": exc.detail, "path": request.url.path},
|
|
82
|
-
)
|
|
83
|
-
locale = locale = getattr(request.state, "locale", None)
|
|
84
|
-
return _json_response(request, exc.status_code, detail=_(exc.detail, locale=locale))
|
|
85
|
-
|
|
86
|
-
# 3) خطاهای اعتبارسنجی FastAPI (request body/query/path)
|
|
87
102
|
@app.exception_handler(RequestValidationError)
|
|
88
103
|
async def _handle_request_validation_error(request: Request, exc: RequestValidationError):
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return
|
|
104
|
+
await _log_exception(request, exc, level="info", extra={"errors": exc.errors()})
|
|
105
|
+
|
|
106
|
+
normalized_exception = UnprocessableEntityException(
|
|
107
|
+
detail="Validation Error",
|
|
108
|
+
validation_errors=exc.errors()
|
|
109
|
+
)
|
|
110
|
+
return await _handle_base_http_exception(request, normalized_exception)
|
|
96
111
|
|
|
97
112
|
@app.exception_handler(ValidationError)
|
|
98
113
|
async def _handle_pydantic_validation_error(request: Request, exc: ValidationError):
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return
|
|
114
|
+
await _log_exception(request, exc, level="info", extra={"errors": exc.errors()})
|
|
115
|
+
|
|
116
|
+
normalized_exception = UnprocessableEntityException(
|
|
117
|
+
detail="Validation Error",
|
|
118
|
+
validation_errors=exc.errors()
|
|
119
|
+
)
|
|
120
|
+
return await _handle_base_http_exception(request, normalized_exception)
|
|
121
|
+
|
|
122
|
+
@app.exception_handler(StarletteHTTPException)
|
|
123
|
+
async def _handle_starlette_http_exception(request: Request, exc: StarletteHTTPException):
|
|
124
|
+
await _log_exception(request, exc, extra={"status": exc.status_code})
|
|
125
|
+
|
|
126
|
+
locale = getattr(request.state, "locale", None)
|
|
127
|
+
message_str = str(exc.detail) if exc.detail else "HTTP Error"
|
|
128
|
+
translated_message = _(message_str, locale=locale)
|
|
129
|
+
|
|
130
|
+
error_detail = ErrorDetail(
|
|
131
|
+
code=exc.status_code,
|
|
132
|
+
message=translated_message
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
response_model = ErrorResponse(
|
|
136
|
+
message=translated_message,
|
|
137
|
+
errors=[error_detail]
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
return _json_response(request, exc.status_code, content=response_model)
|
|
106
141
|
|
|
107
142
|
@app.exception_handler(Exception)
|
|
108
143
|
async def _handle_unexpected_exception(request: Request, exc: Exception):
|
|
109
144
|
tid = _ensure_trace_id(request)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
locale =
|
|
114
|
-
|
|
145
|
+
await _log_exception(request, exc, level="exception", extra={"trace_id": tid})
|
|
146
|
+
|
|
147
|
+
raw_detail = str(exc) if expose_server_errors else "Internal Server Error"
|
|
148
|
+
locale = getattr(request.state, "locale", None)
|
|
149
|
+
translated_detail = _(raw_detail, locale=locale)
|
|
150
|
+
|
|
151
|
+
error_detail = ErrorDetail(
|
|
152
|
+
code=HTTP_500_INTERNAL_SERVER_ERROR,
|
|
153
|
+
message=translated_detail
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
response_model = ErrorResponse(
|
|
157
|
+
message=translated_detail,
|
|
158
|
+
errors=[error_detail]
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return _json_response(
|
|
162
|
+
request,
|
|
163
|
+
HTTP_500_INTERNAL_SERVER_ERROR,
|
|
164
|
+
content=response_model,
|
|
165
|
+
trace_id=tid
|
|
166
|
+
)
|
|
@@ -1,108 +1,153 @@
|
|
|
1
|
-
from
|
|
1
|
+
from http import HTTPStatus
|
|
2
|
+
from typing import Any, Dict, List, Optional, Union
|
|
2
3
|
|
|
3
|
-
from fastapi import HTTPException
|
|
4
|
+
from fastapi import HTTPException
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
4
6
|
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
8
|
+
class ErrorDetail(BaseModel):
|
|
9
|
+
code: int | str = 0
|
|
10
|
+
message: Optional[str] = None
|
|
11
|
+
fields: Optional[Union[List[Union[str, int]], str]] = None
|
|
12
|
+
data: Optional[Union[List[Dict], Dict]] = None
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
class BaseHttpException(HTTPException):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
status_code: int,
|
|
19
|
+
detail: Optional[str] = None,
|
|
20
|
+
errors: Optional[List[ErrorDetail]] = None,
|
|
21
|
+
fields: Optional[Union[List[Union[str, int]], str]] = None,
|
|
22
|
+
data: Optional[Dict] = None,
|
|
23
|
+
code: Optional[str] = None,
|
|
24
|
+
):
|
|
25
|
+
if errors is None:
|
|
26
|
+
message = detail or HTTPStatus(status_code).phrase
|
|
27
|
+
|
|
28
|
+
if not code:
|
|
29
|
+
code = HTTPStatus(status_code).phrase.lower().replace(" ", "_")
|
|
30
|
+
|
|
31
|
+
errors = [
|
|
32
|
+
ErrorDetail(
|
|
33
|
+
code=code,
|
|
34
|
+
message=message,
|
|
35
|
+
fields=fields,
|
|
36
|
+
data=data
|
|
37
|
+
)
|
|
38
|
+
]
|
|
16
39
|
|
|
40
|
+
self.errors = errors
|
|
41
|
+
super().__init__(status_code=status_code, detail=self.message)
|
|
17
42
|
|
|
18
|
-
|
|
19
|
-
|
|
43
|
+
@property
|
|
44
|
+
def message(self) -> str:
|
|
45
|
+
if self.errors and self.errors[0].message:
|
|
46
|
+
return self.errors[0].message
|
|
47
|
+
return HTTPStatus(self.status_code).phrase
|
|
20
48
|
|
|
21
49
|
|
|
22
|
-
class
|
|
23
|
-
def __init__(
|
|
50
|
+
class UnprocessableEntityException(BaseHttpException):
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
detail: str = None,
|
|
54
|
+
fields: Optional[Union[List[Union[str, int]], str]] = None,
|
|
55
|
+
validation_errors: Optional[List[Dict[str, Any]]] = None
|
|
56
|
+
):
|
|
57
|
+
errors = None
|
|
58
|
+
|
|
59
|
+
if validation_errors:
|
|
60
|
+
errors = []
|
|
61
|
+
for error in validation_errors:
|
|
62
|
+
err_type = error.get("type")
|
|
63
|
+
loc = error.get("loc")
|
|
64
|
+
msg = error.get("msg")
|
|
65
|
+
inp = error.get("input")
|
|
66
|
+
|
|
67
|
+
if err_type == "json_invalid":
|
|
68
|
+
loc = ["body"]
|
|
69
|
+
msg = "Invalid JSON format. Please check your syntax (e.g., convert '۱' to '1')."
|
|
70
|
+
|
|
71
|
+
elif isinstance(loc, tuple):
|
|
72
|
+
loc = list(loc)
|
|
73
|
+
|
|
74
|
+
error_data = {}
|
|
75
|
+
if inp is not None and not (isinstance(inp, dict) and not inp):
|
|
76
|
+
error_data["input"] = inp
|
|
77
|
+
|
|
78
|
+
errors.append(
|
|
79
|
+
ErrorDetail(
|
|
80
|
+
code=err_type or "validation_error",
|
|
81
|
+
message=msg,
|
|
82
|
+
fields=loc,
|
|
83
|
+
data=error_data if error_data else None
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
|
|
24
87
|
super().__init__(
|
|
25
|
-
status_code=
|
|
88
|
+
status_code=HTTPStatus.UNPROCESSABLE_ENTITY,
|
|
26
89
|
detail=detail,
|
|
90
|
+
fields=fields,
|
|
91
|
+
errors=errors
|
|
27
92
|
)
|
|
28
93
|
|
|
29
94
|
|
|
95
|
+
class BadRequestException(BaseHttpException):
|
|
96
|
+
def __init__(self, detail: str = None, code: int = 0):
|
|
97
|
+
super().__init__(status_code=HTTPStatus.BAD_REQUEST, detail=detail, code=code)
|
|
98
|
+
|
|
99
|
+
|
|
30
100
|
class UnauthorizedException(BaseHttpException):
|
|
31
|
-
def __init__(self, detail: str =
|
|
32
|
-
super().__init__(
|
|
33
|
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
34
|
-
detail=detail,
|
|
35
|
-
)
|
|
101
|
+
def __init__(self, detail: str = None):
|
|
102
|
+
super().__init__(status_code=HTTPStatus.UNAUTHORIZED, detail=detail)
|
|
36
103
|
|
|
37
104
|
|
|
38
105
|
class ForbiddenException(BaseHttpException):
|
|
39
|
-
def __init__(self, detail: str =
|
|
40
|
-
super().__init__(
|
|
41
|
-
status_code=status.HTTP_403_FORBIDDEN,
|
|
42
|
-
detail=detail,
|
|
43
|
-
)
|
|
106
|
+
def __init__(self, detail: str = None):
|
|
107
|
+
super().__init__(status_code=HTTPStatus.FORBIDDEN, detail=detail)
|
|
44
108
|
|
|
45
109
|
|
|
46
110
|
class NotFoundException(BaseHttpException):
|
|
47
|
-
def __init__(self, detail: str =
|
|
48
|
-
super().__init__(
|
|
49
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
|
50
|
-
detail=detail,
|
|
51
|
-
)
|
|
111
|
+
def __init__(self, detail: str = None):
|
|
112
|
+
super().__init__(status_code=HTTPStatus.NOT_FOUND, detail=detail)
|
|
52
113
|
|
|
53
114
|
|
|
54
115
|
class ConflictException(BaseHttpException):
|
|
55
|
-
def __init__(self, detail: str =
|
|
56
|
-
super().__init__(
|
|
57
|
-
status_code=status.HTTP_409_CONFLICT,
|
|
58
|
-
detail=detail,
|
|
59
|
-
)
|
|
116
|
+
def __init__(self, detail: str = None, data: Optional[Union[List[Dict], Dict]] = None):
|
|
117
|
+
super().__init__(status_code=HTTPStatus.CONFLICT, detail=detail, data=data)
|
|
60
118
|
|
|
61
119
|
|
|
62
120
|
class NotSupportedException(BaseHttpException):
|
|
63
|
-
def __init__(self, detail: str =
|
|
64
|
-
super().__init__(
|
|
65
|
-
status_code=status.HTTP_501_NOT_IMPLEMENTED,
|
|
66
|
-
detail=detail,
|
|
67
|
-
)
|
|
121
|
+
def __init__(self, detail: str = None):
|
|
122
|
+
super().__init__(status_code=HTTPStatus.NOT_IMPLEMENTED, detail=detail)
|
|
68
123
|
|
|
69
124
|
|
|
70
125
|
class InternalServerException(BaseHttpException):
|
|
71
|
-
def __init__(self, detail: str =
|
|
72
|
-
super().__init__(
|
|
73
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
74
|
-
detail=detail,
|
|
75
|
-
)
|
|
126
|
+
def __init__(self, detail: str = None):
|
|
127
|
+
super().__init__(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=detail)
|
|
76
128
|
|
|
77
129
|
|
|
78
|
-
class UnprocessableEntityException
|
|
79
|
-
def __init__(self, detail: str
|
|
130
|
+
class LogicalValidationException(UnprocessableEntityException):
|
|
131
|
+
def __init__(self, detail: str = None,
|
|
132
|
+
fields: Optional[Union[List[str], str]] = None,
|
|
133
|
+
validation_errors: Optional[List[Dict[str, Any]]] = None):
|
|
80
134
|
super().__init__(
|
|
81
|
-
|
|
82
|
-
|
|
135
|
+
detail=detail,
|
|
136
|
+
fields=fields,
|
|
137
|
+
validation_errors=validation_errors
|
|
83
138
|
)
|
|
84
139
|
|
|
85
140
|
|
|
86
|
-
class LogicalValidationException(HTTPException):
|
|
87
|
-
def __init__(self, detail: str = None, loc: Iterable[Any] | None = None, type_: str = "logical_error",
|
|
88
|
-
errors: List[Dict[str, Any]] = None):
|
|
89
|
-
self.errors = errors
|
|
90
|
-
if errors:
|
|
91
|
-
super().__init__(detail=errors, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,)
|
|
92
|
-
else:
|
|
93
|
-
super().__init__(detail=_errors(loc, detail, type_), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
|
|
94
|
-
|
|
95
|
-
|
|
96
141
|
class GoneException(BaseHttpException):
|
|
97
|
-
def __init__(self, detail: str =
|
|
98
|
-
super().__init__(
|
|
99
|
-
|
|
100
|
-
detail=detail,
|
|
101
|
-
)
|
|
142
|
+
def __init__(self, detail: str = None):
|
|
143
|
+
super().__init__(status_code=HTTPStatus.GONE, detail=detail)
|
|
144
|
+
|
|
102
145
|
|
|
103
146
|
class TooManyRequestsException(BaseHttpException):
|
|
104
|
-
def __init__(self, detail: str =
|
|
105
|
-
super().__init__(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
147
|
+
def __init__(self, detail: str = None):
|
|
148
|
+
super().__init__(status_code=HTTPStatus.TOO_MANY_REQUESTS, detail=detail)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class NotAcceptableException(BaseHttpException):
|
|
152
|
+
def __init__(self, detail: str = None):
|
|
153
|
+
super().__init__(status_code=HTTPStatus.NOT_ACCEPTABLE, detail=detail)
|
nlbone/interfaces/api/schemas.py
CHANGED
|
@@ -31,9 +31,9 @@ nlbone/adapters/http_clients/uploadchi/__init__.py,sha256=uBzEOuVtY22teWW2b36Pit
|
|
|
31
31
|
nlbone/adapters/http_clients/uploadchi/uploadchi.py,sha256=erpjOees25FW0nuK1PkYS-oU0h8MeRV9Rhs1cf3gaEs,4881
|
|
32
32
|
nlbone/adapters/http_clients/uploadchi/uploadchi_async.py,sha256=PQbVNeaYde5CmgT3vcnQoI1PGeSs9AxHlPFuB8biOmU,4717
|
|
33
33
|
nlbone/adapters/i18n/__init__.py,sha256=fS97TR7HEc7fiDC2ufQKoFOxXDNkGA4njAFIB3EmhLk,426
|
|
34
|
-
nlbone/adapters/i18n/engine.py,sha256=
|
|
34
|
+
nlbone/adapters/i18n/engine.py,sha256=yH_b614oJQ2PgM8qpQ5_Prroi4Jjqb-xPguHCCJm0_0,1305
|
|
35
35
|
nlbone/adapters/i18n/loaders.py,sha256=7td0Cmn0ehjDO2S2qeH31zwl8UyWI7quzedP9PnPhWk,2381
|
|
36
|
-
nlbone/adapters/i18n/locales/fa-IR.json,sha256=
|
|
36
|
+
nlbone/adapters/i18n/locales/fa-IR.json,sha256=Sc711S0_HexhSCJ6eVgr2HjoSDmSz4uODZmNn9O9Pec,88
|
|
37
37
|
nlbone/adapters/messaging/__init__.py,sha256=o6ZiMihm_MhRXfcEpcjHBB3JGQovQbg3pxe0qS6516c,41
|
|
38
38
|
nlbone/adapters/messaging/event_bus.py,sha256=MSM70JPHoDK17efWlh20ATT1O0KW7xWnwZ5D-gI6U_w,3773
|
|
39
39
|
nlbone/adapters/messaging/rabbitmq.py,sha256=Io3flSj8DMIHExJguh3hDgWT4LuDoPYb_xmQQ3k47Cs,1894
|
|
@@ -70,10 +70,10 @@ nlbone/core/ports/translation.py,sha256=pnqbxhdRCR7eprm8UI8ZKKx7VDUPntvBtlytrnTG
|
|
|
70
70
|
nlbone/core/ports/uow.py,sha256=VhqSc-Ryt9m-rlNMiXTzD3dPGz6mM_JxND8D0UJGRu4,962
|
|
71
71
|
nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
72
|
nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
nlbone/interfaces/api/exception_handlers.py,sha256=
|
|
74
|
-
nlbone/interfaces/api/exceptions.py,sha256=
|
|
73
|
+
nlbone/interfaces/api/exception_handlers.py,sha256=2wJp0HZcsSNVsmjFXma3FQ994iga7m3zm9o1E4MIncw,5582
|
|
74
|
+
nlbone/interfaces/api/exceptions.py,sha256=IggZxV9q6l4jqw-G7SWEmuyXnWgbNXJJT-rmnirRIK4,5057
|
|
75
75
|
nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
|
-
nlbone/interfaces/api/schemas.py,sha256=
|
|
76
|
+
nlbone/interfaces/api/schemas.py,sha256=34Tz2EeXyf12rFL9iyYWaB2ftuaXUebQQQxSO9ouV94,133
|
|
77
77
|
nlbone/interfaces/api/additional_filed/__init__.py,sha256=BWemliLSQV9iq1vdUaF733q0FOSipSWBOQk9eYj732Q,318
|
|
78
78
|
nlbone/interfaces/api/additional_filed/assembler.py,sha256=80sFuNiquqdLPOcx7MoQ_ud9fAJtA327M77Z9V47pIU,1956
|
|
79
79
|
nlbone/interfaces/api/additional_filed/field_registry.py,sha256=IhIvzHWOMtKv8iTdFu7LzQboi4SFTLOyJqKdYPY8xFE,5418
|
|
@@ -109,13 +109,14 @@ nlbone/utils/cache_keys.py,sha256=Y2YSellHTbUOcoaNbl1jaD4r485VU_e4KXsfBWhYTBo,10
|
|
|
109
109
|
nlbone/utils/cache_registry.py,sha256=3FWYyhujW8oPBiVUPzk1CqJ3jJfxs9729Sbb1pQ5Fag,707
|
|
110
110
|
nlbone/utils/context.py,sha256=Wq3QLYsMzo_xUiVAHLgEPQUG6LhgJTmFn8MO5Qa7S8w,1837
|
|
111
111
|
nlbone/utils/crypto.py,sha256=PX0Tlf2nqXcGbuv16J26MoUPzo2c4xcD4sZBXxhBXgQ,746
|
|
112
|
+
nlbone/utils/flatten_dict.py,sha256=nkx8gAcJkjCKG3I5y9clqtjGMZCWyUWRhgD2R8zGEqM,299
|
|
112
113
|
nlbone/utils/flatten_sqlalchemy_result.py,sha256=JGwQEauoJVjhzvXrOtqabj3wQ7zp2-OPwhuh44sUdUE,625
|
|
113
114
|
nlbone/utils/http.py,sha256=0yeI34j5FfelqvX3PJnKknSXji1jl15VYbVIIvrSbXg,997
|
|
114
115
|
nlbone/utils/normalize_mobile.py,sha256=sGH4tV9gX-6eVKozviNWJhm1DN1J28Nj-ERldCYkS_E,732
|
|
115
116
|
nlbone/utils/redactor.py,sha256=-V4HrHmHwPi3Kez587Ek1uJlgK35qGSrwBOvcbw8Jas,1279
|
|
116
117
|
nlbone/utils/time.py,sha256=DjjyQ9GLsfXoT6NK8RDW2rOlJg3e6sF04Jw6PBUrSvg,1268
|
|
117
|
-
nlbone-0.
|
|
118
|
-
nlbone-0.
|
|
119
|
-
nlbone-0.
|
|
120
|
-
nlbone-0.
|
|
121
|
-
nlbone-0.
|
|
118
|
+
nlbone-0.8.0.dist-info/METADATA,sha256=Joe3SppJPlbtJ5q5vdB1jSKCTAgOodLaLdkI4BWg7K4,2294
|
|
119
|
+
nlbone-0.8.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
120
|
+
nlbone-0.8.0.dist-info/entry_points.txt,sha256=CpIL45t5nbhl1dGQPhfIIDfqqak3teK0SxPGBBr7YCk,59
|
|
121
|
+
nlbone-0.8.0.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
|
+
nlbone-0.8.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|