springbootAI 1.8.7__tar.gz → 1.8.8__tar.gz

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 (224) hide show
  1. {springbootai-1.8.7/springbootAI.egg-info → springbootai-1.8.8}/PKG-INFO +4 -4
  2. {springbootai-1.8.7 → springbootai-1.8.8}/README.md +3 -3
  3. {springbootai-1.8.7 → springbootai-1.8.8}/pyproject.toml +1 -1
  4. {springbootai-1.8.7 → springbootai-1.8.8}/spring/__init__.py +1 -1
  5. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/autoconfig.py +24 -10
  6. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/cloud.py +9 -7
  7. {springbootai-1.8.7 → springbootai-1.8.8}/spring/aop/cloud_aop.py +19 -8
  8. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/__init__.py +2 -1
  9. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/gateway.py +93 -20
  10. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/seata.py +145 -98
  11. springbootai-1.8.8/spring/cloud/seata_bridge.py +142 -0
  12. {springbootai-1.8.7 → springbootai-1.8.8}/spring/config/config_loader.py +59 -1
  13. {springbootai-1.8.7 → springbootai-1.8.8}/spring/logging/loguru_logger.py +99 -32
  14. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/cache/redis_cache.py +93 -42
  15. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/jwt_utils.py +27 -13
  16. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/actuator.py +115 -13
  17. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/health.py +67 -46
  18. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/web_context.py +6 -1
  19. {springbootai-1.8.7 → springbootai-1.8.8/springbootAI.egg-info}/PKG-INFO +4 -4
  20. {springbootai-1.8.7 → springbootai-1.8.8}/springbootAI.egg-info/SOURCES.txt +2 -0
  21. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_actuator.py +7 -1
  22. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_ai_module.py +16 -6
  23. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_di_config_event_full.py +82 -0
  24. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_logging_config.py +128 -7
  25. springbootai-1.8.8/tests/test_seata_bridge.py +175 -0
  26. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_security.py +4 -1
  27. {springbootai-1.8.7 → springbootai-1.8.8}/LICENSE +0 -0
  28. {springbootai-1.8.7 → springbootai-1.8.8}/MANIFEST.in +0 -0
  29. {springbootai-1.8.7 → springbootai-1.8.8}/requirements.txt +0 -0
  30. {springbootai-1.8.7 → springbootai-1.8.8}/setup.cfg +0 -0
  31. {springbootai-1.8.7 → springbootai-1.8.8}/setup.py +0 -0
  32. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/__init__.py +0 -0
  33. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/advisors.py +0 -0
  34. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/annotations.py +0 -0
  35. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/core.py +0 -0
  36. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/etl.py +0 -0
  37. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/memory.py +0 -0
  38. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/observability.py +0 -0
  39. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/providers.py +0 -0
  40. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/resilience.py +0 -0
  41. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/tools.py +0 -0
  42. {springbootai-1.8.7 → springbootai-1.8.8}/spring/ai/vectorstore.py +0 -0
  43. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/__init__.py +0 -0
  44. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/cache.py +0 -0
  45. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/conditional.py +0 -0
  46. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/core.py +0 -0
  47. {springbootai-1.8.7 → springbootai-1.8.8}/spring/annotations/messaging.py +0 -0
  48. {springbootai-1.8.7 → springbootai-1.8.8}/spring/aop/__init__.py +0 -0
  49. {springbootai-1.8.7 → springbootai-1.8.8}/spring/aop/comprehensive_aop.py +0 -0
  50. {springbootai-1.8.7 → springbootai-1.8.8}/spring/aop/method_interceptor.py +0 -0
  51. {springbootai-1.8.7 → springbootai-1.8.8}/spring/aop/proxy_factory.py +0 -0
  52. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/discovery.py +0 -0
  53. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/feign.py +0 -0
  54. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/load_balancer.py +0 -0
  55. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/sentinel.py +0 -0
  56. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/tracer.py +0 -0
  57. {springbootai-1.8.7 → springbootai-1.8.8}/spring/cloud/transaction_store.py +0 -0
  58. {springbootai-1.8.7 → springbootai-1.8.8}/spring/config/__init__.py +0 -0
  59. {springbootai-1.8.7 → springbootai-1.8.8}/spring/config/binding.py +0 -0
  60. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/__init__.py +0 -0
  61. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/application_context.py +0 -0
  62. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/bean_definition.py +0 -0
  63. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/bean_factory.py +0 -0
  64. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/registry.py +0 -0
  65. {springbootai-1.8.7 → springbootai-1.8.8}/spring/context/scanner.py +0 -0
  66. {springbootai-1.8.7 → springbootai-1.8.8}/spring/core/__init__.py +0 -0
  67. {springbootai-1.8.7 → springbootai-1.8.8}/spring/core/graceful_shutdown.py +0 -0
  68. {springbootai-1.8.7 → springbootai-1.8.8}/spring/core/typing_utils.py +0 -0
  69. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/__init__.py +0 -0
  70. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/annotations.py +0 -0
  71. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/converters.py +0 -0
  72. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/easy_csv.py +0 -0
  73. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/exceptions.py +0 -0
  74. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/reader.py +0 -0
  75. {springbootai-1.8.7 → springbootai-1.8.8}/spring/csv/writer.py +0 -0
  76. {springbootai-1.8.7 → springbootai-1.8.8}/spring/data/__init__.py +0 -0
  77. {springbootai-1.8.7 → springbootai-1.8.8}/spring/data/page.py +0 -0
  78. {springbootai-1.8.7 → springbootai-1.8.8}/spring/data/repository.py +0 -0
  79. {springbootai-1.8.7 → springbootai-1.8.8}/spring/data/specification.py +0 -0
  80. {springbootai-1.8.7 → springbootai-1.8.8}/spring/datasource/__init__.py +0 -0
  81. {springbootai-1.8.7 → springbootai-1.8.8}/spring/datasource/annotations.py +0 -0
  82. {springbootai-1.8.7 → springbootai-1.8.8}/spring/datasource/context.py +0 -0
  83. {springbootai-1.8.7 → springbootai-1.8.8}/spring/datasource/dynamic.py +0 -0
  84. {springbootai-1.8.7 → springbootai-1.8.8}/spring/event/__init__.py +0 -0
  85. {springbootai-1.8.7 → springbootai-1.8.8}/spring/event/publisher.py +0 -0
  86. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/__init__.py +0 -0
  87. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/annotations.py +0 -0
  88. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/converters.py +0 -0
  89. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/easy_excel.py +0 -0
  90. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/exceptions.py +0 -0
  91. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/reader.py +0 -0
  92. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/style.py +0 -0
  93. {springbootai-1.8.7 → springbootai-1.8.8}/spring/excel/writer.py +0 -0
  94. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/__init__.py +0 -0
  95. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/accessor.py +0 -0
  96. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/auto_config.py +0 -0
  97. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/holder.py +0 -0
  98. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/locale.py +0 -0
  99. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/locale_resolver.py +0 -0
  100. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/message_source.py +0 -0
  101. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/middleware.py +0 -0
  102. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/properties.py +0 -0
  103. {springbootai-1.8.7 → springbootai-1.8.8}/spring/i18n/sources.py +0 -0
  104. {springbootai-1.8.7 → springbootai-1.8.8}/spring/logging/__init__.py +0 -0
  105. {springbootai-1.8.7 → springbootai-1.8.8}/spring/main.py +0 -0
  106. {springbootai-1.8.7 → springbootai-1.8.8}/spring/messaging/__init__.py +0 -0
  107. {springbootai-1.8.7 → springbootai-1.8.8}/spring/messaging/rabbitmq.py +0 -0
  108. {springbootai-1.8.7 → springbootai-1.8.8}/spring/monitoring/__init__.py +0 -0
  109. {springbootai-1.8.7 → springbootai-1.8.8}/spring/monitoring/prometheus.py +0 -0
  110. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/__init__.py +0 -0
  111. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/database.py +0 -0
  112. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/ddl_auto.py +0 -0
  113. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/migration.py +0 -0
  114. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/mybatis_integration.py +0 -0
  115. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/__init__.py +0 -0
  116. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/annotations/__init__.py +0 -0
  117. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/annotations/annotations.py +0 -0
  118. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/cache/__init__.py +0 -0
  119. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/cache/cache.py +0 -0
  120. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/circuit_breaker/__init__.py +0 -0
  121. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +0 -0
  122. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/configuration.py +0 -0
  123. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/core/__init__.py +0 -0
  124. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/core/sql_session.py +0 -0
  125. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/core/sql_session_factory.py +0 -0
  126. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/dialect/__init__.py +0 -0
  127. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/dialect/dialect.py +0 -0
  128. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/dynamic_sql/__init__.py +0 -0
  129. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +0 -0
  130. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/interceptor/__init__.py +0 -0
  131. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/interceptor/interceptor.py +0 -0
  132. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/mapper/__init__.py +0 -0
  133. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/mapper/mapper.py +0 -0
  134. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/metrics/__init__.py +0 -0
  135. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/metrics/metrics.py +0 -0
  136. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/pool/__init__.py +0 -0
  137. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/pool/connection_pool.py +0 -0
  138. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/security/__init__.py +0 -0
  139. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/security/access_control.py +0 -0
  140. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/security/password_encoder.py +0 -0
  141. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/security/sensitive_data_masker.py +0 -0
  142. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/security/sql_injection_detector.py +0 -0
  143. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/transaction/__init__.py +0 -0
  144. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/transaction/transaction.py +0 -0
  145. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/type_handler/__init__.py +0 -0
  146. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/type_handler/type_handler.py +0 -0
  147. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/version.py +0 -0
  148. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/xml_parser/__init__.py +0 -0
  149. {springbootai-1.8.7 → springbootai-1.8.8}/spring/orm/pymybatis/xml_parser/xml_parser.py +0 -0
  150. {springbootai-1.8.7 → springbootai-1.8.8}/spring/retry/__init__.py +0 -0
  151. {springbootai-1.8.7 → springbootai-1.8.8}/spring/retry/retry_annotations.py +0 -0
  152. {springbootai-1.8.7 → springbootai-1.8.8}/spring/retry/retry_decorator.py +0 -0
  153. {springbootai-1.8.7 → springbootai-1.8.8}/spring/scheduling/__init__.py +0 -0
  154. {springbootai-1.8.7 → springbootai-1.8.8}/spring/scheduling/scheduler.py +0 -0
  155. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/__init__.py +0 -0
  156. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/replay_protection.py +0 -0
  157. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/secret_manager.py +0 -0
  158. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/security_aop.py +0 -0
  159. {springbootai-1.8.7 → springbootai-1.8.8}/spring/security/security_context.py +0 -0
  160. {springbootai-1.8.7 → springbootai-1.8.8}/spring/test/__init__.py +0 -0
  161. {springbootai-1.8.7 → springbootai-1.8.8}/spring/test/slicing.py +0 -0
  162. {springbootai-1.8.7 → springbootai-1.8.8}/spring/tracing/__init__.py +0 -0
  163. {springbootai-1.8.7 → springbootai-1.8.8}/spring/tracing/skywalking.py +0 -0
  164. {springbootai-1.8.7 → springbootai-1.8.8}/spring/tx/__init__.py +0 -0
  165. {springbootai-1.8.7 → springbootai-1.8.8}/spring/tx/events.py +0 -0
  166. {springbootai-1.8.7 → springbootai-1.8.8}/spring/tx/synchronization.py +0 -0
  167. {springbootai-1.8.7 → springbootai-1.8.8}/spring/utils/__init__.py +0 -0
  168. {springbootai-1.8.7 → springbootai-1.8.8}/spring/utils/banner.py +0 -0
  169. {springbootai-1.8.7 → springbootai-1.8.8}/spring/utils/bean_utils.py +0 -0
  170. {springbootai-1.8.7 → springbootai-1.8.8}/spring/utils/logger.py +0 -0
  171. {springbootai-1.8.7 → springbootai-1.8.8}/spring/utils/redis_client.py +0 -0
  172. {springbootai-1.8.7 → springbootai-1.8.8}/spring/validation/__init__.py +0 -0
  173. {springbootai-1.8.7 → springbootai-1.8.8}/spring/validation/aop.py +0 -0
  174. {springbootai-1.8.7 → springbootai-1.8.8}/spring/validation/constraints.py +0 -0
  175. {springbootai-1.8.7 → springbootai-1.8.8}/spring/validation/exceptions.py +0 -0
  176. {springbootai-1.8.7 → springbootai-1.8.8}/spring/validation/validator.py +0 -0
  177. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/__init__.py +0 -0
  178. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/exception_handler.py +0 -0
  179. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/interceptor.py +0 -0
  180. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/result.py +0 -0
  181. {springbootai-1.8.7 → springbootai-1.8.8}/spring/web/swagger.py +0 -0
  182. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/__init__.py +0 -0
  183. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/annotations.py +0 -0
  184. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/broker.py +0 -0
  185. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/exceptions.py +0 -0
  186. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/handler.py +0 -0
  187. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/router.py +0 -0
  188. {springbootai-1.8.7 → springbootai-1.8.8}/spring/websocket/session.py +0 -0
  189. {springbootai-1.8.7 → springbootai-1.8.8}/springbootAI.egg-info/dependency_links.txt +0 -0
  190. {springbootai-1.8.7 → springbootai-1.8.8}/springbootAI.egg-info/entry_points.txt +0 -0
  191. {springbootai-1.8.7 → springbootai-1.8.8}/springbootAI.egg-info/requires.txt +0 -0
  192. {springbootai-1.8.7 → springbootai-1.8.8}/springbootAI.egg-info/top_level.txt +0 -0
  193. {springbootai-1.8.7 → springbootai-1.8.8}/sql/seata_undo_log.sql +0 -0
  194. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_annotation_combinations.py +0 -0
  195. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_annotations_contract.py +0 -0
  196. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_aop_annotations_full.py +0 -0
  197. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_bean_utils.py +0 -0
  198. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_cache_annotations.py +0 -0
  199. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_cloud_embedded_full.py +0 -0
  200. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_component_init_error.py +0 -0
  201. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_conditional_annotations.py +0 -0
  202. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_config_binding.py +0 -0
  203. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_config_fixes_185.py +0 -0
  204. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_connection_resilience.py +0 -0
  205. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_core_annotations_full.py +0 -0
  206. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_csv_module.py +0 -0
  207. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_data_repository.py +0 -0
  208. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_datasource_routing.py +0 -0
  209. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_ddl_auto.py +0 -0
  210. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_excel_module.py +0 -0
  211. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_i18n_module.py +0 -0
  212. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_jpa_version_transient.py +0 -0
  213. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_new_features.py +0 -0
  214. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_orm_pymybatis_full.py +0 -0
  215. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_production_readiness.py +0 -0
  216. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_pymybatis_contract.py +0 -0
  217. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_seata_durable_store.py +0 -0
  218. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_security_full.py +0 -0
  219. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_swagger_module.py +0 -0
  220. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_test_slicing.py +0 -0
  221. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_transactional_events.py +0 -0
  222. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_validation_module.py +0 -0
  223. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_web_annotations_full.py +0 -0
  224. {springbootai-1.8.7 → springbootai-1.8.8}/tests/test_websocket_module.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: springbootAI
