aury-boot 0.0.2__py3-none-any.whl → 0.0.3__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.
- aury/boot/__init__.py +66 -0
- aury/boot/_version.py +2 -2
- aury/boot/application/__init__.py +120 -0
- aury/boot/application/app/__init__.py +39 -0
- aury/boot/application/app/base.py +511 -0
- aury/boot/application/app/components.py +434 -0
- aury/boot/application/app/middlewares.py +101 -0
- aury/boot/application/config/__init__.py +44 -0
- aury/boot/application/config/settings.py +663 -0
- aury/boot/application/constants/__init__.py +19 -0
- aury/boot/application/constants/components.py +50 -0
- aury/boot/application/constants/scheduler.py +28 -0
- aury/boot/application/constants/service.py +29 -0
- aury/boot/application/errors/__init__.py +55 -0
- aury/boot/application/errors/chain.py +80 -0
- aury/boot/application/errors/codes.py +67 -0
- aury/boot/application/errors/exceptions.py +238 -0
- aury/boot/application/errors/handlers.py +320 -0
- aury/boot/application/errors/response.py +120 -0
- aury/boot/application/interfaces/__init__.py +76 -0
- aury/boot/application/interfaces/egress.py +224 -0
- aury/boot/application/interfaces/ingress.py +98 -0
- aury/boot/application/middleware/__init__.py +22 -0
- aury/boot/application/middleware/logging.py +451 -0
- aury/boot/application/migrations/__init__.py +13 -0
- aury/boot/application/migrations/manager.py +685 -0
- aury/boot/application/migrations/setup.py +237 -0
- aury/boot/application/rpc/__init__.py +63 -0
- aury/boot/application/rpc/base.py +108 -0
- aury/boot/application/rpc/client.py +294 -0
- aury/boot/application/rpc/discovery.py +218 -0
- aury/boot/application/scheduler/__init__.py +13 -0
- aury/boot/application/scheduler/runner.py +123 -0
- aury/boot/application/server/__init__.py +296 -0
- aury/boot/commands/__init__.py +30 -0
- aury/boot/commands/add.py +76 -0
- aury/boot/commands/app.py +105 -0
- aury/boot/commands/config.py +177 -0
- aury/boot/commands/docker.py +367 -0
- aury/boot/commands/docs.py +284 -0
- aury/boot/commands/generate.py +1277 -0
- aury/boot/commands/init.py +890 -0
- aury/boot/commands/migrate/__init__.py +37 -0
- aury/boot/commands/migrate/app.py +54 -0
- aury/boot/commands/migrate/commands.py +303 -0
- aury/boot/commands/scheduler.py +124 -0
- aury/boot/commands/server/__init__.py +21 -0
- aury/boot/commands/server/app.py +541 -0
- aury/boot/commands/templates/generate/api.py.tpl +105 -0
- aury/boot/commands/templates/generate/model.py.tpl +17 -0
- aury/boot/commands/templates/generate/repository.py.tpl +19 -0
- aury/boot/commands/templates/generate/schema.py.tpl +29 -0
- aury/boot/commands/templates/generate/service.py.tpl +48 -0
- aury/boot/commands/templates/project/CLI.md.tpl +92 -0
- aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +1397 -0
- aury/boot/commands/templates/project/README.md.tpl +111 -0
- aury/boot/commands/templates/project/admin_console_init.py.tpl +50 -0
- aury/boot/commands/templates/project/config.py.tpl +30 -0
- aury/boot/commands/templates/project/conftest.py.tpl +26 -0
- aury/boot/commands/templates/project/env.example.tpl +213 -0
- aury/boot/commands/templates/project/gitignore.tpl +128 -0
- aury/boot/commands/templates/project/main.py.tpl +41 -0
- aury/boot/commands/templates/project/modules/api.py.tpl +19 -0
- aury/boot/commands/templates/project/modules/exceptions.py.tpl +84 -0
- aury/boot/commands/templates/project/modules/schedules.py.tpl +18 -0
- aury/boot/commands/templates/project/modules/tasks.py.tpl +20 -0
- aury/boot/commands/worker.py +143 -0
- aury/boot/common/__init__.py +35 -0
- aury/boot/common/exceptions/__init__.py +114 -0
- aury/boot/common/i18n/__init__.py +16 -0
- aury/boot/common/i18n/translator.py +272 -0
- aury/boot/common/logging/__init__.py +716 -0
- aury/boot/contrib/__init__.py +10 -0
- aury/boot/contrib/admin_console/__init__.py +18 -0
- aury/boot/contrib/admin_console/auth.py +137 -0
- aury/boot/contrib/admin_console/discovery.py +69 -0
- aury/boot/contrib/admin_console/install.py +172 -0
- aury/boot/contrib/admin_console/utils.py +44 -0
- aury/boot/domain/__init__.py +79 -0
- aury/boot/domain/exceptions/__init__.py +132 -0
- aury/boot/domain/models/__init__.py +51 -0
- aury/boot/domain/models/base.py +69 -0
- aury/boot/domain/models/mixins.py +135 -0
- aury/boot/domain/models/models.py +96 -0
- aury/boot/domain/pagination/__init__.py +279 -0
- aury/boot/domain/repository/__init__.py +23 -0
- aury/boot/domain/repository/impl.py +423 -0
- aury/boot/domain/repository/interceptors.py +47 -0
- aury/boot/domain/repository/interface.py +106 -0
- aury/boot/domain/repository/query_builder.py +348 -0
- aury/boot/domain/service/__init__.py +11 -0
- aury/boot/domain/service/base.py +73 -0
- aury/boot/domain/transaction/__init__.py +404 -0
- aury/boot/infrastructure/__init__.py +104 -0
- aury/boot/infrastructure/cache/__init__.py +31 -0
- aury/boot/infrastructure/cache/backends.py +348 -0
- aury/boot/infrastructure/cache/base.py +68 -0
- aury/boot/infrastructure/cache/exceptions.py +37 -0
- aury/boot/infrastructure/cache/factory.py +94 -0
- aury/boot/infrastructure/cache/manager.py +274 -0
- aury/boot/infrastructure/database/__init__.py +39 -0
- aury/boot/infrastructure/database/config.py +71 -0
- aury/boot/infrastructure/database/exceptions.py +44 -0
- aury/boot/infrastructure/database/manager.py +317 -0
- aury/boot/infrastructure/database/query_tools/__init__.py +164 -0
- aury/boot/infrastructure/database/strategies/__init__.py +198 -0
- aury/boot/infrastructure/di/__init__.py +15 -0
- aury/boot/infrastructure/di/container.py +393 -0
- aury/boot/infrastructure/events/__init__.py +33 -0
- aury/boot/infrastructure/events/bus.py +362 -0
- aury/boot/infrastructure/events/config.py +52 -0
- aury/boot/infrastructure/events/consumer.py +134 -0
- aury/boot/infrastructure/events/middleware.py +51 -0
- aury/boot/infrastructure/events/models.py +63 -0
- aury/boot/infrastructure/monitoring/__init__.py +529 -0
- aury/boot/infrastructure/scheduler/__init__.py +19 -0
- aury/boot/infrastructure/scheduler/exceptions.py +37 -0
- aury/boot/infrastructure/scheduler/manager.py +478 -0
- aury/boot/infrastructure/storage/__init__.py +38 -0
- aury/boot/infrastructure/storage/base.py +164 -0
- aury/boot/infrastructure/storage/exceptions.py +37 -0
- aury/boot/infrastructure/storage/factory.py +88 -0
- aury/boot/infrastructure/tasks/__init__.py +24 -0
- aury/boot/infrastructure/tasks/config.py +45 -0
- aury/boot/infrastructure/tasks/constants.py +37 -0
- aury/boot/infrastructure/tasks/exceptions.py +37 -0
- aury/boot/infrastructure/tasks/manager.py +490 -0
- aury/boot/testing/__init__.py +24 -0
- aury/boot/testing/base.py +122 -0
- aury/boot/testing/client.py +163 -0
- aury/boot/testing/factory.py +154 -0
- aury/boot/toolkit/__init__.py +21 -0
- aury/boot/toolkit/http/__init__.py +367 -0
- {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/METADATA +3 -2
- aury_boot-0.0.3.dist-info/RECORD +137 -0
- aury_boot-0.0.2.dist-info/RECORD +0 -5
- {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/WHEEL +0 -0
- {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""中间件和组件名称常量。
|
|
2
|
+
|
|
3
|
+
定义所有内置中间件和组件的标准命名。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MiddlewareName(str, Enum):
|
|
12
|
+
"""中间件名称常量。
|
|
13
|
+
|
|
14
|
+
所有内置 HTTP 中间件的标准命名。
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# HTTP 中间件
|
|
18
|
+
REQUEST_LOGGING = "request_logging"
|
|
19
|
+
WEBSOCKET_LOGGING = "websocket_logging"
|
|
20
|
+
CORS = "cors"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ComponentName(str, Enum):
|
|
24
|
+
"""组件名称常量。
|
|
25
|
+
|
|
26
|
+
所有内置基础设施组件的标准命名。
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# 基础设施组件
|
|
30
|
+
DATABASE = "database"
|
|
31
|
+
CACHE = "cache"
|
|
32
|
+
TASK_QUEUE = "task_queue"
|
|
33
|
+
SCHEDULER = "scheduler"
|
|
34
|
+
|
|
35
|
+
# 存储组件
|
|
36
|
+
STORAGE = "storage"
|
|
37
|
+
|
|
38
|
+
# 迁移组件
|
|
39
|
+
MIGRATIONS = "migrations"
|
|
40
|
+
|
|
41
|
+
# 管理后台(可选扩展)
|
|
42
|
+
ADMIN_CONSOLE = "admin_console"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
"ComponentName",
|
|
47
|
+
"MiddlewareName",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""调度器运行模式常量。
|
|
2
|
+
|
|
3
|
+
定义调度器运行模式的枚举。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SchedulerMode(str, Enum):
|
|
12
|
+
"""调度器运行模式枚举(应用层配置)。
|
|
13
|
+
|
|
14
|
+
- EMBEDDED: 伴随 API 运行(默认)
|
|
15
|
+
- STANDALONE: 独立运行
|
|
16
|
+
- DISABLED: 禁用调度器
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
EMBEDDED = "embedded"
|
|
20
|
+
STANDALONE = "standalone"
|
|
21
|
+
DISABLED = "disabled"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"SchedulerMode",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""服务类型常量。
|
|
2
|
+
|
|
3
|
+
定义服务运行模式的枚举。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ServiceType(str, Enum):
|
|
12
|
+
"""服务类型枚举(应用层配置)。
|
|
13
|
+
|
|
14
|
+
用于区分不同的服务运行模式:
|
|
15
|
+
- API: 运行 API 服务(可伴随调度器)
|
|
16
|
+
- WORKER: 运行任务队列 Worker
|
|
17
|
+
- SCHEDULER: 仅运行调度器(独立 pod)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
API = "api"
|
|
21
|
+
WORKER = "worker"
|
|
22
|
+
SCHEDULER = "scheduler"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"ServiceType",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""错误处理系统 - 责任链模式 + Pydantic。
|
|
2
|
+
|
|
3
|
+
提供统一的异常类和错误处理链。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .chain import ErrorHandlerChain, error_handler_chain, global_exception_handler
|
|
7
|
+
from .codes import ErrorCode
|
|
8
|
+
from .exceptions import (
|
|
9
|
+
AlreadyExistsError,
|
|
10
|
+
BaseError,
|
|
11
|
+
BusinessError,
|
|
12
|
+
DatabaseError,
|
|
13
|
+
ForbiddenError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
UnauthorizedError,
|
|
16
|
+
ValidationError,
|
|
17
|
+
VersionConflictError,
|
|
18
|
+
)
|
|
19
|
+
from .handlers import (
|
|
20
|
+
BaseErrorHandler,
|
|
21
|
+
DatabaseErrorHandler,
|
|
22
|
+
ErrorHandler,
|
|
23
|
+
HTTPExceptionHandler,
|
|
24
|
+
ServiceErrorHandler,
|
|
25
|
+
ValidationErrorHandler,
|
|
26
|
+
)
|
|
27
|
+
from .response import ErrorDetail
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"AlreadyExistsError",
|
|
31
|
+
"BaseError",
|
|
32
|
+
"BaseErrorHandler",
|
|
33
|
+
"BusinessError",
|
|
34
|
+
"DatabaseError",
|
|
35
|
+
"DatabaseErrorHandler",
|
|
36
|
+
# 错误代码
|
|
37
|
+
"ErrorCode",
|
|
38
|
+
# 错误模型
|
|
39
|
+
"ErrorDetail",
|
|
40
|
+
# 错误处理器
|
|
41
|
+
"ErrorHandler",
|
|
42
|
+
# 错误处理链
|
|
43
|
+
"ErrorHandlerChain",
|
|
44
|
+
"ForbiddenError",
|
|
45
|
+
"HTTPExceptionHandler",
|
|
46
|
+
"NotFoundError",
|
|
47
|
+
"ServiceErrorHandler",
|
|
48
|
+
"UnauthorizedError",
|
|
49
|
+
"ValidationError",
|
|
50
|
+
"ValidationErrorHandler",
|
|
51
|
+
"VersionConflictError",
|
|
52
|
+
"error_handler_chain",
|
|
53
|
+
"global_exception_handler",
|
|
54
|
+
]
|
|
55
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""错误处理链管理器。
|
|
2
|
+
|
|
3
|
+
提供错误处理链的构建和管理。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fastapi import Request
|
|
7
|
+
from fastapi.responses import JSONResponse
|
|
8
|
+
|
|
9
|
+
from .handlers import (
|
|
10
|
+
BaseErrorHandler,
|
|
11
|
+
DatabaseErrorHandler,
|
|
12
|
+
ErrorHandler,
|
|
13
|
+
HTTPExceptionHandler,
|
|
14
|
+
ServiceErrorHandler,
|
|
15
|
+
ValidationErrorHandler,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ErrorHandlerChain:
|
|
20
|
+
"""错误处理链管理器。"""
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
"""初始化处理链。"""
|
|
24
|
+
self._chain = self._build_chain()
|
|
25
|
+
|
|
26
|
+
def _build_chain(self) -> ErrorHandler:
|
|
27
|
+
"""构建处理链。
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
ErrorHandler: 处理链头部
|
|
31
|
+
"""
|
|
32
|
+
# 按优先级顺序构建处理链
|
|
33
|
+
# 1. BaseErrorHandler - 处理应用层自定义异常
|
|
34
|
+
# 2. ServiceErrorHandler - 处理 Domain 层 ServiceException(业务异常)
|
|
35
|
+
# 3. HTTPExceptionHandler - 处理 FastAPI HTTP 异常
|
|
36
|
+
# 4. ValidationErrorHandler - 处理 Pydantic 验证异常
|
|
37
|
+
# 5. DatabaseErrorHandler - 处理数据库异常(包括 Domain 层其他异常)
|
|
38
|
+
base_handler = BaseErrorHandler()
|
|
39
|
+
service_handler = ServiceErrorHandler()
|
|
40
|
+
http_handler = HTTPExceptionHandler()
|
|
41
|
+
validation_handler = ValidationErrorHandler()
|
|
42
|
+
db_handler = DatabaseErrorHandler()
|
|
43
|
+
|
|
44
|
+
base_handler.set_next(service_handler).set_next(http_handler).set_next(validation_handler).set_next(db_handler)
|
|
45
|
+
|
|
46
|
+
return base_handler
|
|
47
|
+
|
|
48
|
+
async def handle(self, exception: Exception, request: Request) -> JSONResponse:
|
|
49
|
+
"""处理异常。
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
exception: 异常对象
|
|
53
|
+
request: 请求对象
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
JSONResponse: 响应对象
|
|
57
|
+
"""
|
|
58
|
+
return await self._chain.process(exception, request)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 全局异常处理器实例
|
|
62
|
+
error_handler_chain = ErrorHandlerChain()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
|
66
|
+
"""全局异常处理器(FastAPI集成)。
|
|
67
|
+
|
|
68
|
+
使用方式:
|
|
69
|
+
app.add_exception_handler(Exception, global_exception_handler)
|
|
70
|
+
"""
|
|
71
|
+
return await error_handler_chain.handle(exc, request)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
__all__ = [
|
|
75
|
+
"ErrorHandlerChain",
|
|
76
|
+
"error_handler_chain",
|
|
77
|
+
"global_exception_handler",
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""错误代码定义。
|
|
2
|
+
|
|
3
|
+
提供统一的错误代码枚举。
|
|
4
|
+
|
|
5
|
+
**重要提示**:
|
|
6
|
+
Python 的 Enum 不支持继承已有成员的枚举。
|
|
7
|
+
如果你需要扩展错误代码,请使用以下方式之一:
|
|
8
|
+
|
|
9
|
+
方式 1(推荐):创建独立的枚举类
|
|
10
|
+
```python
|
|
11
|
+
class ServiceErrorCode(str, Enum):
|
|
12
|
+
# 服务特定错误代码(5xxx)
|
|
13
|
+
CUSTOM_ERROR = "5000"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
方式 2:使用联合类型
|
|
17
|
+
```python
|
|
18
|
+
ErrorCodeType = ErrorCode | ServiceErrorCode
|
|
19
|
+
```
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from enum import Enum
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ErrorCode(str, Enum):
|
|
28
|
+
"""Foundation Kit 基础错误代码。
|
|
29
|
+
|
|
30
|
+
预留范围:
|
|
31
|
+
- 1xxx: 通用错误
|
|
32
|
+
- 2xxx: 数据库错误
|
|
33
|
+
- 3xxx: 业务错误
|
|
34
|
+
- 4xxx: 外部服务错误
|
|
35
|
+
- 5xxx+: 留给各个服务自定义
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# 通用错误 (1xxx)
|
|
39
|
+
UNKNOWN_ERROR = "1000"
|
|
40
|
+
VALIDATION_ERROR = "1001"
|
|
41
|
+
NOT_FOUND = "1002"
|
|
42
|
+
ALREADY_EXISTS = "1003"
|
|
43
|
+
UNAUTHORIZED = "1004"
|
|
44
|
+
FORBIDDEN = "1005"
|
|
45
|
+
|
|
46
|
+
# 数据库错误 (2xxx)
|
|
47
|
+
DATABASE_ERROR = "2000"
|
|
48
|
+
DUPLICATE_KEY = "2001"
|
|
49
|
+
CONSTRAINT_VIOLATION = "2002"
|
|
50
|
+
VERSION_CONFLICT = "2003" # 乐观锁冲突
|
|
51
|
+
|
|
52
|
+
# 业务错误 (3xxx)
|
|
53
|
+
BUSINESS_ERROR = "3000"
|
|
54
|
+
INVALID_OPERATION = "3001"
|
|
55
|
+
INSUFFICIENT_PERMISSION = "3002"
|
|
56
|
+
|
|
57
|
+
# 外部服务错误 (4xxx)
|
|
58
|
+
EXTERNAL_SERVICE_ERROR = "4000"
|
|
59
|
+
TIMEOUT_ERROR = "4001"
|
|
60
|
+
NETWORK_ERROR = "4002"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
__all__ = [
|
|
64
|
+
"ErrorCode",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""应用层异常类定义。
|
|
2
|
+
|
|
3
|
+
提供应用层业务异常类,用于业务逻辑中抛出异常。
|
|
4
|
+
这些异常会被错误处理器转换为 HTTP 响应。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
from fastapi import status
|
|
12
|
+
|
|
13
|
+
from aury.boot.common.exceptions import FoundationError
|
|
14
|
+
|
|
15
|
+
from .codes import ErrorCode
|
|
16
|
+
from .response import ErrorDetail
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from aury.boot.domain.exceptions import VersionConflictError as DomainVersionConflictError
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseError(FoundationError):
|
|
23
|
+
"""应用层异常基类(用于 HTTP 响应)。
|
|
24
|
+
|
|
25
|
+
所有应用层的异常应继承此类。
|
|
26
|
+
用于 HTTP API 响应,包含错误代码和状态码。
|
|
27
|
+
|
|
28
|
+
继承示例:
|
|
29
|
+
class OrderError(BaseError):
|
|
30
|
+
default_message = "订单错误"
|
|
31
|
+
default_code = "5001" # 自定义错误码
|
|
32
|
+
default_status_code = 400
|
|
33
|
+
|
|
34
|
+
class OrderNotPaidError(OrderError):
|
|
35
|
+
default_message = "订单未支付"
|
|
36
|
+
default_code = "5002"
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
message: 错误消息
|
|
40
|
+
code: 错误代码(字符串或 ErrorCode 枚举)
|
|
41
|
+
status_code: HTTP状态码
|
|
42
|
+
details: 错误详情列表
|
|
43
|
+
metadata: 元数据
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# 类级别默认值,子类可覆盖
|
|
47
|
+
default_message: str = "未知错误"
|
|
48
|
+
default_code: str | ErrorCode = ErrorCode.UNKNOWN_ERROR
|
|
49
|
+
default_status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
message: str | None = None,
|
|
54
|
+
code: str | ErrorCode | None = None,
|
|
55
|
+
status_code: int | None = None,
|
|
56
|
+
details: list[ErrorDetail] | None = None,
|
|
57
|
+
metadata: dict[str, Any] | None = None,
|
|
58
|
+
) -> None:
|
|
59
|
+
"""初始化异常。
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
message: 错误消息(默认使用类的 default_message)
|
|
63
|
+
code: 错误代码(默认使用类的 default_code)
|
|
64
|
+
status_code: HTTP状态码(默认使用类的 default_status_code)
|
|
65
|
+
details: 错误详情
|
|
66
|
+
metadata: 元数据
|
|
67
|
+
"""
|
|
68
|
+
self.message = message or self.default_message
|
|
69
|
+
self.code = code or self.default_code
|
|
70
|
+
self.status_code = status_code or self.default_status_code
|
|
71
|
+
self.details = details or []
|
|
72
|
+
self.metadata = metadata or {}
|
|
73
|
+
super().__init__(self.message)
|
|
74
|
+
|
|
75
|
+
def to_dict(self) -> dict[str, Any]:
|
|
76
|
+
"""转换为字典。"""
|
|
77
|
+
code_value = self.code.value if isinstance(self.code, ErrorCode) else self.code
|
|
78
|
+
return {
|
|
79
|
+
"message": self.message,
|
|
80
|
+
"code": code_value,
|
|
81
|
+
"status_code": self.status_code,
|
|
82
|
+
"details": [detail.model_dump() for detail in self.details],
|
|
83
|
+
"metadata": self.metadata,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
def __repr__(self) -> str:
|
|
87
|
+
"""字符串表示。"""
|
|
88
|
+
code_value = self.code.value if isinstance(self.code, ErrorCode) else self.code
|
|
89
|
+
return f"<{self.__class__.__name__} code={code_value} message={self.message}>"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ValidationError(BaseError):
|
|
93
|
+
"""验证异常。"""
|
|
94
|
+
|
|
95
|
+
default_message = "数据验证失败"
|
|
96
|
+
default_code = ErrorCode.VALIDATION_ERROR
|
|
97
|
+
default_status_code = status.HTTP_400_BAD_REQUEST
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class NotFoundError(BaseError):
|
|
101
|
+
"""资源不存在异常。"""
|
|
102
|
+
|
|
103
|
+
default_message = "资源不存在"
|
|
104
|
+
default_code = ErrorCode.NOT_FOUND
|
|
105
|
+
default_status_code = status.HTTP_404_NOT_FOUND
|
|
106
|
+
|
|
107
|
+
def __init__(
|
|
108
|
+
self,
|
|
109
|
+
message: str | None = None,
|
|
110
|
+
resource: Any = None,
|
|
111
|
+
**kwargs
|
|
112
|
+
) -> None:
|
|
113
|
+
if resource:
|
|
114
|
+
metadata = kwargs.get("metadata", {})
|
|
115
|
+
metadata["resource"] = str(resource)
|
|
116
|
+
kwargs["metadata"] = metadata
|
|
117
|
+
super().__init__(message=message, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class AlreadyExistsError(BaseError):
|
|
121
|
+
"""资源已存在异常。"""
|
|
122
|
+
|
|
123
|
+
default_message = "资源已存在"
|
|
124
|
+
default_code = ErrorCode.ALREADY_EXISTS
|
|
125
|
+
default_status_code = status.HTTP_409_CONFLICT
|
|
126
|
+
|
|
127
|
+
def __init__(
|
|
128
|
+
self,
|
|
129
|
+
message: str | None = None,
|
|
130
|
+
resource: Any = None,
|
|
131
|
+
**kwargs
|
|
132
|
+
) -> None:
|
|
133
|
+
if resource:
|
|
134
|
+
metadata = kwargs.get("metadata", {})
|
|
135
|
+
metadata["resource"] = str(resource)
|
|
136
|
+
kwargs["metadata"] = metadata
|
|
137
|
+
super().__init__(message=message, **kwargs)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class VersionConflictError(BaseError):
|
|
141
|
+
"""版本冲突异常(乐观锁)。
|
|
142
|
+
|
|
143
|
+
当使用 VersionedModel 时,如果更新时版本号不匹配,抛出此异常。
|
|
144
|
+
|
|
145
|
+
注意:此异常继承自 BaseError,用于应用层(HTTP 响应)。
|
|
146
|
+
Domain 层的 VersionConflictError 在 domain.exceptions 中定义。
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
def __init__(
|
|
150
|
+
self,
|
|
151
|
+
message: str = "数据已被其他操作修改,请刷新后重试",
|
|
152
|
+
current_version: int | None = None,
|
|
153
|
+
expected_version: int | None = None,
|
|
154
|
+
**kwargs
|
|
155
|
+
) -> None:
|
|
156
|
+
metadata = kwargs.pop("metadata", {})
|
|
157
|
+
if current_version is not None:
|
|
158
|
+
metadata["current_version"] = current_version
|
|
159
|
+
if expected_version is not None:
|
|
160
|
+
metadata["expected_version"] = expected_version
|
|
161
|
+
|
|
162
|
+
super().__init__(
|
|
163
|
+
message=message,
|
|
164
|
+
code=ErrorCode.VERSION_CONFLICT,
|
|
165
|
+
status_code=status.HTTP_409_CONFLICT,
|
|
166
|
+
metadata=metadata,
|
|
167
|
+
**kwargs
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def from_domain_exception(
|
|
172
|
+
cls,
|
|
173
|
+
exc: DomainVersionConflictError,
|
|
174
|
+
) -> VersionConflictError:
|
|
175
|
+
"""从 Domain 层的 VersionConflictError 创建应用层异常。
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
exc: Domain 层的 VersionConflictError 异常
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
VersionConflictError: 应用层的异常对象
|
|
182
|
+
"""
|
|
183
|
+
from aury.boot.domain.exceptions import VersionConflictError as DomainVersionConflictError
|
|
184
|
+
|
|
185
|
+
if isinstance(exc, DomainVersionConflictError):
|
|
186
|
+
return cls(
|
|
187
|
+
message=exc.message,
|
|
188
|
+
current_version=exc.current_version,
|
|
189
|
+
expected_version=exc.expected_version,
|
|
190
|
+
)
|
|
191
|
+
# 不应该到达这里
|
|
192
|
+
return cls(message=str(exc))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class UnauthorizedError(BaseError):
|
|
196
|
+
"""未授权异常。"""
|
|
197
|
+
|
|
198
|
+
default_message = "未授权访问"
|
|
199
|
+
default_code = ErrorCode.UNAUTHORIZED
|
|
200
|
+
default_status_code = status.HTTP_401_UNAUTHORIZED
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class ForbiddenError(BaseError):
|
|
204
|
+
"""禁止访问异常。"""
|
|
205
|
+
|
|
206
|
+
default_message = "禁止访问"
|
|
207
|
+
default_code = ErrorCode.FORBIDDEN
|
|
208
|
+
default_status_code = status.HTTP_403_FORBIDDEN
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class DatabaseError(BaseError):
|
|
212
|
+
"""数据库异常。"""
|
|
213
|
+
|
|
214
|
+
default_message = "数据库错误"
|
|
215
|
+
default_code = ErrorCode.DATABASE_ERROR
|
|
216
|
+
default_status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class BusinessError(BaseError):
|
|
220
|
+
"""业务逻辑异常。"""
|
|
221
|
+
|
|
222
|
+
default_message = "业务错误"
|
|
223
|
+
default_code = ErrorCode.BUSINESS_ERROR
|
|
224
|
+
default_status_code = status.HTTP_400_BAD_REQUEST
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
__all__ = [
|
|
228
|
+
"AlreadyExistsError",
|
|
229
|
+
"BaseError",
|
|
230
|
+
"BusinessError",
|
|
231
|
+
"DatabaseError",
|
|
232
|
+
"ForbiddenError",
|
|
233
|
+
"NotFoundError",
|
|
234
|
+
"UnauthorizedError",
|
|
235
|
+
"ValidationError",
|
|
236
|
+
"VersionConflictError",
|
|
237
|
+
]
|
|
238
|
+
|