springbootAI 1.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.
Files changed (175) hide show
  1. spring/__init__.py +66 -0
  2. spring/ai/__init__.py +78 -0
  3. spring/ai/advisors.py +139 -0
  4. spring/ai/annotations.py +74 -0
  5. spring/ai/autoconfig.py +481 -0
  6. spring/ai/core.py +391 -0
  7. spring/ai/etl.py +188 -0
  8. spring/ai/memory.py +109 -0
  9. spring/ai/observability.py +129 -0
  10. spring/ai/providers.py +789 -0
  11. spring/ai/resilience.py +258 -0
  12. spring/ai/tools.py +106 -0
  13. spring/ai/vectorstore.py +303 -0
  14. spring/annotations/__init__.py +188 -0
  15. spring/annotations/cache.py +126 -0
  16. spring/annotations/cloud.py +207 -0
  17. spring/annotations/conditional.py +272 -0
  18. spring/annotations/core.py +864 -0
  19. spring/annotations/messaging.py +107 -0
  20. spring/aop/__init__.py +4 -0
  21. spring/aop/cloud_aop.py +404 -0
  22. spring/aop/comprehensive_aop.py +1015 -0
  23. spring/aop/method_interceptor.py +19 -0
  24. spring/aop/proxy_factory.py +55 -0
  25. spring/cloud/__init__.py +76 -0
  26. spring/cloud/discovery.py +364 -0
  27. spring/cloud/feign.py +469 -0
  28. spring/cloud/gateway.py +452 -0
  29. spring/cloud/load_balancer.py +149 -0
  30. spring/cloud/seata.py +557 -0
  31. spring/cloud/sentinel.py +525 -0
  32. spring/cloud/tracer.py +337 -0
  33. spring/config/__init__.py +21 -0
  34. spring/config/binding.py +206 -0
  35. spring/config/config_loader.py +405 -0
  36. spring/context/__init__.py +13 -0
  37. spring/context/application_context.py +589 -0
  38. spring/context/bean_definition.py +70 -0
  39. spring/context/bean_factory.py +1052 -0
  40. spring/context/registry.py +58 -0
  41. spring/context/scanner.py +106 -0
  42. spring/core/__init__.py +3 -0
  43. spring/core/graceful_shutdown.py +196 -0
  44. spring/core/typing_utils.py +50 -0
  45. spring/csv/__init__.py +52 -0
  46. spring/csv/annotations.py +402 -0
  47. spring/csv/converters.py +69 -0
  48. spring/csv/easy_csv.py +95 -0
  49. spring/csv/exceptions.py +27 -0
  50. spring/csv/reader.py +195 -0
  51. spring/csv/writer.py +155 -0
  52. spring/data/__init__.py +54 -0
  53. spring/data/page.py +181 -0
  54. spring/data/repository.py +274 -0
  55. spring/data/specification.py +228 -0
  56. spring/datasource/__init__.py +66 -0
  57. spring/datasource/annotations.py +133 -0
  58. spring/datasource/context.py +69 -0
  59. spring/datasource/dynamic.py +148 -0
  60. spring/event/__init__.py +7 -0
  61. spring/event/publisher.py +69 -0
  62. spring/excel/__init__.py +51 -0
  63. spring/excel/annotations.py +405 -0
  64. spring/excel/converters.py +231 -0
  65. spring/excel/easy_excel.py +94 -0
  66. spring/excel/exceptions.py +31 -0
  67. spring/excel/reader.py +254 -0
  68. spring/excel/style.py +95 -0
  69. spring/excel/writer.py +197 -0
  70. spring/i18n/__init__.py +97 -0
  71. spring/i18n/accessor.py +94 -0
  72. spring/i18n/auto_config.py +177 -0
  73. spring/i18n/holder.py +106 -0
  74. spring/i18n/locale.py +152 -0
  75. spring/i18n/locale_resolver.py +367 -0
  76. spring/i18n/message_source.py +250 -0
  77. spring/i18n/middleware.py +79 -0
  78. spring/i18n/properties.py +168 -0
  79. spring/i18n/sources.py +255 -0
  80. spring/logging/__init__.py +1 -0
  81. spring/logging/loguru_logger.py +228 -0
  82. spring/main.py +378 -0
  83. spring/messaging/__init__.py +1 -0
  84. spring/messaging/rabbitmq.py +302 -0
  85. spring/monitoring/__init__.py +1 -0
  86. spring/monitoring/prometheus.py +199 -0
  87. spring/orm/__init__.py +258 -0
  88. spring/orm/database.py +222 -0
  89. spring/orm/ddl_auto.py +1217 -0
  90. spring/orm/migration.py +419 -0
  91. spring/orm/mybatis_integration.py +400 -0
  92. spring/orm/pymybatis/__init__.py +86 -0
  93. spring/orm/pymybatis/annotations/__init__.py +30 -0
  94. spring/orm/pymybatis/annotations/annotations.py +332 -0
  95. spring/orm/pymybatis/cache/__init__.py +47 -0
  96. spring/orm/pymybatis/cache/cache.py +371 -0
  97. spring/orm/pymybatis/cache/redis_cache.py +434 -0
  98. spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
  99. spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
  100. spring/orm/pymybatis/configuration.py +525 -0
  101. spring/orm/pymybatis/core/__init__.py +10 -0
  102. spring/orm/pymybatis/core/sql_session.py +1382 -0
  103. spring/orm/pymybatis/core/sql_session_factory.py +76 -0
  104. spring/orm/pymybatis/dialect/__init__.py +9 -0
  105. spring/orm/pymybatis/dialect/dialect.py +445 -0
  106. spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
  107. spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
  108. spring/orm/pymybatis/interceptor/__init__.py +31 -0
  109. spring/orm/pymybatis/interceptor/interceptor.py +427 -0
  110. spring/orm/pymybatis/mapper/__init__.py +9 -0
  111. spring/orm/pymybatis/mapper/mapper.py +540 -0
  112. spring/orm/pymybatis/metrics/__init__.py +41 -0
  113. spring/orm/pymybatis/metrics/metrics.py +595 -0
  114. spring/orm/pymybatis/pool/__init__.py +9 -0
  115. spring/orm/pymybatis/pool/connection_pool.py +711 -0
  116. spring/orm/pymybatis/security/__init__.py +19 -0
  117. spring/orm/pymybatis/security/access_control.py +415 -0
  118. spring/orm/pymybatis/security/password_encoder.py +293 -0
  119. spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
  120. spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
  121. spring/orm/pymybatis/transaction/__init__.py +9 -0
  122. spring/orm/pymybatis/transaction/transaction.py +288 -0
  123. spring/orm/pymybatis/type_handler/__init__.py +37 -0
  124. spring/orm/pymybatis/type_handler/type_handler.py +473 -0
  125. spring/orm/pymybatis/version.py +9 -0
  126. spring/orm/pymybatis/xml_parser/__init__.py +9 -0
  127. spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
  128. spring/retry/__init__.py +12 -0
  129. spring/retry/retry_annotations.py +71 -0
  130. spring/retry/retry_decorator.py +155 -0
  131. spring/scheduling/__init__.py +3 -0
  132. spring/scheduling/scheduler.py +389 -0
  133. spring/security/__init__.py +39 -0
  134. spring/security/jwt_utils.py +281 -0
  135. spring/security/replay_protection.py +206 -0
  136. spring/security/secret_manager.py +226 -0
  137. spring/security/security_aop.py +248 -0
  138. spring/security/security_context.py +172 -0
  139. spring/test/__init__.py +45 -0
  140. spring/test/slicing.py +341 -0
  141. spring/tracing/__init__.py +11 -0
  142. spring/tracing/skywalking.py +229 -0
  143. spring/tx/__init__.py +52 -0
  144. spring/tx/events.py +172 -0
  145. spring/tx/synchronization.py +143 -0
  146. spring/utils/__init__.py +5 -0
  147. spring/utils/banner.py +32 -0
  148. spring/utils/logger.py +73 -0
  149. spring/utils/redis_client.py +526 -0
  150. spring/validation/__init__.py +55 -0
  151. spring/validation/aop.py +141 -0
  152. spring/validation/constraints.py +357 -0
  153. spring/validation/exceptions.py +55 -0
  154. spring/validation/validator.py +139 -0
  155. spring/web/__init__.py +12 -0
  156. spring/web/actuator.py +319 -0
  157. spring/web/exception_handler.py +61 -0
  158. spring/web/health.py +399 -0
  159. spring/web/interceptor.py +91 -0
  160. spring/web/result.py +44 -0
  161. spring/web/swagger.py +601 -0
  162. spring/web/web_context.py +755 -0
  163. spring/websocket/__init__.py +86 -0
  164. spring/websocket/annotations.py +169 -0
  165. spring/websocket/broker.py +238 -0
  166. spring/websocket/exceptions.py +26 -0
  167. spring/websocket/handler.py +243 -0
  168. spring/websocket/router.py +526 -0
  169. spring/websocket/session.py +216 -0
  170. springbootai-1.8.0.dist-info/METADATA +2796 -0
  171. springbootai-1.8.0.dist-info/RECORD +175 -0
  172. springbootai-1.8.0.dist-info/WHEEL +5 -0
  173. springbootai-1.8.0.dist-info/entry_points.txt +2 -0
  174. springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
  175. springbootai-1.8.0.dist-info/top_level.txt +1 -0