3
- Version: 1.8.7
3
+ Version: 1.8.8
4
4
  Summary: Python版Spring Boot框架,集成PyMyBatis ORM
5
5
  Author-email: YuConggen <1516933915@qq.com>
6
6
  License-Expression: MIT
@@ -86,7 +86,7 @@ Dynamic: license-file
86
86
 
87
87
  SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提供装饰器式组件扫描、依赖注入、FastAPI 路由、配置加载、安全能力、内嵌的 PyMyBatis ORM,以及企业级 AI 模块(对齐 Spring AI 2.0:ChatClient/Advisor/Tools/RAG/Function Calling)。本指南为框架核心综合使用文档;**AI / ORM / Cloud / Excel 等模块的完整注解与功能说明已分离为独立文档**(见下方“模块文档”),本指南相应章节保留概览与跳转链接。
88
88
 
89
- - SpringBootAI 版本:`1.8.4`
89
+ - SpringBootAI 版本:`1.8.8`
90
90
  - 内嵌 PyMyBatis 版本:`1.4.0`
91
91
  - Python:3.10+
92
92
  - 状态:Beta(企业试点)
@@ -153,7 +153,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
153
153
 
154
154
  | 组件 | 当前版本 |
155
155
  |------|----------|
156
- | `spring` 框架 API | 1.8.4 |
156
+ | `spring` 框架 API | 1.8.8 |
157
157
  | `spring.orm.pymybatis` | 1.4.0 |
