deepfos 1.1.76__tar.gz → 1.1.78__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 (192) hide show
  1. {deepfos-1.1.76 → deepfos-1.1.78}/CHANGELOG.md +15 -0
  2. {deepfos-1.1.76 → deepfos-1.1.78}/PKG-INFO +1 -1
  3. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/_version.py +3 -3
  4. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/account.py +1 -0
  5. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/app.py +1 -0
  6. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/base.py +68 -70
  7. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/platform.py +1 -0
  8. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/space.py +1 -0
  9. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/system.py +1 -0
  10. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/deepmodel.py +2 -2
  11. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/discovery.py +3 -0
  12. deepfos-1.1.78/deepfos/lib/k8s.py +101 -0
  13. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/options.py +19 -5
  14. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/PKG-INFO +1 -1
  15. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/SOURCES.txt +2 -0
  16. {deepfos-1.1.76 → deepfos-1.1.78}/setup.py +1 -1
  17. {deepfos-1.1.76 → deepfos-1.1.78}/.gitattributes +0 -0
  18. {deepfos-1.1.76 → deepfos-1.1.78}/.gitee/ISSUE_GUIDELINES.md +0 -0
  19. {deepfos-1.1.76 → deepfos-1.1.78}/.gitee/ISSUE_TEMPLATE.md +0 -0
  20. {deepfos-1.1.76 → deepfos-1.1.78}/.gitignore +0 -0
  21. {deepfos-1.1.76 → deepfos-1.1.78}/MANIFEST.in +0 -0
  22. {deepfos-1.1.76 → deepfos-1.1.78}/README.md +0 -0
  23. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/__init__.py +0 -0
  24. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/algo/__init__.py +0 -0
  25. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/algo/graph.py +0 -0
  26. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/__init__.py +0 -0
  27. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/business_model.py +0 -0
  28. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/dimension.py +0 -0
  29. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/models/__init__.py +0 -0
  30. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/models/business_model.py +0 -0
  31. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_1/models/dimension.py +0 -0
  32. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_2/__init__.py +0 -0
  33. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_2/dimension.py +0 -0
  34. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_2/models/__init__.py +0 -0
  35. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/V1_2/models/dimension.py +0 -0
  36. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/__init__.py +0 -0
  37. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/accounting_engines.py +0 -0
  38. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/approval_process.py +0 -0
  39. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/business_model.py +0 -0
  40. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/consolidation.py +0 -0
  41. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/consolidation_process.py +0 -0
  42. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/datatable.py +0 -0
  43. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/deep_pipeline.py +0 -0
  44. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/deepconnector.py +0 -0
  45. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/deepfos_task.py +0 -0
  46. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/deepmodel.py +0 -0
  47. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/dimension.py +0 -0
  48. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/financial_model.py +0 -0
  49. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/journal_model.py +0 -0
  50. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/journal_template.py +0 -0
  51. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/memory_financial_model.py +0 -0
  52. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/__init__.py +0 -0
  53. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/account.py +0 -0
  54. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/accounting_engines.py +0 -0
  55. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/app.py +0 -0
  56. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/approval_process.py +0 -0
  57. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/base.py +0 -0
  58. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/business_model.py +0 -0
  59. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/consolidation.py +0 -0
  60. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/consolidation_process.py +0 -0
  61. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/datatable_mysql.py +0 -0
  62. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/deep_pipeline.py +0 -0
  63. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/deepconnector.py +0 -0
  64. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/deepfos_task.py +0 -0
  65. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/deepmodel.py +0 -0
  66. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/dimension.py +0 -0
  67. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/financial_model.py +0 -0
  68. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/journal_model.py +0 -0
  69. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/journal_template.py +0 -0
  70. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/memory_financial_model.py +0 -0
  71. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/platform.py +0 -0
  72. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/python.py +0 -0
  73. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/reconciliation_engine.py +0 -0
  74. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/reconciliation_report.py +0 -0
  75. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/role_strategy.py +0 -0
  76. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/smartlist.py +0 -0
  77. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/space.py +0 -0
  78. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/system.py +0 -0
  79. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/variable.py +0 -0
  80. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/models/workflow.py +0 -0
  81. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/python.py +0 -0
  82. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/reconciliation_engine.py +0 -0
  83. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/reconciliation_report.py +0 -0
  84. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/role_strategy.py +0 -0
  85. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/smartlist.py +0 -0
  86. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/variable.py +0 -0
  87. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/api/workflow.py +0 -0
  88. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/__init__.py +0 -0
  89. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/jstream.c +0 -0
  90. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/jstream.pyx +0 -0
  91. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/pandas.c +0 -0
  92. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/pandas.pyx +0 -0
  93. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/py_jstream.py +0 -0
  94. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/boost/py_pandas.py +0 -0
  95. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/cache.py +0 -0
  96. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/config.py +0 -0
  97. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/__init__.py +0 -0
  98. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/__init__.py +0 -0
  99. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/_base.py +0 -0
  100. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/constants.py +0 -0
  101. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/cube.py +0 -0
  102. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/formula.py +0 -0
  103. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/syscube.py +0 -0
  104. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/typing.py +0 -0
  105. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/cube/utils.py +0 -0
  106. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/__init__.py +0 -0
  107. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/_base.py +0 -0
  108. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/dimcreator.py +0 -0
  109. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/dimension.py +0 -0
  110. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/dimexpr.py +0 -0
  111. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/dimmember.py +0 -0
  112. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/eledimension.py +0 -0
  113. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/filters.py +0 -0
  114. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/dimension/sysdimension.py +0 -0
  115. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/__init__.py +0 -0
  116. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/_cache.py +0 -0
  117. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/_operator.py +0 -0
  118. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/nodemixin.py +0 -0
  119. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/sqlcondition.py +0 -0
  120. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/core/logictable/tablemodel.py +0 -0
  121. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/__init__.py +0 -0
  122. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/cipher.py +0 -0
  123. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/clickhouse.py +0 -0
  124. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/connector.py +0 -0
  125. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/daclickhouse.py +0 -0
  126. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/dameng.py +0 -0
  127. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/damysql.py +0 -0
  128. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/dbkits.py +0 -0
  129. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/deepengine.py +0 -0
  130. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/deepmodel.py +0 -0
  131. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/deepmodel_kingbase.py +0 -0
  132. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/edb.py +0 -0
  133. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/gauss.py +0 -0
  134. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/kingbase.py +0 -0
  135. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/mysql.py +0 -0
  136. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/oracle.py +0 -0
  137. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/postgresql.py +0 -0
  138. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/sqlserver.py +0 -0
  139. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/db/utils.py +0 -0
  140. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/__init__.py +0 -0
  141. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/accounting.py +0 -0
  142. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/apvlprocess.py +0 -0
  143. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/base.py +0 -0
  144. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/bizmodel.py +0 -0
  145. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/datatable.py +0 -0
  146. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/deep_pipeline.py +0 -0
  147. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/deepconnector.py +0 -0
  148. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/dimension.py +0 -0
  149. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/fact_table.py +0 -0
  150. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/finmodel.py +0 -0
  151. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/journal.py +0 -0
  152. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/journal_template.py +0 -0
  153. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/pyscript.py +0 -0
  154. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/reconciliation.py +0 -0
  155. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/rolestrategy.py +0 -0
  156. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/smartlist.py +0 -0
  157. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/variable.py +0 -0
  158. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/element/workflow.py +0 -0
  159. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/exceptions/__init__.py +0 -0
  160. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/exceptions/hook.py +0 -0
  161. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lazy.py +0 -0
  162. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/__init__.py +0 -0
  163. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/_javaobj.py +0 -0
  164. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/asynchronous.py +0 -0
  165. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/concurrency.py +0 -0
  166. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/constant.py +0 -0
  167. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/decorator.py +0 -0
  168. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/deepchart.py +0 -0
  169. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/deepux.py +0 -0
  170. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/edb_lexer.py +0 -0
  171. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/eureka.py +0 -0
  172. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/filterparser.py +0 -0
  173. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/httpcli.py +0 -0
  174. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/jsonstreamer.py +0 -0
  175. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/msg.py +0 -0
  176. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/nacos.py +0 -0
  177. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/patch.py +0 -0
  178. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/redis.py +0 -0
  179. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/serutils.py +0 -0
  180. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/stopwatch.py +0 -0
  181. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/subtask.py +0 -0
  182. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/sysutils.py +0 -0
  183. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/lib/utils.py +0 -0
  184. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/local.py +0 -0
  185. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos/translation.py +0 -0
  186. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/dependency_links.txt +0 -0
  187. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/not-zip-safe +0 -0
  188. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/requires.txt +0 -0
  189. {deepfos-1.1.76 → deepfos-1.1.78}/deepfos.egg-info/top_level.txt +0 -0
  190. {deepfos-1.1.76 → deepfos-1.1.78}/requirements.txt +0 -0
  191. {deepfos-1.1.76 → deepfos-1.1.78}/setup.cfg +0 -0
  192. {deepfos-1.1.76 → deepfos-1.1.78}/versioneer.py +0 -0