spring/tx/events.py ADDED
@@ -0,0 +1,172 @@
1
+ """事务事件监听(对齐 Spring ``@TransactionalEventListener`` + ``TransactionalEventPublisher``)。
2
+
3
+ ``@TransactionalEventListener(phase=...)`` 标记的监听器在事务达到指定阶段时才触发:
4
+ - ``BEFORE_COMMIT``:事务提交前
5
+ - ``AFTER_COMMIT``:事务提交后(默认)
6
+ - ``AFTER_ROLLBACK``:事务回滚后
7
+ - ``AFTER_COMPLETION``:事务完成后(提交或回滚)
8
+
9
+ 设计:
10
+ - **事件延迟**:``TransactionalEventPublisher.publish_event`` 发布事件时,若当前存在活动事务,
11
+ 把事务监听器包装为 ``TransactionSynchronization`` 注册到 ``TransactionSynchronizationManager``,
12
+ 等待 ``@Transactional`` 切面在对应阶段触发;无活动事务时按 ``fallback_execution`` 决定是否立即执行。
13
+ - **复用既有事件基础设施**:普通 ``@EventListener`` 由 ``ApplicationEventPublisher`` 立即触发,
14
+ 本模块仅处理事务监听器;可委托 ``ApplicationEventPublisher`` 处理普通监听器以共存的。
15
+ - **注解基类**:``TransactionalEventListener`` 继承 ``SpringAnnotation``,元数据挂到
16
+ ``__spring_annotations__``,由 ``ApplicationContext._register_event_listeners`` 扫描注册。
17
+
18
+ 与 Java 的差异:
19
+ - Spring ``@TransactionalEventListener`` 默认 ``AFTER_COMMIT``,无事务时不执行;本实现一致。
20
+ - 监听器顺序由注册顺序决定(Spring 支持 ``@Order``,本实现保留 ``order`` 字段供扩展)。
21
+ """
22
+ from __future__ import annotations
23
+
24
+ import asyncio
25
+ import inspect
26
+ import logging
27
+ from typing import Any, Callable, List, Optional, Tuple, Type
28
+
29
+ from spring.annotations.core import ApplicationEvent, SpringAnnotation
30
+ from .synchronization import (
31
+ TransactionPhase,
32
+ TransactionSynchronization,
33
+ TransactionSynchronizationManager,
34
+ )
35
+
36
+ logger = logging.getLogger("Spring.Tx.Events")
37
+
38
+
39
+ class TransactionalEventListener(SpringAnnotation):
40
+ """``@TransactionalEventListener`` 标记方法为事务阶段事件监听器。
41
+
42
+ Args:
43
+ phase: 触发阶段,默认 ``AFTER_COMMIT``。
44
+ fallback_execution: 无活动事务时是否立即执行(默认 ``False``,对齐 Spring)。
45
+ event_type: 监听的事件类型;未指定时从方法首参类型推断。
46
+ order: 监听器顺序(保留字段,当前按注册顺序触发)。
47
+ """
48
+
49
+ _annotation_type = "tx_event_listener"
50
+
51
+ def __init__(
52
+ self,
53
+ phase: TransactionPhase = TransactionPhase.AFTER_COMMIT,
54
+ fallback_execution: bool = False,
55
+ event_type: Optional[Type[ApplicationEvent]] = None,
56
+ order: int = 0,
57
+ ):
58
+ # 支持装饰器简写:@TransactionalEventListener(SomeEvent)
59
+ super().__init__(
60
+ phase=phase,
61
+ fallback_execution=fallback_execution,
62
+ event_type=event_type,
63
+ order=order,
64
+ )
65
+
66
+
67
+ # 事务监听器条目:(event_type, callback, phase, fallback_execution, order)
68
+ _TxListenerEntry = Tuple[Optional[Type[ApplicationEvent]], Callable, TransactionPhase, bool, int]
69
+
70
+
71
+ class _ListenerSynchronization(TransactionSynchronization):
72
+ """把一个事务监听器适配为事务同步回调,在指定阶段触发。"""
73
+
74
+ def __init__(
75
+ self,
76
+ callback: Callable,
77
+ event: Any,
78
+ phase: TransactionPhase,
79
+ order: int,
80
+ ):
81
+ self._callback = callback
82
+ self._event = event
83
+ self._phase = phase
84
+ self._order = order
85
+ # AFTER_COMPLETION 阶段在 after_completion 中触发;其它阶段在对应方法触发。
86
+ self._fired = False
87
+
88
+ def _invoke(self) -> None:
89
+ if self._fired:
90
+ return
91
+ self._fired = True
92
+ result = self._callback(self._event)
93
+ if inspect.isawaitable(result):
94
+ self._finish_awaitable(result)
95
+
96
+ @staticmethod
97
+ def _finish_awaitable(awaitable) -> None:
98
+ try:
99
+ loop = asyncio.get_running_loop()
100
+ except RuntimeError:
101
+ asyncio.run(awaitable)
102
+ else:
103
+ loop.create_task(awaitable)
104
+
105
+ def before_commit(self) -> None:
106
+ if self._phase == TransactionPhase.BEFORE_COMMIT:
107
+ self._invoke()
108
+
109
+ def after_commit(self) -> None:
110
+ if self._phase == TransactionPhase.AFTER_COMMIT:
111
+ self._invoke()
112
+
113
+ def after_rollback(self) -> None:
114
+ if self._phase == TransactionPhase.AFTER_ROLLBACK:
115
+ self._invoke()
116
+
117
+ def after_completion(self, status: str) -> None:
118
+ if self._phase == TransactionPhase.AFTER_COMPLETION:
119
+ self._invoke()
120
+
121
+
122
+ class TransactionalEventPublisher:
123
+ """事务事件发布器:管理事务监听器并在事务阶段触发。
124
+
125
+ 与 ``ApplicationEventPublisher`` 平行存在;可单独使用,也可由 ``ApplicationContext``
126
+ 注册为 Bean 供 ``publish_event`` 统一委托。
127
+ """
128
+
129
+ def __init__(self):
130
+ self._listeners: List[_TxListenerEntry] = []
131
+
132
+ def add_listener(
133
+ self,
134
+ callback: Callable,
135
+ event_type: Optional[Type[ApplicationEvent]] = None,
136
+ phase: TransactionPhase = TransactionPhase.AFTER_COMMIT,
137
+ fallback_execution: bool = False,
138
+ order: int = 0,
139
+ ) -> None:
140
+ self._listeners.append((event_type, callback, phase, fallback_execution, order))
141
+
142
+ def clear(self) -> None:
143
+ self._listeners.clear()
144
+
145
+ def listener_count(self) -> int:
146
+ return len(self._listeners)
147
+
148
+ def publish_event(self, event: Any) -> Any:
149
+ """发布事件:匹配的事务监听器按事务阶段触发或回退立即执行。"""
150
+ if not isinstance(event, ApplicationEvent):
151
+ event = ApplicationEvent(source=event)
152
+
153
+ tx_active = TransactionSynchronizationManager.is_synchronization_active()
154
+ for event_type, callback, phase, fallback, _order in list(self._listeners):
155
+ if event_type is not None and not isinstance(event, event_type):
156
+ continue
157
+ if tx_active:
158
+ sync = _ListenerSynchronization(callback, event, phase, _order)
159
+ TransactionSynchronizationManager.register_synchronization(sync)
160
+ elif fallback:
161
+ # 无活动事务且允许回退执行:立即触发
162
+ result = callback(event)
163
+ if inspect.isawaitable(result):
164
+ _ListenerSynchronization._finish_awaitable(result)
165
+ # 否则丢弃(对齐 Spring 默认:无事务不执行)
166
+ return event
167
+
168
+
169
+ __all__ = [
170
+ "TransactionalEventListener",
171
+ "TransactionalEventPublisher",
172
+ ]
@@ -0,0 +1,143 @@
1
+ """事务同步管理器(对齐 Spring ``TransactionSynchronizationManager``)。
2
+
3
+ 跟踪当前事务的同步回调(``TransactionSynchronization``),在事务生命周期各阶段触发:
4
+ ``BEFORE_COMMIT`` / ``AFTER_COMMIT`` / ``AFTER_ROLLBACK`` / ``AFTER_COMPLETION``。
5
+
6
+ 设计:
7
+ - **ContextVar 持有**:用 ``ContextVar`` 保存当前事务的同步列表与活跃标志,兼容 ``asyncio`` 协程,
8
+ 对齐 Spring 的 ``ThreadLocal<List<TransactionSynchronization>>``。
9
+ - **最佳努力触发**:同步回调抛错时记录日志但不中断事务流程(与 Spring ``after_completion``
10
+ 语义一致;``beforeCommit`` 抛错在 Spring 中会触发回滚,此处为安全起见统一记录,避免影响既有事务)。
11
+ - **集成点**:``@Transactional`` 切面(``bean_factory._wrap_transactional``)在事务边界调用
12
+ ``init/clear`` 与各 ``trigger_*``;非受管场景可用 ``transaction_sync_scope`` 上下文管理器。
13
+
14
+ 与 Java 的差异:
15
+ - Spring 用 ``ThreadLocal``;Python 用 ``ContextVar`` 兼容协程。
16
+ - 同步回调抛错统一记录不中断事务(Spring ``beforeCommit`` 抛错会回滚),已在模块文档标注。
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import logging
21
+ from contextlib import contextmanager
22
+ from contextvars import ContextVar
23
+ from enum import Enum
24
+ from typing import Callable, List, Optional
25
+
26
+ logger = logging.getLogger("Spring.Tx.Synchronization")
27
+
28
+
29
+ class TransactionPhase(Enum):
30
+ """事务事件触发阶段(对齐 Spring ``TransactionPhase``)。"""
31
+ BEFORE_COMMIT = "BEFORE_COMMIT"
32
+ AFTER_COMMIT = "AFTER_COMMIT"
33
+ AFTER_ROLLBACK = "AFTER_ROLLBACK"
34
+ AFTER_COMPLETION = "AFTER_COMPLETION"
35
+
36
+
37
+ class TransactionSynchronization:
38
+ """事务同步回调接口(对齐 Spring ``TransactionSynchronization``)。
39
+
40
+ 子类按需重写各阶段回调;默认无操作。``@TransactionalEventListener`` 通过本接口的
41
+ 适配实现把监听器挂到指定阶段。
42
+ """
43
+
44
+ def before_commit(self) -> None:
45
+ """事务提交前调用(同一事务可多次刷新时,仅最终提交前调用一次)。"""
46
+
47
+ def after_commit(self) -> None:
48
+ """事务成功提交后调用。"""
49
+
50
+ def after_rollback(self) -> None:
51
+ """事务回滚后调用。"""
52
+
53
+ def after_completion(self, status: str) -> None:
54
+ """事务完成后调用(``status`` 为 ``'commit'`` 或 ``'rollback'``)。"""
55
+
56
+
57
+ # 当前事务的同步回调列表(None 表示当前无活动事务)
58
+ _synchronizations: ContextVar[Optional[List[TransactionSynchronization]]] = ContextVar(
59
+ "spring_tx_synchronizations", default=None
60
+ )
61
+
62
+
63
+ class TransactionSynchronizationManager:
64
+ """事务同步管理器(静态方法风格,对齐 Spring 同名类)。"""
65
+
66
+ @staticmethod
67
+ def is_synchronization_active() -> bool:
68
+ return _synchronizations.get() is not None
69
+
70
+ @staticmethod
71
+ def init_synchronization() -> None:
72
+ """开启一个新的事务同步上下文(``@Transactional`` 入口调用)。"""
73
+ _synchronizations.set([])
74
+
75
+ @staticmethod
76
+ def clear_synchronization() -> None:
77
+ """清空当前事务同步上下文(``@Transactional`` 出口调用)。"""
78
+ _synchronizations.set(None)
79
+
80
+ @staticmethod
81
+ def get_synchronizations() -> List[TransactionSynchronization]:
82
+ """返回当前事务已注册的同步回调列表(无活动事务返回空列表)。"""
83
+ syncs = _synchronizations.get()
84
+ return list(syncs) if syncs is not None else []
85
+
86
+ @staticmethod
87
+ def register_synchronization(sync: TransactionSynchronization) -> None:
88
+ """注册一个同步回调到当前事务;无活动事务时抛错(对齐 Spring)。"""
89
+ syncs = _synchronizations.get()
90
+ if syncs is None:
91
+ raise RuntimeError(
92
+ "注册事务同步回调要求当前存在活动事务;"
93
+ "请在 @Transactional 方法内或 transaction_sync_scope 内调用"
94
+ )
95
+ syncs.append(sync)
96
+
97
+ # ==================== 阶段触发 ====================
98
+
99
+ @staticmethod
100
+ def trigger_before_commit() -> None:
101
+ TransactionSynchronizationManager._trigger(
102
+ "before_commit", lambda s: s.before_commit()
103
+ )
104
+
105
+ @staticmethod
106
+ def trigger_after_commit() -> None:
107
+ TransactionSynchronizationManager._trigger(
108
+ "after_commit", lambda s: s.after_commit()
109
+ )
110
+
111
+ @staticmethod
112
+ def trigger_after_rollback() -> None:
113
+ TransactionSynchronizationManager._trigger(
114
+ "after_rollback", lambda s: s.after_rollback()
115
+ )
116
+
117
+ @staticmethod
118
+ def trigger_after_completion(status: str) -> None:
119
+ TransactionSynchronizationManager._trigger(
120
+ "after_completion", lambda s: s.after_completion(status)
121
+ )
122
+
123
+ @staticmethod
124
+ def _trigger(phase: str, invoker: Callable[[TransactionSynchronization], None]) -> None:
125
+ """最佳努力触发:逐个调用同步回调,单个抛错记录日志但不中断后续。"""
126
+ for sync in TransactionSynchronizationManager.get_synchronizations():
127
+ try:
128
+ invoker(sync)
129
+ except Exception: # pragma: no cover - 防御性,同步回调实现多样
130
+ logger.exception("事务同步回调 %s 执行失败", phase)
131
+
132
+
133
+ @contextmanager
134
+ def transaction_sync_scope():
135
+ """非受管场景的事务同步上下文:进入 init,退出 clear(不触发任何阶段)。
136
+
137
+ 供独立测试或手动管理事务事件边界使用。``@Transactional`` 切面内部会自行管理。
138
+ """
139
+ TransactionSynchronizationManager.init_synchronization()
140
+ try:
141
+ yield TransactionSynchronizationManager
142
+ finally:
143
+ TransactionSynchronizationManager.clear_synchronization()
@@ -0,0 +1,5 @@
1
+ from .logger import SpringLogger
2
+ from .banner import BannerPrinter
3
+ from .redis_client import RedisClient
4
+
5
+ __all__ = ["SpringLogger", "BannerPrinter", "RedisClient"]
spring/utils/banner.py ADDED
@@ -0,0 +1,32 @@
1
+ from spring.utils.logger import SpringLogger
2
+
3
+
4
+ class BannerPrinter:
5
+ SPRING_BANNER = """
6
+ ____ _ _ ____ _ _ ____ _ ____
7
+ / ___| ___ ___| |_ ___| |__ / ___|| | | | / ___| / \\ | _ \\
8
+ \\___ \\ / _ \\ / __| __/ __| '_ \\ \\___ \\| |_| | \\___ \\ / _ \\ | |_) |
9
+ ___) | (_) | (__| || (__| | | | ___) | _ | ___) / ___ \\| __/
10
+ |____/ \\___/ \\___|\\__\\___|_| |_| |____/|_| |_| |____/_/ \\_\\_|
11
+
12
+ """
13
+
14
+ def __init__(self, version: str = "0.1.0"):
15
+ self.version = version
16
+ self.logger = SpringLogger()
17
+
18
+ def print_banner(self) -> None:
19
+ print(self.SPRING_BANNER)
20
+ print(f" Spring Framework {self.version} ".center(60, "="))
21
+ print()
22
+
23
+ def print_startup_info(self, port: int, context_path: str = "") -> None:
24
+ self.logger.info("Starting Spring application...")
25
+ self.logger.info(f"Server port: {port}")
26
+ self.logger.info(f"Context path: {context_path or '/'}")
27
+ self.logger.info("Application started successfully!")
28
+ print()
29
+
30
+ def print_shutdown_info(self) -> None:
31
+ self.logger.info("Shutting down Spring application...")
32
+ self.logger.info("Application stopped successfully!")
spring/utils/logger.py ADDED
@@ -0,0 +1,73 @@
1
+ import logging
2
+ import sys
3
+ from typing import Optional
4
+
5
+
6
+ class SpringLogger:
7
+ _instance: Optional['SpringLogger'] = None
8
+
9
+ def __new__(cls, *args, **kwargs):
10
+ if cls._instance is None:
11
+ cls._instance = super().__new__(cls)
12
+ cls._instance._initialized = False
13
+ return cls._instance
14
+
15
+ def __init__(self):
16
+ if getattr(self, '_initialized', False):
17
+ return
18
+
19
+ self._logger = logging.getLogger("Spring")
20
+ self._logger.setLevel(logging.INFO)
21
+
22
+ formatter = logging.Formatter(
23
+ "%(asctime)s [%(levelname)s] %(name)s - %(message)s",
24
+ datefmt="%Y-%m-%d %H:%M:%S"
25
+ )
26
+
27
+ console_handler = logging.StreamHandler(sys.stdout)
28
+ console_handler.setFormatter(formatter)
29
+ console_handler.setLevel(logging.INFO)
30
+
31
+ self._logger.addHandler(console_handler)
32
+ self._initialized = True
33
+
34
+ def get_logger(self) -> logging.Logger:
35
+ return self._logger
36
+
37
+ def info(self, message: str) -> None:
38
+ self._logger.info(message)
39
+
40
+ def warn(self, message: str) -> None:
41
+ self._logger.warning(message)
42
+
43
+ def warning(self, message: str) -> None:
44
+ """Expose the standard-library logging spelling used by framework code."""
45
+ self._logger.warning(message)
46
+
47
+ def error(self, message: str) -> None:
48
+ self._logger.error(message)
49
+
50
+ def debug(self, message: str) -> None:
51
+ self._logger.debug(message)
52
+
53
+ def trace(self, message: str) -> None:
54
+ self._logger.debug(message)
55
+
56
+ def set_level(self, level: int) -> None:
57
+ self._logger.setLevel(level)
58
+ for handler in self._logger.handlers:
59
+ handler.setLevel(level)
60
+
61
+
62
+ def get_logger(name: str = "Spring") -> logging.Logger:
63
+ logger = logging.getLogger(name)
64
+ if not logger.handlers:
65
+ logger.setLevel(logging.INFO)
66
+ formatter = logging.Formatter(
67
+ "%(asctime)s [%(levelname)s] %(name)s - %(message)s",
68
+ datefmt="%Y-%m-%d %H:%M:%S"
69
+ )
70
+ console_handler = logging.StreamHandler(sys.stdout)
71
+ console_handler.setFormatter(formatter)
72
+ logger.addHandler(console_handler)
73
+ return logger