158
158
  | Python | 3.10+ |
159
159
 
@@ -442,7 +442,7 @@ CORS_ALLOW_ORIGINS CORS_ALLOW_CREDENTIALS
442
442
  LOG_LEVEL LOG_DIR
443
443
  ```
444
444
 
445
- 当前 `SPRING_PROFILES_ACTIVE` 用于 `@Profile` 组件筛选和生产安全校验,不会自动合并 `application-prod.yml`。需要多环境文件时,由部署流程生成最终 `application.yml` 或显式传入配置路径。
445
+ `SPRING_PROFILES_ACTIVE` 用于 `@Profile` 组件筛选、生产安全校验,以及**自动加载并深度合并** `application-{profile}.yml`(v1.8.5 起实现,对齐 Spring Boot 语义)。Profile 文件与主 `application.yml` 同目录,加载顺序为:主配置 → profile 配置深度合并(profile 覆盖主配置的同名键,未涉及的键保留),合并后再解析 `${ENV:default}` 占位符和环境变量覆盖。例如 `SPRING_PROFILES_ACTIVE=prod` 会自动合并 `application-prod.yml`,无需部署流程生成最终 `application.yml`。
446
446
 
447
447
  ### 4.4 Docker 容器 IP 自动检测(开发环境)
448
448
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提供装饰器式组件扫描、依赖注入、FastAPI 路由、配置加载、安全能力、内嵌的 PyMyBatis ORM,以及企业级 AI 模块(对齐 Spring AI 2.0:ChatClient/Advisor/Tools/RAG/Function Calling)。本指南为框架核心综合使用文档;**AI / ORM / Cloud / Excel 等模块的完整注解与功能说明已分离为独立文档**(见下方“模块文档”),本指南相应章节保留概览与跳转链接。
4
4
 
5
- - SpringBootAI 版本:`1.8.4`
5
+ - SpringBootAI 版本:`1.8.8`
6
6
  - 内嵌 PyMyBatis 版本:`1.4.0`
7
7
  - Python:3.10+
8
8
  - 状态:Beta(企业试点)
@@ -69,7 +69,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
69
69
 
70
70
  | 组件 | 当前版本 |
71
71
  |------|----------|
72
- | `spring` 框架 API | 1.8.4 |
72
+ | `spring` 框架 API | 1.8.8 |
73
73
  | `spring.orm.pymybatis` | 1.4.0 |
74
74
  | Python | 3.10+ |
75
75
 
@@ -358,7 +358,7 @@ CORS_ALLOW_ORIGINS CORS_ALLOW_CREDENTIALS
358
358
  LOG_LEVEL LOG_DIR
359
359
  ```