@@ -1,3 +1,18 @@
1
+ ## [1.1.78] - 2025-12-11
2
+
3
+ ### 更新
4
+
5
+ * api base实现方式改进
6
+ * 修复deepmodel无法insert必填多选链接的bug
7
+
8
+ ## [1.1.77] - 2025-12-05
9
+
10
+ ### 新增
11
+
12
+ * 支持k8s作为服务发现
13
+ * 支持RootAPI从服务发现中获取url
14
+
15
+
1
16
  ## [1.1.76] - 2025-11-06
2
17
 
3
18
  ### 更新
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepfos
3
- Version: 1.1.76
3
+ Version: 1.1.78
4
4
  Summary: Collecions of useful and handy tools for deepfos platform
5
5
  Home-page: http://py.deepfos.com
6
6
  Author: deepfos-python-team
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-11-06T08:50:17+0000",
11
+ "date": "2025-12-22T07:20:38+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "1f02db295b03468baac5e6df6dfd160ee0eba4a2",
15
- "version": "1.1.76"
14
+ "full-revisionid": "1a939ca4b6be850040e0d9076eaf235608eebb23",
15
+ "version": "1.1.78"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -120,6 +120,7 @@ class UserImport(ChildAPI):
120
120
  class AccountAPI(RootAPI):
