fastapi-augment 0.1.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.
Files changed (50) hide show
  1. fastapi_augment/__init__.py +24 -0
  2. fastapi_augment/common/__init__.py +61 -0
  3. fastapi_augment/common/constants.py +26 -0
  4. fastapi_augment/common/exception_handlers.py +178 -0
  5. fastapi_augment/common/exceptions.py +162 -0
  6. fastapi_augment/common/utils/__init__.py +5 -0
  7. fastapi_augment/common/utils/strings.py +175 -0
  8. fastapi_augment/config/__init__.py +8 -0
  9. fastapi_augment/config/settings.py +104 -0
  10. fastapi_augment/db/__init__.py +5 -0
  11. fastapi_augment/db/sqlalchemy/__init__.py +20 -0
  12. fastapi_augment/db/sqlalchemy/alembic/__init__.py +5 -0
  13. fastapi_augment/db/sqlalchemy/alembic/env.py +141 -0
  14. fastapi_augment/db/sqlalchemy/base.py +9 -0
  15. fastapi_augment/db/sqlalchemy/crud_base.py +426 -0
  16. fastapi_augment/db/sqlalchemy/engine.py +238 -0
  17. fastapi_augment/db/sqlalchemy/migrate.py +356 -0
  18. fastapi_augment/db/sqlalchemy/mixins/__init__.py +18 -0
  19. fastapi_augment/db/sqlalchemy/mixins/audit.py +61 -0
  20. fastapi_augment/db/sqlalchemy/mixins/soft_delete.py +80 -0
  21. fastapi_augment/db/sqlalchemy/mixins/timestamp.py +48 -0
  22. fastapi_augment/db/sqlalchemy/model_base.py +47 -0
  23. fastapi_augment/db/sqlalchemy/session.py +160 -0
  24. fastapi_augment/factory.py +238 -0
  25. fastapi_augment/health/__init__.py +34 -0
  26. fastapi_augment/health/checker.py +101 -0
  27. fastapi_augment/health/checkers.py +109 -0
  28. fastapi_augment/health/router.py +87 -0
  29. fastapi_augment/lifespan.py +450 -0
  30. fastapi_augment/log/__init__.py +26 -0
  31. fastapi_augment/log/config.py +201 -0
  32. fastapi_augment/log/factory.py +32 -0
  33. fastapi_augment/log/filters.py +23 -0
  34. fastapi_augment/log/handlers.py +81 -0
  35. fastapi_augment/middlewares/__init__.py +20 -0
  36. fastapi_augment/middlewares/base.py +79 -0
  37. fastapi_augment/middlewares/request_id.py +82 -0
  38. fastapi_augment/openapi.py +110 -0
  39. fastapi_augment/py.typed +0 -0
  40. fastapi_augment/schemas/__init__.py +29 -0
  41. fastapi_augment/schemas/base.py +32 -0
  42. fastapi_augment/schemas/pagination.py +46 -0
  43. fastapi_augment/schemas/request.py +28 -0
  44. fastapi_augment/schemas/response.py +139 -0
  45. fastapi_augment/schemas/types.py +11 -0
  46. fastapi_augment-0.1.0.dist-info/METADATA +654 -0
  47. fastapi_augment-0.1.0.dist-info/RECORD +50 -0
  48. fastapi_augment-0.1.0.dist-info/WHEEL +5 -0
  49. fastapi_augment-0.1.0.dist-info/entry_points.txt +2 -0
  50. fastapi_augment-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,46 @@