360
360
 
361
- 当前 `SPRING_PROFILES_ACTIVE` 用于 `@Profile` 组件筛选和生产安全校验,不会自动合并 `application-prod.yml`。需要多环境文件时,由部署流程生成最终 `application.yml` 或显式传入配置路径。
361
+ `SPRING_PROFILES_ACTIVE` 用于 `@Profile` 组件筛选、生产安全校验,以及**自动加载并深度合并** `application-{profile}.yml`(v1.8.5 起实现,对齐 Spring Boot 语义)。Profile 文件与主 `application.yml` 同目录,加载顺序为:主配置 → profile 配置深度合并(profile 覆盖主配置的同名键,未涉及的键保留),合并后再解析 `${ENV:default}` 占位符和环境变量覆盖。例如 `SPRING_PROFILES_ACTIVE=prod` 会自动合并 `application-prod.yml`,无需部署流程生成最终 `application.yml`。
362
362
 
363
363
  ### 4.4 Docker 容器 IP 自动检测(开发环境)
364
364
 
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
  [project]
13
13
  # 发行名 springbootAI(PyPI 包名,pip install springbootAI);导入包名仍为 spring
14
14
  name = "springbootAI"
15
- version = "1.8.7"
15
+ version = "1.8.8"
16
16
  description = "Python版Spring Boot框架,集成PyMyBatis ORM"