121
121
  """账户中心"""
122
122
  prefix = lambda: OPTION.server.account
123
+ server_name = "seepln-account"
123
124
 
124
125
  def __init__(self, *args, **kwargs):
125
126
  super(self.__class__.__base__, self).__init__(*args, **kwargs)
@@ -580,6 +580,7 @@ class PermissionAPI(ChildAPI):
580
580
  class AppAPI(RootAPI):
581
581
  """应用服务接口"""
582
582
  prefix = lambda: OPTION.server.app
583
+ server_name = "app-server"
583
584
 
584
585
  @cached_property
585
586
  def element_info(self) -> AppElementInfoAPI:
@@ -1,7 +1,6 @@
1
1
  import enum
2
2
  import json
3
3
  import re
4
- import weakref
5
4
  from importlib import import_module
6
5
  from shlex import quote
7
6
  from typing import (
@@ -366,7 +365,8 @@ class Route:
366
365
 
367
366
  # ---------------------------------------------------------------------
368
367
  # get request info
369
- req = RequestInfo(url=concat_url(ins.base_url, endpoint), method=method)
368
+ base_url = await ins.get_base_url()
369
+ req = RequestInfo(url=concat_url(base_url, endpoint), method=method)
370
370
  req.update_default(func(ins, *args, **kwargs))
371
371
  url, body, ext_header = req.url, req.body, req.header
372
372
  raw_result = model is None
@@ -533,6 +533,7 @@ post = DummyDeco(method='post')
533
533
 
534
534
  class APIBase:
535
535
  endpoint = '/'
536
+ server_name: str = None
536
537
 
537
538
  def __init__(
538
539
  self,
@@ -553,14 +554,27 @@ class APIBase:
553
554
  else:
554
555
  self.header = header
555
556
 
556
- if mat := RE_SYS_SERVER_PARSER.match(prefix):
557
- self.base_url = concat_url(OPTION.server.base, mat.group(1), self.endpoint)
558
- else:
559
- self.base_url = concat_url(prefix, self.endpoint)
557
+ self.prefix = prefix
560
558
  self.header.update({
561
559
  "Content-Type": "application/json;charset=UTF8",
562
560
  "Connection": "close",
563
561
  })
562
+ self.base_url = None
563
+
564
+ async def get_base_url(self):
565
+ if self.base_url is None:
566
+ if (
567
+ OPTION.discovery.enabled
568
+ and OPTION.discovery.take_over
569
+ and self.server_name is not None
570
+ ):
571
+ discovery = ServiceDiscovery.instantiate()
572
+ self.base_url = await discovery.get_url(self.server_name)
573
+ elif mat := RE_SYS_SERVER_PARSER.match(self.prefix):
574
+ self.base_url = concat_url(OPTION.server.base, mat.group(1))
575
+ else:
576
+ self.base_url = self.prefix
577
+ return self.base_url
564
578
 
565
579
 
566
580
  class APIMeta(type):
@@ -596,9 +610,11 @@ class SyncAPIBase(APIBase, metaclass=APIMeta):
596
610
 
597
611
  # noinspection PyUnresolvedReferences
598
612
  class _DynamicAPIMixin:
613
+ module_id: str
599
614
  server_cache = TTLCache(maxsize=128, ttl=3600)
600
615
  module_type: str = UNSET
601
- server_known = False
616
+ server_name: str = None
617
+ base_url: str = None
602
618
  version = None
603
619
 
604
620
  def get_module_id(self, version: Union[float, str], module_id: str):
@@ -619,16 +635,30 @@ class _DynamicAPIMixin:
619
635
  self.server_cache[self.module_id] = server_name
620
636
  return server_name
621
637
 
622
- def get_server_name(self):
623
- return NotImplemented
624
-
625
- # noinspection PyAttributeOutsideInit
626
- def set_url(self, server_name):
627
- self.base_url = concat_url(OPTION.server.base, server_name, self.base_url)
628
- self.server_known = True
638
+ async def get_server_name(self):
639
+ if self.server_name is None:
640
+ if self.module_id in self.server_cache:
641
+ self.server_name = self.server_cache[self.module_id]
642
+ else:
643
+ from .space import SpaceAPI
644
+ api = SpaceAPI(self.header, sync=False)
645
+ server_meta = await api.module.detail(self.module_id) # noqa
646
+ self.server_name = self._add_to_memo(server_meta)
647
+ return self.server_name
648
+
649
+ async def get_base_url(self):
650
+ if self.base_url is None:
651
+ server_name = await self.get_server_name()
652
+ if OPTION.discovery.enabled: # pragma: no cover
653
+ discovery = ServiceDiscovery.instantiate()
654
+ base_url = await discovery.get_url(server_name)
655
+ self.base_url = concat_url(base_url)
656
+ else:
657
+ self.base_url = concat_url(OPTION.server.base, server_name)
658
+ return self.base_url
629
659
 
630
660
 
631
- class DynamicAPIBase(SyncAPIBase, _DynamicAPIMixin):
661
+ class DynamicAPIBase(_DynamicAPIMixin, SyncAPIBase):
632
662
  def __init__(
633
663
  self,
634
664
  version: Union[float, str] = None,
@@ -637,33 +667,16 @@ class DynamicAPIBase(SyncAPIBase, _DynamicAPIMixin):
637
667
  lazy: bool = False
638
668
  ):
639
669
  super().__init__(header)
640
- self.module_id = module_id = self.get_module_id(version, module_id)
641
- # lazy = True means called from element/base, will be set url in ElementBase
642
- if module_id is not None and not lazy:
643
- if module_id in self.server_cache:
644
- logger.debug(f'Find server name for module: {module_id} from cache.')
645
- server_name = self.server_cache[module_id]
646
- else:
647
- server_name = self.get_server_name()
648
- self.set_url(server_name)
649
-
650
- def get_server_name(self):
651
- from .space import SpaceAPI
652
- api = SpaceAPI(self.header, sync=True)
653
- server_meta = api.module.detail(self.module_id)
654
- return self._add_to_memo(server_meta)
655
-
656
- def set_url(self, server_name):
657
- if OPTION.discovery.enabled: # pragma: no cover
658
- discovery = ServiceDiscovery.instantiate()
659
- base_url = discovery.sync_get_url(server_name)
660
- self.base_url = concat_url(base_url, self.endpoint)
661
- self.server_known = True
662
- else:
663
- super().set_url(server_name)
670
+ self.module_id = self.get_module_id(version, module_id)
664
671
 
672
+ def set_server_name(self, server_name):
673
+ self.server_name = server_name
665
674
 
666
- class ADynamicAPIBase(AsyncAPIBase, _DynamicAPIMixin):
675
+ # backward compatibility
676
+ set_url = set_server_name
677
+
678
+
679
+ class ADynamicAPIBase(_DynamicAPIMixin, AsyncAPIBase):
667
680
  def __init__(
668
681
  self,
669
682
  version: Union[float, str] = None,
@@ -678,32 +691,14 @@ class ADynamicAPIBase(AsyncAPIBase, _DynamicAPIMixin):
678
691
  def __await__(self):
679
692
  return self.init().__await__()
680
693
 
681
- async def get_server_name(self):
682
- from .space import SpaceAPI
683
- api = SpaceAPI(self.header, sync=False)
684
- server_meta = await api.module.detail(self.module_id) # noqa
685
- return self._add_to_memo(server_meta)
686
-
687
694
  async def init(self):
688
- if self.module_id is None:
689
- return self
690
- # lazy = True means called from element/base, will be set url in ElementBase
691
- if not self.lazy:
692
- if self.module_id in self.server_cache:
693
- server_name = self.server_cache[self.module_id]
694
- else:
695
- server_name = await self.get_server_name()
696
- await self.set_url(server_name)
697
695
  return self
698
696
 
699
- async def set_url(self, server_name):
700
- if OPTION.discovery.enabled: # pragma: no cover
701
- discovery = ServiceDiscovery.instantiate()
702
- base_url = await discovery.get_url(server_name)
703
- self.base_url = concat_url(base_url, self.endpoint)
704
- self.server_known = True
705
- else:
706
- super().set_url(server_name)
697
+ async def set_server_name(self, server_name):
698
+ self.server_name = server_name
699
+
700
+ # backward compatibility
701
+ set_url = set_server_name
707
702
 
708
703
 
709
704
  class RootAPI:
@@ -722,6 +717,7 @@ class RootAPI:
722
717
  api_version = None
723
718
  cls_name = None
724
719
  module_name = None
720
+ server_name = None
725
721
  builtin = True
726
722
 
727
723
  if TYPE_CHECKING: # pragma: no cover
@@ -881,17 +877,19 @@ class ChildAPI(RootAPI):
881
877
  def __new__(cls, root: RootAPI):
882
878
  clz = cls.resolve_cls(
883
879
  root.sync, (SyncAPIBase, _ChildAPI), (AsyncAPIBase, _ChildAPI),
884
- extra={'root': cls.root}
880
+ extra={'get_base_url': cls.get_base_url}
885
881
  )
886
- ins = clz(header=root.header, prefix=root.base_url)
882
+ ins = clz(header=root.header, prefix=root.prefix)
887
883
  if root.url_need_format:
888
- ins.base_url = ins.base_url.format(**root.header)
889
- ins.__root = weakref.ref(root)
884
+ ins.endpoint = ins.endpoint.format(**root.header)
885
+ ins.root = root
890
886
  return ins
891
887
 
892
- @property
893
- def root(self):
894
- return self.__root()
888
+ async def get_base_url(self):
889
+ if self.base_url is None:
890
+ base_url = await self.root.get_base_url()
891
+ self.base_url = concat_url(base_url, self.endpoint)
892
+ return self.base_url
895
893
 
896
894
 
897
895
  class DynamicRootAPI(RootAPI):
@@ -175,6 +175,7 @@ class FilePyAPI(ChildAPI):
175
175
  class PlatformAPI(RootAPI):
176
176
  """文件上传服务接口"""
177
177
  prefix = lambda: OPTION.server.platform_file
178
+ server_name = "platform-file-server"
178
179
 
179
180
  @cached_property
180
181
  def file(self) -> StdFileAPI:
@@ -522,6 +522,7 @@ class SpaceInternalAPI(ChildAPI):
522
522
  class SpaceAPI(RootAPI):
523
523
  """空间服务接口"""
524
524
  prefix = lambda: OPTION.server.space
525
+ server_name = "space-server"
525
526
 
526
527
  @cached_property
527
528
  def app(self) -> SpaceAppAPI:
@@ -312,6 +312,7 @@ class Space(ChildAPI):
312
312
  class SystemAPI(RootAPI):
313
313
  """系统服务接口"""
314
314
  prefix = lambda: OPTION.server.system
315
+ server_name = "system-server"
315
316
 
316
317
  @cached_property
317
318
  def data_source(self) -> SysDataSourceAPI:
@@ -1249,7 +1249,7 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1249
1249
  lambda f: f.name,
1250
1250
  filter(lambda f: f.required, structure.fields.values())
1251
1251
  ))
1252
- if missing_fields := (required_fields - set(data.columns)):
1252
+ if missing_fields := (required_fields - set(data.columns).union(relation)):
1253
1253
  raise RequiredFieldUnfilled(f'缺少必填字段: {missing_fields}')
1254
1254
 
1255
1255
  if not relation:
@@ -1449,9 +1449,9 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1449
1449
  raise ExternalObjectReadOnly('外部对象只可读')
1450
1450
 
1451
1451
  structure = ObjectStructure(name=obj.name, structure=obj.fields.values())
1452
+ relation = relation or {}
1452
1453
  self._valid_data(data, object_name, relation, structure, check_required=insert)
1453
1454
 
1454
- relation = relation or {}
1455
1455
  bkey = await self._get_bkey(obj)
1456
1456
  if bkey not in data.columns:
1457
1457
  raise RequiredFieldUnfilled(f'缺少业务主键[{bkey}]')
@@ -256,6 +256,9 @@ class ServiceDiscovery(ABC):
256
256
  elif impl == 'nacos':
257
257
  from deepfos.lib.nacos import Nacos
258
258
  cls.__ins__[impl] = Nacos
259
+ elif impl == 'k8s':
260
+ from deepfos.lib.k8s import K8s
261
+ cls.__ins__[impl] = K8s
259
262
 
260
263
  return cls.__ins__[impl]
261
264
 
@@ -0,0 +1,101 @@
1
+ import asyncio
2
+ from collections import defaultdict
3
+ from functools import cached_property
4
+ from typing import TypedDict, Literal, Type, Dict, FrozenSet
5
+
6
+ from loguru import logger
7
+ from kubernetes_asyncio import client, config
8
+ from kubernetes_asyncio.client import (
9
+ V1ServiceList,
10
+ V1Endpoints,
11
+ V1EndpointSubset,
12
+ V1EndpointAddress,
13
+ CoreV1EndpointPort,
14
+ )
15
+ from deepfos.lib.discovery import ServiceDiscovery
16
+ from deepfos import OPTION
17
+
18
+
19
+ class K8s(ServiceDiscovery):
20
+ def __init__(self):
21
+ super().__init__()
22
+ self._instance_lock: Dict[str, asyncio.Lock] = defaultdict(asyncio.Lock)
23
+ self._server_lock = asyncio.Lock()
24
+ self._cares = set()
25
+ self._ns = OPTION.k8s.namespace
26
+
27
+ async def on_close(self):
28
+ self._cares.clear()
29
+ self.server_cache.clear()
30
+ self._instance_lock.clear()
31
+
32
+ async def on_startup(self):
33
+ config.load_incluster_config()
34
+
35
+ @cached_property
36
+ def _api(self):
37
+ return client.CoreV1Api()
38
+
39
+ async def on_interval(self):
40
+ await self._update_cache()
41
+
42
+ async def _update_cache(self):
43
+ logger.opt(lazy=True).debug(f"Update cache for instance: {self._cares}")
44
+ await asyncio.gather(*(
45
+ self.update_instance_for_service(sn)
46
+ for sn in self._cares
47
+ ))
48
+
49
+ async def update_service_cache(self, server_name: str):
50
+ async with self._server_lock:
51
+ if server_name not in self.server_cache:
52
+ await self.update_services()
53
+
54
+ async def update_instance_cache(self, server_name):
55
+ self._cares.add(server_name)
56
+ await self.update_instance_for_service(server_name)
57
+
58
+
59
+ async def _list_all_service_names(self) -> FrozenSet[str]:
60
+ svcs: V1ServiceList = await self._api.list_namespaced_service(self._ns)
61
+ return frozenset(svc.metadata.name for svc in svcs.items)
62
+
63
+ async def update_services(self):
64
+ new_services = await self._list_all_service_names()
65
+ cur_services = frozenset(self.server_cache.keys())
66
+
67
+ if added := new_services - cur_services:
68
+ for srv in added:
69
+ self.server_cache.__getitem__(srv)
70
+ logger.debug(f"Added services: {added}")
71
+
72
+ if removed := cur_services - new_services:
73
+ for srv in removed:
74
+ self.server_cache.pop(srv)
75
+ self._instance_lock.pop(srv, None) # noqa
76
+ logger.debug(f"Removed servieces: {removed}")
77
+
78
+ async def update_instance_for_service(self, server_name: str):
79
+ endpoints: V1Endpoints = await self._api.read_namespaced_endpoints(
80
+ server_name,
81
+ self._ns,
82
+ )
83
+
84
+ no_active_nodes = True
85
+ async with self._instance_lock[server_name]:
86
+ cache = self.server_cache[server_name]
87
+
88
+ for subset in endpoints.subsets or []:
89
+ subset: V1EndpointSubset
90
+ for addr in subset.addresses or []:
91
+ addr: V1EndpointAddress
92
+ no_active_nodes = False
93
+ for port in subset.ports:
94
+ port: CoreV1EndpointPort
95
+ url = f"{port.name}://{addr.ip}:{port.port}"
96
+ cache.add(url)
97
+
98
+ if no_active_nodes:
99
+ logger.debug(f"{server_name} has no active endpoint, clear invalid...")
100
+ for item in list(cache):
101
+ cache.delete(item)
@@ -115,7 +115,8 @@ def _ensure_discovery_server_is_set(value):
115
115
  impl = OPTION.discovery.implementation
116
116
  server_opt = {
117
117
  'eureka': OPTION.server.eureka,
118
- 'nacos': OPTION.nacos.server
118
+ 'nacos': OPTION.nacos.server,
119
+ 'k8s': OPTION.k8s.namespace,
119
120
  }[impl]
120
121
 
121
122
  if server_opt is None:
@@ -379,9 +380,9 @@ class _Category:
379
380
  class _Server(_Category):
380
381
  __id__ = 'server_url'
381
382
 
382
- base = _Option('http://', val_type=str)
383
+ base = _Option('http://web-gateway', val_type=str)
383
384
  app = _Option('http://app-server', val_type=str)
384
- account = _Option('http://account-server', val_type=str)
385
+ account = _Option('http://seepln-account', val_type=str)
385
386
  system = _Option('http://system-server', val_type=str)
386
387
  space = _Option('http://space-server', val_type=str)
387
388
  platform_file = _Option('http://platform-file-server', val_type=str)
@@ -484,16 +485,18 @@ class _Boost(_Category):
484
485
  class _ServiceDiscovery(_Category):
485
486
  __id__ = 'service_discovery'
486
487
 
487
- #: 是否使用服务发现功能
488
+ #: 是否使用服务发现功能(仅影响DynamicAPI)
488
489
  enabled = _Option(False, val_type=bool, on_set=_ensure_discovery_server_is_set)
489
490
  #: 服务注册发现使用的实现
490
- implementation = _Option('eureka', val_type=str, val_choices=('eureka', 'nacos'))
491
+ implementation = _Option('eureka', val_type=str, val_choices=('eureka', 'nacos', 'k8s'))
491
492
  #: 服务注册发现使用的缓存策略
492
493
  cache_strategy = _Option(
493
494
  'ranked',
494
495
  val_type=str,
495
496
  val_choices=('ranked', 'roundrobin', 'random')
496
497
  )
498
+ #: 是否完全使用服务发现获取请求地址(包括Root API)
499
+ take_over = _Option(False, val_type=bool)
497
500
 
498
501
  def __get__(self, instance, owner) -> '_ServiceDiscovery':
499
502
  """defined to help ide"""
@@ -513,6 +516,16 @@ class _Nacos(_Category):
513
516
  return super().__get__(instance, owner)
514
517
 
515
518
 
519
+ class _Kubernets(_Category):
520
+ """Nacos 相关配置"""
521
+
522
+ namespace = _Option(None, val_type=str)
523
+
524
+ def __get__(self, instance, owner) -> '_Kubernets':
525
+ """defined to help ide"""
526
+ return super().__get__(instance, owner)
527
+
528
+
516
529
  # -----------------------------------------------------------------------------
517
530
  # Options
518
531
  class _GlobalOptions:
@@ -525,6 +538,7 @@ class _GlobalOptions:
525
538
  discovery = _ServiceDiscovery()
526
539
  nacos = _Nacos()
527
540
  edgedb = _Edgedb()
541
+ k8s = _Kubernets()
528
542
 
529
543
  def load_file(self, filepath):
530
544
  parser = configparser.ConfigParser()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepfos
3
- Version: 1.1.76
3
+ Version: 1.1.78
4
4
  Summary: Collecions of useful and handy tools for deepfos platform
5
5
  Home-page: http://py.deepfos.com
6
6
  Author: deepfos-python-team
@@ -167,6 +167,7 @@ versioneer.py
167
167
  ./deepfos/lib/filterparser.py
168
168
  ./deepfos/lib/httpcli.py
169
169
  ./deepfos/lib/jsonstreamer.py
170
+ ./deepfos/lib/k8s.py
170
171
  ./deepfos/lib/msg.py
171
172
  ./deepfos/lib/nacos.py
172
173
  ./deepfos/lib/patch.py
@@ -348,6 +349,7 @@ deepfos/lib/eureka.py
348
349
  deepfos/lib/filterparser.py
349
350
  deepfos/lib/httpcli.py
350
351
  deepfos/lib/jsonstreamer.py
352
+ deepfos/lib/k8s.py
351
353
  deepfos/lib/msg.py
352
354
  deepfos/lib/nacos.py
353
355
  deepfos/lib/patch.py
@@ -54,5 +54,5 @@ def resolve_extensions():
54
54
  setup(
55
55
  version=versioneer.get_version(),
56
56
  cmdclass=versioneer.get_cmdclass(),
57
- ext_modules=resolve_extensions()
57
+ ext_modules=[]
58
58
  )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes