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.
Files changed (138) hide show
  1. aury/boot/__init__.py +66 -0
  2. aury/boot/_version.py +2 -2
  3. aury/boot/application/__init__.py +120 -0
  4. aury/boot/application/app/__init__.py +39 -0
  5. aury/boot/application/app/base.py +511 -0
  6. aury/boot/application/app/components.py +434 -0
  7. aury/boot/application/app/middlewares.py +101 -0
  8. aury/boot/application/config/__init__.py +44 -0
  9. aury/boot/application/config/settings.py +663 -0
  10. aury/boot/application/constants/__init__.py +19 -0
  11. aury/boot/application/constants/components.py +50 -0
  12. aury/boot/application/constants/scheduler.py +28 -0
  13. aury/boot/application/constants/service.py +29 -0
  14. aury/boot/application/errors/__init__.py +55 -0
  15. aury/boot/application/errors/chain.py +80 -0
  16. aury/boot/application/errors/codes.py +67 -0
  17. aury/boot/application/errors/exceptions.py +238 -0
  18. aury/boot/application/errors/handlers.py +320 -0
  19. aury/boot/application/errors/response.py +120 -0
  20. aury/boot/application/interfaces/__init__.py +76 -0
  21. aury/boot/application/interfaces/egress.py +224 -0
  22. aury/boot/application/interfaces/ingress.py +98 -0
  23. aury/boot/application/middleware/__init__.py +22 -0
  24. aury/boot/application/middleware/logging.py +451 -0
  25. aury/boot/application/migrations/__init__.py +13 -0
  26. aury/boot/application/migrations/manager.py +685 -0
  27. aury/boot/application/migrations/setup.py +237 -0
  28. aury/boot/application/rpc/__init__.py +63 -0
  29. aury/boot/application/rpc/base.py +108 -0
  30. aury/boot/application/rpc/client.py +294 -0
  31. aury/boot/application/rpc/discovery.py +218 -0
  32. aury/boot/application/scheduler/__init__.py +13 -0
  33. aury/boot/application/scheduler/runner.py +123 -0
  34. aury/boot/application/server/__init__.py +296 -0
  35. aury/boot/commands/__init__.py +30 -0
  36. aury/boot/commands/add.py +76 -0
  37. aury/boot/commands/app.py +105 -0
  38. aury/boot/commands/config.py +177 -0
  39. aury/boot/commands/docker.py +367 -0
  40. aury/boot/commands/docs.py +284 -0
  41. aury/boot/commands/generate.py +1277 -0
  42. aury/boot/commands/init.py +890 -0
  43. aury/boot/commands/migrate/__init__.py +37 -0
  44. aury/boot/commands/migrate/app.py +54 -0
  45. aury/boot/commands/migrate/commands.py +303 -0
  46. aury/boot/commands/scheduler.py +124 -0
  47. aury/boot/commands/server/__init__.py +21 -0
  48. aury/boot/commands/server/app.py +541 -0
  49. aury/boot/commands/templates/generate/api.py.tpl +105 -0
  50. aury/boot/commands/templates/generate/model.py.tpl +17 -0
  51. aury/boot/commands/templates/generate/repository.py.tpl +19 -0
  52. aury/boot/commands/templates/generate/schema.py.tpl +29 -0
  53. aury/boot/commands/templates/generate/service.py.tpl +48 -0
  54. aury/boot/commands/templates/project/CLI.md.tpl +92 -0
  55. aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +1397 -0
  56. aury/boot/commands/templates/project/README.md.tpl +111 -0
  57. aury/boot/commands/templates/project/admin_console_init.py.tpl +50 -0
  58. aury/boot/commands/templates/project/config.py.tpl +30 -0
  59. aury/boot/commands/templates/project/conftest.py.tpl +26 -0
  60. aury/boot/commands/templates/project/env.example.tpl +213 -0
  61. aury/boot/commands/templates/project/gitignore.tpl +128 -0
  62. aury/boot/commands/templates/project/main.py.tpl +41 -0
  63. aury/boot/commands/templates/project/modules/api.py.tpl +19 -0
  64. aury/boot/commands/templates/project/modules/exceptions.py.tpl +84 -0
  65. aury/boot/commands/templates/project/modules/schedules.py.tpl +18 -0
  66. aury/boot/commands/templates/project/modules/tasks.py.tpl +20 -0
  67. aury/boot/commands/worker.py +143 -0
  68. aury/boot/common/__init__.py +35 -0
  69. aury/boot/common/exceptions/__init__.py +114 -0
  70. aury/boot/common/i18n/__init__.py +16 -0
  71. aury/boot/common/i18n/translator.py +272 -0
  72. aury/boot/common/logging/__init__.py +716 -0
  73. aury/boot/contrib/__init__.py +10 -0
  74. aury/boot/contrib/admin_console/__init__.py +18 -0
  75. aury/boot/contrib/admin_console/auth.py +137 -0
  76. aury/boot/contrib/admin_console/discovery.py +69 -0
  77. aury/boot/contrib/admin_console/install.py +172 -0
  78. aury/boot/contrib/admin_console/utils.py +44 -0
  79. aury/boot/domain/__init__.py +79 -0
  80. aury/boot/domain/exceptions/__init__.py +132 -0
  81. aury/boot/domain/models/__init__.py +51 -0
  82. aury/boot/domain/models/base.py +69 -0
  83. aury/boot/domain/models/mixins.py +135 -0
  84. aury/boot/domain/models/models.py +96 -0
  85. aury/boot/domain/pagination/__init__.py +279 -0
  86. aury/boot/domain/repository/__init__.py +23 -0
  87. aury/boot/domain/repository/impl.py +423 -0
  88. aury/boot/domain/repository/interceptors.py +47 -0
  89. aury/boot/domain/repository/interface.py +106 -0
  90. aury/boot/domain/repository/query_builder.py +348 -0
  91. aury/boot/domain/service/__init__.py +11 -0
  92. aury/boot/domain/service/base.py +73 -0
  93. aury/boot/domain/transaction/__init__.py +404 -0
  94. aury/boot/infrastructure/__init__.py +104 -0
  95. aury/boot/infrastructure/cache/__init__.py +31 -0
  96. aury/boot/infrastructure/cache/backends.py +348 -0
  97. aury/boot/infrastructure/cache/base.py +68 -0
  98. aury/boot/infrastructure/cache/exceptions.py +37 -0
  99. aury/boot/infrastructure/cache/factory.py +94 -0
  100. aury/boot/infrastructure/cache/manager.py +274 -0
  101. aury/boot/infrastructure/database/__init__.py +39 -0
  102. aury/boot/infrastructure/database/config.py +71 -0
  103. aury/boot/infrastructure/database/exceptions.py +44 -0
  104. aury/boot/infrastructure/database/manager.py +317 -0
  105. aury/boot/infrastructure/database/query_tools/__init__.py +164 -0
  106. aury/boot/infrastructure/database/strategies/__init__.py +198 -0
  107. aury/boot/infrastructure/di/__init__.py +15 -0
  108. aury/boot/infrastructure/di/container.py +393 -0
  109. aury/boot/infrastructure/events/__init__.py +33 -0
  110. aury/boot/infrastructure/events/bus.py +362 -0
  111. aury/boot/infrastructure/events/config.py +52 -0
  112. aury/boot/infrastructure/events/consumer.py +134 -0
  113. aury/boot/infrastructure/events/middleware.py +51 -0
  114. aury/boot/infrastructure/events/models.py +63 -0
  115. aury/boot/infrastructure/monitoring/__init__.py +529 -0
  116. aury/boot/infrastructure/scheduler/__init__.py +19 -0
  117. aury/boot/infrastructure/scheduler/exceptions.py +37 -0
  118. aury/boot/infrastructure/scheduler/manager.py +478 -0
  119. aury/boot/infrastructure/storage/__init__.py +38 -0
  120. aury/boot/infrastructure/storage/base.py +164 -0
  121. aury/boot/infrastructure/storage/exceptions.py +37 -0
  122. aury/boot/infrastructure/storage/factory.py +88 -0
  123. aury/boot/infrastructure/tasks/__init__.py +24 -0
  124. aury/boot/infrastructure/tasks/config.py +45 -0
  125. aury/boot/infrastructure/tasks/constants.py +37 -0
  126. aury/boot/infrastructure/tasks/exceptions.py +37 -0
  127. aury/boot/infrastructure/tasks/manager.py +490 -0
  128. aury/boot/testing/__init__.py +24 -0
  129. aury/boot/testing/base.py +122 -0
  130. aury/boot/testing/client.py +163 -0
  131. aury/boot/testing/factory.py +154 -0
  132. aury/boot/toolkit/__init__.py +21 -0
  133. aury/boot/toolkit/http/__init__.py +367 -0
  134. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/METADATA +3 -2
  135. aury_boot-0.0.3.dist-info/RECORD +137 -0
  136. aury_boot-0.0.2.dist-info/RECORD +0 -5
  137. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/WHEEL +0 -0
  138. {aury_boot-0.0.2.dist-info → aury_boot-0.0.3.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,274 @@
1
+ """缓存管理器 - 命名多实例模式。
2
+
3
+ 提供统一的缓存管理接口。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from collections.abc import Callable
9
+ from datetime import timedelta
10
+ from functools import wraps
11
+ import hashlib
12
+ from typing import Any, TypeVar
13
+
14
+ from aury.boot.common.logging import logger
15
+
16
+ # from aury.boot.config import settings # TODO: 需要从应用配置中获取
17
+ from .base import CacheBackend, ICache
18
+ from .factory import CacheFactory
19
+
20
+
21
+ class CacheManager:
22
+ """缓存管理器(命名多实例)。
23
+
24
+ 类似Flask-Cache的API设计,优雅简洁。
25
+ 支持多个命名实例,如不同的 Redis 实例或缓存策略。
26
+
27
+ 使用示例:
28
+ # 默认实例
29
+ cache = CacheManager.get_instance()
30
+ await cache.init_app({
31
+ "CACHE_TYPE": "redis",
32
+ "CACHE_URL": "redis://localhost:6379"
33
+ })
34
+
35
+ # 命名实例
36
+ session_cache = CacheManager.get_instance("session")
37
+ rate_limit_cache = CacheManager.get_instance("rate_limit")
38
+
39
+ # 使用
40
+ await cache.set("key", "value", expire=60)
41
+ value = await cache.get("key")
42
+ """
43
+
44
+ _instances: dict[str, CacheManager] = {}
45
+
46
+ def __init__(self, name: str = "default") -> None:
47
+ """初始化缓存管理器。
48
+
49
+ Args:
50
+ name: 实例名称
51
+ """
52
+ self.name = name
53
+ self._backend: ICache | None = None
54
+ self._config: dict[str, Any] = {}
55
+
56
+ @classmethod
57
+ def get_instance(cls, name: str = "default") -> CacheManager:
58
+ """获取指定名称的实例。
59
+
60
+ Args:
61
+ name: 实例名称,默认为 "default"
62
+
63
+ Returns:
64
+ CacheManager: 缓存管理器实例
65
+ """
66
+ if name not in cls._instances:
67
+ cls._instances[name] = cls(name)
68
+ return cls._instances[name]
69
+
70
+ @classmethod
71
+ def reset_instance(cls, name: str | None = None) -> None:
72
+ """重置实例(仅用于测试)。
73
+
74
+ Args:
75
+ name: 要重置的实例名称。如果为 None,则重置所有实例。
76
+
77
+ 注意:调用此方法前应先调用 cleanup() 释放资源。
78
+ """
79
+ if name is None:
80
+ cls._instances.clear()
81
+ elif name in cls._instances:
82
+ del cls._instances[name]
83
+
84
+ async def init_app(self, config: dict[str, Any]) -> None:
85
+ """初始化缓存(类似Flask-Cache)。
86
+
87
+ Args:
88
+ config: 配置字典
89
+ - CACHE_TYPE: 缓存类型(redis/memory/memcached)
90
+ - CACHE_URL: 缓存服务 URL(通用)
91
+ - CACHE_MAX_SIZE: 内存缓存最大容量
92
+ - CACHE_SERIALIZER: 序列化方式(json/pickle)
93
+ """
94
+ self._config = config.copy()
95
+ cache_type = config.get("CACHE_TYPE", "redis")
96
+
97
+ # 构建后端配置
98
+ backend_config = self._build_backend_config(cache_type, config)
99
+
100
+ # 使用工厂创建后端
101
+ self._backend = await CacheFactory.create(cache_type, **backend_config)
102
+ logger.info(f"缓存管理器初始化完成: {cache_type}")
103
+
104
+ def _build_backend_config(self, cache_type: str, config: dict[str, Any]) -> dict[str, Any]:
105
+ """构建后端配置。
106
+
107
+ 使用函数式编程处理配置构建逻辑。
108
+ """
109
+ # 配置构建函数字典(函数式编程)
110
+ config_builders: dict[str, Callable[[dict[str, Any]], dict[str, Any]]] = {
111
+ "redis": lambda cfg: {
112
+ "url": cfg.get("CACHE_URL"),
113
+ "serializer": cfg.get("CACHE_SERIALIZER", "json"),
114
+ },
115
+ "memory": lambda cfg: {
116
+ "max_size": cfg.get("CACHE_MAX_SIZE", 1000),
117
+ },
118
+ "memcached": lambda cfg: {
119
+ "servers": cfg.get("CACHE_URL"), # memcached 也用 URL
120
+ },
121
+ }
122
+
123
+ if cache_type not in config_builders:
124
+ available = ", ".join(config_builders.keys())
125
+ raise ValueError(
126
+ f"不支持的缓存类型: {cache_type}。可用类型: {available}"
127
+ )
128
+
129
+ builder = config_builders[cache_type]
130
+ backend_config = builder(config)
131
+
132
+ # 验证必需配置
133
+ if cache_type == "redis" and not backend_config.get("url"):
134
+ raise ValueError("缓存 URL 未配置,请设置 CACHE_URL")
135
+ if cache_type == "memcached" and not backend_config.get("servers"):
136
+ raise ValueError("缓存 URL 未配置,请设置 CACHE_URL")
137
+
138
+ return backend_config
139
+
140
+ async def initialize(
141
+ self,
142
+ backend: CacheBackend = CacheBackend.REDIS,
143
+ *,
144
+ url: str | None = None,
145
+ max_size: int = 1000,
146
+ serializer: str = "json",
147
+ servers: list[str] | None = None,
148
+ ) -> None:
149
+ """初始化缓存。
150
+
151
+ Args:
152
+ backend: 缓存后端类型
153
+ url: Redis连接URL
154
+ max_size: 最大缓存项数
155
+ serializer: 序列化方式
156
+ servers: Memcached服务器列表
157
+ """
158
+ # 转换为配置字典(使用函数式编程)
159
+ backend_config_map: dict[CacheBackend, Callable[[], dict[str, Any]]] = {
160
+ CacheBackend.REDIS: lambda: {
161
+ "CACHE_TYPE": backend.value,
162
+ "CACHE_REDIS_URL": url, # TODO: 从应用配置中获取默认值
163
+ "CACHE_SERIALIZER": serializer,
164
+ },
165
+ CacheBackend.MEMORY: lambda: {
166
+ "CACHE_TYPE": backend.value,
167
+ "CACHE_MAX_SIZE": max_size,
168
+ },
169
+ CacheBackend.MEMCACHED: lambda: {
170
+ "CACHE_TYPE": backend.value,
171
+ "CACHE_MEMCACHED_SERVERS": servers,
172
+ },
173
+ }
174
+
175
+ config_builder = backend_config_map.get(backend)
176
+ if config_builder is None:
177
+ raise ValueError(f"不支持的缓存后端: {backend}")
178
+
179
+ config = config_builder()
180
+ await self.init_app(config)
181
+
182
+ @property
183
+ def backend(self) -> ICache:
184
+ """获取缓存后端。"""
185
+ if self._backend is None:
186
+ raise RuntimeError("缓存管理器未初始化,请先调用 init_app() 或 initialize()")
187
+ return self._backend
188
+
189
+ @property
190
+ def backend_type(self) -> str:
191
+ """获取当前使用的后端类型。"""
192
+ return self._config.get("CACHE_TYPE", "unknown")
193
+
194
+ async def get(self, key: str, default: Any = None) -> Any:
195
+ """获取缓存。"""
196
+ return await self.backend.get(key, default)
197
+
198
+ async def set(
199
+ self,
200
+ key: str,
201
+ value: Any,
202
+ expire: int | timedelta | None = None,
203
+ ) -> bool:
204
+ """设置缓存。"""
205
+ return await self.backend.set(key, value, expire)
206
+
207
+ async def delete(self, *keys: str) -> int:
208
+ """删除缓存。"""
209
+ return await self.backend.delete(*keys)
210
+
211
+ async def exists(self, *keys: str) -> int:
212
+ """检查缓存是否存在。"""
213
+ return await self.backend.exists(*keys)
214
+
215
+ async def clear(self) -> None:
216
+ """清空所有缓存。"""
217
+ await self.backend.clear()
218
+
219
+ def cached[T](
220
+ self,
221
+ expire: int | timedelta | None = None,
222
+ *,
223
+ key_prefix: str = "",
224
+ ) -> Callable[[Callable[..., T]], Callable[..., T]]:
225
+ """缓存装饰器。
226
+
227
+ Args:
228
+ expire: 过期时间
229
+ key_prefix: 键前缀
230
+ """
231
+ def decorator(func: Callable[..., T]) -> Callable[..., T]:
232
+ @wraps(func)
233
+ async def wrapper(*args, **kwargs) -> T:
234
+ # 生成缓存键
235
+ func_name = f"{func.__module__}.{func.__name__}"
236
+ args_str = str(args) + str(sorted(kwargs.items()))
237
+ key_hash = hashlib.md5(args_str.encode()).hexdigest()[:8]
238
+ cache_key = f"{key_prefix}:{func_name}:{key_hash}" if key_prefix else f"{func_name}:{key_hash}"
239
+
240
+ # 尝试获取缓存
241
+ cached_value = await self.get(cache_key)
242
+ if cached_value is not None:
243
+ logger.debug(f"缓存命中: {cache_key}")
244
+ return cached_value
245
+
246
+ # 执行函数
247
+ result = await func(*args, **kwargs)
248
+
249
+ # 存入缓存
250
+ await self.set(cache_key, result, expire)
251
+ logger.debug(f"缓存更新: {cache_key}")
252
+
253
+ return result
254
+
255
+ return wrapper
256
+ return decorator
257
+
258
+ async def cleanup(self) -> None:
259
+ """清理资源。"""
260
+ if self._backend:
261
+ await self._backend.close()
262
+ self._backend = None
263
+ logger.info("缓存管理器已清理")
264
+
265
+ def __repr__(self) -> str:
266
+ """字符串表示。"""
267
+ backend_name = self.backend_type if self._backend else "未初始化"
268
+ return f"<CacheManager backend={backend_name}>"
269
+
270
+
271
+ __all__ = [
272
+ "CacheManager",
273
+ ]
274
+
@@ -0,0 +1,39 @@
1
+ """数据库管理模块。
2
+
3
+ 提供统一的数据库连接管理、会话创建、健康检查、UPSERT策略和查询优化。
4
+ """
5
+
6
+ from .exceptions import (
7
+ DatabaseConnectionError,
8
+ DatabaseError,
9
+ DatabaseQueryError,
10
+ DatabaseTransactionError,
11
+ )
12
+ from .manager import DatabaseManager
13
+ from .query_tools import cache_query, monitor_query
14
+ from .strategies import (
15
+ MySQLUpsertStrategy,
16
+ PostgreSQLUpsertStrategy,
17
+ SQLiteUpsertStrategy,
18
+ UpsertStrategy,
19
+ UpsertStrategyFactory,
20
+ )
21
+
22
+ __all__ = [
23
+ # 异常
24
+ "DatabaseConnectionError",
25
+ "DatabaseError",
26
+ "DatabaseManager",
27
+ "DatabaseQueryError",
28
+ "DatabaseTransactionError",
29
+ # UPSERT 策略
30
+ "MySQLUpsertStrategy",
31
+ "PostgreSQLUpsertStrategy",
32
+ "SQLiteUpsertStrategy",
33
+ "UpsertStrategy",
34
+ "UpsertStrategyFactory",
35
+ # 查询优化
36
+ "cache_query",
37
+ "monitor_query",
38
+ ]
39
+
@@ -0,0 +1,71 @@
1
+ """数据库配置。
2
+
3
+ Infrastructure 层配置,不依赖 application 层。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from pydantic import Field
9
+ from pydantic_settings import BaseSettings, SettingsConfigDict
10
+
11
+
12
+ # 支持的事务隔离级别
13
+ ISOLATION_LEVELS = (
14
+ "READ UNCOMMITTED",
15
+ "READ COMMITTED",
16
+ "REPEATABLE READ",
17
+ "SERIALIZABLE",
18
+ "AUTOCOMMIT",
19
+ )
20
+
21
+
22
+ class DatabaseConfig(BaseSettings):
23
+ """数据库基础设施配置。
24
+
25
+ Infrastructure 层直接使用的数据库配置。
26
+
27
+ 环境变量前缀: DATABASE_
28
+ 示例: DATABASE_URL, DATABASE_ECHO, DATABASE_POOL_SIZE
29
+ """
30
+
31
+ url: str = Field(
32
+ description="数据库连接URL(支持所有 SQLAlchemy 支持的数据库),必需配置"
33
+ )
34
+ echo: bool = Field(
35
+ default=False,
36
+ description="是否打印SQL语句"
37
+ )
38
+ pool_size: int = Field(
39
+ default=5,
40
+ description="连接池大小"
41
+ )
42
+ max_overflow: int = Field(
43
+ default=10,
44
+ description="最大溢出连接数"
45
+ )
46
+ pool_timeout: int = Field(
47
+ default=30,
48
+ description="连接超时时间(秒)"
49
+ )
50
+ pool_recycle: int = Field(
51
+ default=1800,
52
+ description="连接回收时间(秒)"
53
+ )
54
+ isolation_level: str | None = Field(
55
+ default=None,
56
+ description="事务隔离级别: READ UNCOMMITTED / READ COMMITTED / REPEATABLE READ / SERIALIZABLE / AUTOCOMMIT"
57
+ )
58
+
59
+ model_config = SettingsConfigDict(
60
+ env_prefix="DATABASE_",
61
+ case_sensitive=False,
62
+ )
63
+
64
+
65
+ __all__ = [
66
+ "DatabaseConfig",
67
+ "ISOLATION_LEVELS",
68
+ ]
69
+
70
+
71
+
@@ -0,0 +1,44 @@
1
+ """数据库相关异常定义。
2
+
3
+ Infrastructure 层异常,继承自 FoundationError。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from aury.boot.common.exceptions import FoundationError
9
+
10
+
11
+ class DatabaseError(FoundationError):
12
+ """数据库相关错误基类。
13
+
14
+ 所有数据库相关的异常都应该继承此类。
15
+ """
16
+
17
+ pass
18
+
19
+
20
+ class DatabaseConnectionError(DatabaseError):
21
+ """数据库连接错误。"""
22
+
23
+ pass
24
+
25
+
26
+ class DatabaseQueryError(DatabaseError):
27
+ """数据库查询错误。"""
28
+
29
+ pass
30
+
31
+
32
+ class DatabaseTransactionError(DatabaseError):
33
+ """数据库事务错误。"""
34
+
35
+ pass
36
+
37
+
38
+ __all__ = [
39
+ "DatabaseConnectionError",
40
+ "DatabaseError",
41
+ "DatabaseQueryError",
42
+ "DatabaseTransactionError",
43
+ ]
44
+