17
17
  readme = "README.md"
18
18
  license = "MIT"
@@ -5,7 +5,7 @@ from .config import *
5
5
  from .utils import *
6
6
  from .main import create_app, run, SpringApplication, run_cli
7
7
 
8
- __version__ = "1.8.7"
8
+ __version__ = "1.8.8"
9
9
  __author__ = "yuconggen"
10
10
  __license__ = "MIT"
11
11
 
@@ -60,10 +60,24 @@ from spring.context.registry import BeanRegistry
60
60
 
61
61
  logger = logging.getLogger("Spring.AI")
62
62
 
63
- # 生产环境安全开关:AI_ALLOW_FAKE=true(默认)时,api_key 缺失降级 FakeChatModel;
64
- # 设为 false 时,api_key 缺失直接抛 ConfigurationError,防止生产配错无声返回假数据。
65
- _AI_ALLOW_FAKE = os.environ.get("AI_ALLOW_FAKE", "true").strip().lower() in (
66
- "true", "1", "yes", "on")
63
+
64
+ def _ai_allow_fake() -> bool:
65
+ """读取 ``AI_ALLOW_FAKE`` 环境变量,决定 api_key 缺失时是否降级 ``FakeChatModel``。
66
+
67
+ 安全默认:``false``。开发/测试环境需**显式**设置 ``AI_ALLOW_FAKE=true``
68
+ 才允许降级,防止生产环境配错时无声返回测试数据。
69
+
70
+ 设计要点:
71
+ - 每次调用实时读取环境变量(非模块导入时一次性读取),便于 ``config_loader``
72
+ 在生产 profile 下运行时强制 ``AI_ALLOW_FAKE=false``,避免导入时序导致的绕过。
73
+ - 接受 ``true/1/yes/on``(大小写不敏感)为 True,其余为 False,与框架
74
+ ``_to_bool`` 规则一致。
75
+ - 生产环境由 ``config_loader._validate_config`` 双重加固:
76
+ (1) 强制 ``AI_ALLOW_FAKE=false``;
77
+ (2) 校验默认 provider 的 api-key 已配置,缺失直接抛 ``ConfigurationError``。
78
+ """
79
+ return os.environ.get("AI_ALLOW_FAKE", "false").strip().lower() in (
80
+ "true", "1", "yes", "on")
67
81
 