1
+ """
2
+ @Author : hangu
3
+ @CreateDate : 2026/9/1
4
+ @Description : 分页响应模型 PageData,对外输出,继承APISchemaBase
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from math import ceil
9
+ from typing import Generic, Sequence
10
+
11
+ from pydantic import Field
12
+
13
+ from .base import SchemaBase
14
+ from .types import T
15
+
16
+
17
+ class PageData(SchemaBase, Generic[T]):
18
+ """通用分页返回体"""
19
+ items: Sequence[T] = Field(default_factory=list, description='当前页数据列表')
20
+ page: int = Field(default=1, description='当前页码')
21
+ size: int = Field(default=10, description='每页数量')
22
+ pages: int = Field(default=0, description='总页数')
23
+ total: int = Field(default=0, description='总记录数')
24
+
25
+ @classmethod
26
+ def build(
27
+ cls,
28
+ items: list[T] | Sequence[T],
29
+ *,
30
+ page: int,
31
+ size: int,
32
+ total: int
33
+ ) -> 'PageData[T]':
34
+ """构建分页对象,自动计算总页数
35
+
36
+ Args:
37
+ items: 当前页数据列表
38
+ page: 当前页码
39
+ size: 每页数量
40
+ total: 总记录数
41
+
42
+ Returns:
43
+ 分页对象
44
+ """
45
+ pages = ceil(total / size) if size > 0 else 0
46
+ return cls(items=items, page=page, size=size, pages=pages, total=total)
@@ -0,0 +1,28 @@
1
+ """
2
+ @Author : hangu
3
+ @CreateDate : 2026/9/1
4
+ @Description : 请求参数定义
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from datetime import datetime
9
+ from pydantic import Field
10
+
11
+ from .base import SchemaBase
12
+
13
+
14
+ class PageParams(SchemaBase):
15
+ """通用分页请求参数"""
16
+ page: int = Field(default=1, description='当前页码', ge=1)
17
+ size: int = Field(default=100, description='每页数量', ge=1, le=1000)
18
+
19
+
20
+ class TimeRangeParams(SchemaBase):
21
+ """通用时间范围查询参数"""
22
+ start_time: datetime | None = Field(default=None, description='开始时间')
23
+ end_time: datetime | None = Field(default=None, description='结束时间')
24
+
25
+
26
+ class KeywordParams(SchemaBase):
27
+ """通用关键字搜索参数"""
28
+ keyword: str | None = Field(default=None, description='搜索关键字', max_length=100)
@@ -0,0 +1,139 @@
1
+ """
2
+ @Author : hangu
3
+ @CreateDate : 2026/9/1
4
+ @Description : 统一API响应模型与工厂函数
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from typing import Generic, overload
9
+
10
+ from pydantic import Field
11
+
12
+ from .base import SchemaBase
13
+ from .types import T, E
14
+
15
+ CODE_SUCCESS = 0
16
+
17
+ # ====================== request_id 默认值 ======================
18
+ def _default_request_id() -> str:
19
+ """获取当前请求ID,无请求上下文返回空字符串
20
+
21
+ Returns:
22
+ 请求ID
23
+ """
24
+ # 延迟导入,避免循环依赖
25
+ from ..middlewares import get_request_id
26
+ return get_request_id() or ''
27
+
28
+
29
+ # ====================== API响应模型 ======================
30
+ class APIResponse(SchemaBase, Generic[T, E]):
31
+ """全局统一返回格式
32
+
33
+ request_id: 自动从 ContextVar 获取当前请求ID;无请求上下文返回空字符串
34
+ """
35
+ request_id: str = Field(default_factory=_default_request_id, description='请求唯一追踪ID')
36
+ code: int = Field(default=CODE_SUCCESS, description='业务码,0代表成功')
37
+ message: str = Field(default='操作成功', description='提示文案')
38
+ data: T | None = Field(default=None, description='业务主体数据')
39
+ extra: E | None = Field(default=None, description='扩展附加信息')
40
+
41
+
42
+ # ====================== 工厂函数 overload 重载,优化IDE泛型推导 ======================
43
+ @overload
44
+ def build_response(*, code: int = CODE_SUCCESS, message: str = '操作成功') -> APIResponse[None, None]: ...
45
+
46
+
47
+ @overload
48
+ def build_response(*, code: int = CODE_SUCCESS, message: str = '操作成功', data: T) -> APIResponse[T, None]: ...
49
+
50
+
51
+ @overload
52
+ def build_response(*, code: int = CODE_SUCCESS, message: str = '操作成功', extra: E) -> APIResponse[None, E]: ...
53
+
54
+
55
+ @overload
56
+ def build_response(*, code: int = CODE_SUCCESS, message: str = '操作成功', data: T, extra: E) -> APIResponse[T, E]: ...
57
+
58
+
59
+ def build_response(
60
+ *,
61
+ code: int = CODE_SUCCESS,
62
+ message: str = '操作成功',
63
+ data: T | None = None,
64
+ extra: E | None = None,
65
+ ) -> APIResponse[T, E]:
66
+ """底层构建响应,优先使用 response_success / response_fail
67
+
68
+ Args:
69
+ code: 业务码,0代表成功
70
+ message: 提示文案
71
+ data: 业务主体数据
72
+ extra: 扩展附加信息
73
+
74
+ Returns:
75
+ APIResponse[T, E]
76
+ """
77
+ return APIResponse(code=code, message=message, data=data, extra=extra)
78
+
79
+
80
+ @overload
81
+ def response_success(*, message: str = '操作成功') -> APIResponse[None, None]: ...
82
+
83
+
84
+ @overload
85
+ def response_success(*, message: str = '操作成功', data: T) -> APIResponse[T, None]: ...
86
+
87
+
88
+ @overload
89
+ def response_success(*, message: str = '操作成功', extra: E) -> APIResponse[None, E]: ...
90
+
91
+
92
+ @overload
93
+ def response_success(*, message: str = '操作成功', data: T, extra: E) -> APIResponse[T, E]: ...
94
+
95
+
96
+ def response_success(
97
+ *,
98
+ message: str = '操作成功',
99
+ data: T | None = None,
100
+ extra: E | None = None,
101
+ ) -> APIResponse[T, E]:
102
+ """构造成功响应
103
+
104
+ Args:
105
+ message: 提示文案
106
+ data: 业务主体数据
107
+ extra: 扩展附加信息
108
+
109
+ Returns:
110
+ APIResponse[T, E]
111
+ """
112
+ return build_response(code=CODE_SUCCESS, message=message, data=data, extra=extra)
113
+
114
+
115
+ @overload
116
+ def response_fail(*, code: int, message: str = '操作失败') -> APIResponse[None, None]: ...
117
+
118
+
119
+ @overload
120
+ def response_fail(*, code: int, message: str = '操作失败', extra: E) -> APIResponse[None, E]: ...
121
+
122
+
123
+ def response_fail(
124
+ *,
125
+ code: int,
126
+ message: str = '操作失败',
127
+ extra: E | None = None,
128
+ ) -> APIResponse[None, E]:
129
+ """构造失败响应,给业务代码 & fastapi_handlers异常处理器使用
130
+
131
+ Args:
132
+ code: 业务码,0代表成功
133
+ message: 提示文案
134
+ extra: 扩展附加信息
135
+
136
+ Returns:
137
+ APIResponse[None, E]
138
+ """
139
+ return build_response(code=code, message=message, extra=extra)
@@ -0,0 +1,11 @@
1
+ """
2
+ @Author : hangu
3
+ @CreateDate : 2026/9/1
4
+ @Description : 泛型类型变量定义
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from typing import TypeVar
9
+
10
+ T = TypeVar('T')
11
+ E = TypeVar('E') # 扩展结构体