68
82
 
69
83
  # ==================== 类型化配置 dataclass ====================
@@ -258,7 +272,7 @@ def _build_chat_model(props: AIProperties, redis_client=None) -> ChatModel:
258
272
 
259
273
  if provider == "openai":
260
274
  if not props.openai.api_key:
261
- if not _AI_ALLOW_FAKE:
275
+ if not _ai_allow_fake():
262
276
  raise ValueError(
263
277
  "AI_ALLOW_FAKE=false 但 spring.ai.openai.api-key 未配置。"
264
278
  " 请设置 OPENAI_API_KEY 环境变量或 application.yml 的 api-key。")
@@ -295,7 +309,7 @@ def _build_chat_model(props: AIProperties, redis_client=None) -> ChatModel:
295
309
  if provider in _COMPAT_SPECS:
296
310
  pname, lc_mod, lc_cls, cfg = _COMPAT_SPECS[provider]
297
311
  if not cfg.api_key:
298
- if not _AI_ALLOW_FAKE:
312
+ if not _ai_allow_fake():
299
313
  raise ValueError(
300
314
  f"AI_ALLOW_FAKE=false 但 spring.ai.{provider}.api-key 未配置。"
301
315
  f" 请设置 {provider.upper()}_API_KEY 环境变量。")
@@ -309,7 +323,7 @@ def _build_chat_model(props: AIProperties, redis_client=None) -> ChatModel:
309
323
  )
310
324
 
311
325
  logger.warning("未知 AI provider: %s", provider)
312
- if not _AI_ALLOW_FAKE:
326
+ if not _ai_allow_fake():
313
327
  raise ValueError(
314
328
  f"AI_ALLOW_FAKE=false 但未知 provider: {provider}。"
315
329
  " 请检查 application.yml 的 spring.ai.default-provider 配置。")
@@ -323,7 +337,7 @@ def _build_embedding_model(props: AIProperties, redis_client=None):
323
337
 
324
338
  if provider == "openai":
325
339
  if not props.openai.api_key:
326
- if not _AI_ALLOW_FAKE:
340
+ if not _ai_allow_fake():
327
341
  raise ValueError(
328
342
  "AI_ALLOW_FAKE=false 但 Embedding 未配置 api-key。"
329
343
  " 请设置 OPENAI_API_KEY 环境变量。")
@@ -351,7 +365,7 @@ def _build_embedding_model(props: AIProperties, redis_client=None):
351
365
  if provider in ("deepseek", "moonshot", "zhipu"):
352
366
  cfg = getattr(props, provider)
353
367
  if not cfg.api_key:
354
- if not _AI_ALLOW_FAKE:
368
+ if not _ai_allow_fake():
355
369
  raise ValueError(
356
370
  f"AI_ALLOW_FAKE=false 但 Embedding 未配置 {provider} api-key。")
357
371
  logger.warning("Embedding 未配置 %s api-key,降级 FakeEmbeddingModel",
@@ -364,7 +378,7 @@ def _build_embedding_model(props: AIProperties, redis_client=None):
364
378
  circuit_breaker=cb,
365
379
  )
366
380
 
367
- if not _AI_ALLOW_FAKE:
381
+ if not _ai_allow_fake():
368
382
  raise ValueError(
369
383
  "AI_ALLOW_FAKE=false 但未知 Embedding provider。"
370
384
  " 请检查 application.yml 的 spring.ai.default-provider 配置。")
@@ -178,16 +178,18 @@ class LoadBalanced(SpringAnnotation):
178
178
 
179
179
  class GlobalTransactional(SpringAnnotation):
180
180
  """
181
- Seata分布式事务注解
182
- 仅事务发起入口方法添加,所有参与分布式事务的微服务不需要添加该注解
181
+ Seata 分布式事务注解。
182
+
183
+ 仅事务发起入口方法添加。distributed 模式使用官方 Java 客户端桥接和
184
+ Seata TCC;参与服务通过 ``register_branch`` 注册业务分支。
183
185
 
184
186
  使用注意:
185
- - 数据库必须使用InnoDB引擎,支持行锁
186
- - 业务表必须存在主键
187
- - 必须配置Seata注册中心、事务组
187
+ - 必须配置 Seata Server、bridge、共享令牌和事务组
188
+ - TCC 分支必须实现持久化资源预留和幂等的 prepare/commit/rollback
189
+ - 回调要处理重复提交、空回滚和悬挂,不能只修改进程内变量
188
190
  - 不支持嵌套事务
189
- - 只有RuntimeException才会触发全局回滚
190
- - 禁止在异步线程中使用,事务上下文无法传递
191
+ - 业务方法抛出异常时会触发全局回滚
192
+ - 不要把 ContextVar 事务上下文直接复制到独立后台任务中继续使用
191
193
  """
192
194
  _annotation_type = "aop"
193
195
 
@@ -140,16 +140,27 @@ def global_transactional_decorator(annotation: GlobalTransactional):
140
140
  if seata_manager.is_in_transaction():
141
141
  logger.warning("[GlobalTransactional] Nested transaction detected, skipping")
142
142
  return await func(*args, **kwargs)
143
- if seata_manager.get_mode() == "http":
143
+ mode = seata_manager.get_mode()
144
+ if mode in {"http", "distributed"}:
144
145
  tx_id = await asyncio.to_thread(begin_transaction)
145
- transaction_context = await asyncio.to_thread(
146
- seata_manager.get_transaction_context, tx_id
147
- )
148
- if transaction_context is None:
149
- seata_manager._cleanup_context()
150
- raise RuntimeError(
151
- f"Unable to bind durable HTTP transaction context: {tx_id}"
146
+ if mode == "http":
147
+ transaction_context = await asyncio.to_thread(
148
+ seata_manager.get_transaction_context, tx_id
152
149
  )
150
+ if transaction_context is None:
151
+ seata_manager._cleanup_context()
152
+ raise RuntimeError(
153
+ f"Unable to bind durable HTTP transaction context: {tx_id}"
154
+ )
155
+ else:
156
+ transaction_context = {
157
+ 'in_transaction': True,
158
+ 'tx_id': tx_id,
159
+ 'status': 'Begin',
160
+ 'timeout': annotation.timeout,
161
+ 'start_time': time.time(),
162
+ 'name': annotation.name or func.__name__,
163
+ }
153
164
  seata_manager.bind_transaction_context(transaction_context)
154
165
  else:
155
166
  tx_id = begin_transaction()
@@ -19,6 +19,7 @@ from spring.cloud.seata import (
19
19
  BranchStatus,
20
20
  )
21
21
  from spring.cloud.transaction_store import SQLiteTransactionStore
22
+ from spring.cloud.seata_bridge import SeataBridgeClient, SeataBridgeError
22
23
  from spring.cloud.sentinel import (
23
24
  sentinel_engine,
24
25
  SentinelEngine,
@@ -64,7 +65,7 @@ __all__ = [
64
65
  'FeignClientProxy', 'FeignClientFactory', 'create_feign_client', 'create_declared_feign_client',
65
66
  # 分布式事务
66
67
  'seata_manager', 'init_seata', 'SeataTransactionManager', 'BranchStatus',
67
- 'SQLiteTransactionStore',
68
+ 'SQLiteTransactionStore', 'SeataBridgeClient', 'SeataBridgeError',
68
69
  # 熔断限流
69
70
  'sentinel_engine', 'SentinelEngine', 'FlowRule', 'DegradeRule',
70
71
  'SystemRule', 'HotParamRule', 'BlockException', 'sentinel_protect',
@@ -198,6 +198,7 @@ class GatewayRouter:
198
198
 
199
199
  def __init__(self, discovery_client=None, default_filters: List[GatewayFilter] = None,
200
200
  timeout: float = 10.0, max_body_size: int = 10 * 1024 * 1024,
201
+ max_response_size: int = 50 * 1024 * 1024,
201
202
  transport: Optional[httpx.AsyncBaseTransport] = None):
202
203
  self.discovery = discovery_client
203
204
  self.routes: List[Route] = []
@@ -210,6 +211,9 @@ class GatewayRouter:
210
211
  self._path_pattern_cache: Dict[str, re.Pattern] = {}
211
212
  self.timeout = float(timeout)
212
213
  self.max_body_size = int(max_body_size)
214
+ # 上游响应大小上限(字节):防止大文件下载/并发请求整体载入内存耗尽 worker。
215
+ # 旧版本直接 upstream.content 整体载入,无大小限制。0 表示禁用限制(不推荐)。
216
+ self.max_response_size = int(max_response_size)
213
217
  self._transport = transport
214
218
  self._client: Optional[httpx.AsyncClient] = None
215
219
  self._client_lock = threading.Lock()
@@ -410,33 +414,102 @@ class GatewayRouter:
410
414
  }
411
415
  try:
412
416
  target_url = target_uri + forward_path
413
- upstream = await self._get_client().request(
417
+ # 使用 stream=True 避免上游响应整体载入内存:
418
+ # 旧版本 upstream.content 一次性载入全部响应体,大文件下载或并发请求
419
+ # 可能耗尽 worker 内存。流式读取配合 max_response_size 可在超限时提前中止。
420
+ req = self._get_client().build_request(
414
421
  method,
415
422
  target_url,
416
423
  params=query_items,
417
424
  headers=request_headers,
418
425
  content=body,
419
426
  )
427
+ upstream = await self._get_client().send(req, stream=True)
420
428
 
421
- ctx.response_status = upstream.status_code
422
- response_headers = {
423
- key: value for key, value in upstream.headers.items()
424
- if key.lower() not in self._HOP_BY_HOP_HEADERS | {'content-length'}
425
- }
426
- ctx.response_headers.update(response_headers)
427
-
428
- # 执行后置过滤器
429
- for flt in self.filters:
430
- try:
431
- await self._run_filter(flt, 'post_filter', ctx)
432
- except Exception:
433
- logger.exception("[Gateway] post filter failed")
434
-
435
- return Response(
436
- content=upstream.content,
437
- status_code=upstream.status_code,
438
- headers=ctx.response_headers,
439
- )
429
+ try:
430
+ ctx.response_status = upstream.status_code
431
+ response_headers = {
432
+ key: value for key, value in upstream.headers.items()
433
+ if key.lower() not in self._HOP_BY_HOP_HEADERS | {'content-length'}
434
+ }
435
+ ctx.response_headers.update(response_headers)
436
+
437
+ # 执行后置过滤器
438
+ for flt in self.filters:
439
+ try:
440
+ await self._run_filter(flt, 'post_filter', ctx)
441
+ except Exception:
442
+ logger.exception("[Gateway] post filter failed")
443
+
444
+ # 响应大小限制:
445
+ # (1) 先检查 Content-Length 头(快速路径,无需读取响应体即可拒绝)
446
+ # (2) 流式读取时累计字节数,超限立即中止并返回 502
447
+ if self.max_response_size > 0:
448
+ content_length = upstream.headers.get('content-length')
449
+ if content_length:
450
+ try:
451
+ if int(content_length) > self.max_response_size:
452
+ logger.warning(
453
+ "[Gateway] Upstream response Content-Length %s exceeds limit %d",
454
+ content_length, self.max_response_size,
455
+ )
456
+ return JSONResponse(
457
+ {"error": "Upstream response too large",
458
+ "limit_bytes": self.max_response_size},
459
+ status_code=502,
460
+ )
461
+ except ValueError:
462
+ pass
463
+
464
+ # is_stream_consumed=True 表示响应体已预载(如 MockTransport 或
465
+ # 非 stream 模式);此时 aiter_raw() 会抛 StreamConsumed,
466
+ # 直接用 .content 检查大小即可。
467
+ if upstream.is_stream_consumed:
468
+ response_body = upstream.content
469
+ if len(response_body) > self.max_response_size:
470
+ logger.warning(
471
+ "[Gateway] Upstream response %d bytes exceeds limit %d",
472
+ len(response_body), self.max_response_size,
473
+ )
474
+ return JSONResponse(
475
+ {"error": "Upstream response too large",
476
+ "limit_bytes": self.max_response_size},
477
+ status_code=502,
478
+ )
479
+ else:
480
+ chunks = []
481
+ response_size = 0
482
+ too_large = False
483
+ async for chunk in upstream.aiter_raw():
484
+ response_size += len(chunk)
485
+ if response_size > self.max_response_size:
486
+ logger.warning(
487
+ "[Gateway] Upstream response exceeded %d bytes (got %d+), aborting",
488
+ self.max_response_size, response_size,
489
+ )
490
+ too_large = True
491
+ break
492
+ chunks.append(chunk)
493
+
494
+ if too_large:
495
+ return JSONResponse(
496
+ {"error": "Upstream response too large",
497
+ "limit_bytes": self.max_response_size},
498
+ status_code=502,
499
+ )
500
+ response_body = b''.join(chunks)
501
+ else:
502
+ # 无限制:直接读取完整响应(向后兼容,不推荐在生产使用)
503
+ response_body = await upstream.aread()
504
+
505
+ return Response(
506
+ content=response_body,
507
+ status_code=upstream.status_code,
508
+ headers=ctx.response_headers,
509
+ )
510
+ finally:
511
+ # stream=True 模式下必须显式关闭响应,否则连接不会归还连接池
512
+ await upstream.aclose()
440
513
  except httpx.TimeoutException as exc:
441
514
  logger.warning(f"[Gateway] Upstream timeout: {exc}")
442
515
  return JSONResponse({"error": "Gateway timeout"}, status_code=504)