deepfos 1.1.75__tar.gz → 1.1.76__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 (191) hide show
  1. {deepfos-1.1.75 → deepfos-1.1.76}/CHANGELOG.md +9 -0
  2. {deepfos-1.1.75 → deepfos-1.1.76}/PKG-INFO +1 -1
  3. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/_version.py +3 -3
  4. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_2/models/dimension.py +1 -0
  5. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/dimension.py +1 -0
  6. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/deepmodel.py +91 -38
  7. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/dimension.py +16 -3
  8. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/PKG-INFO +1 -1
  9. {deepfos-1.1.75 → deepfos-1.1.76}/.gitattributes +0 -0
  10. {deepfos-1.1.75 → deepfos-1.1.76}/.gitee/ISSUE_GUIDELINES.md +0 -0
  11. {deepfos-1.1.75 → deepfos-1.1.76}/.gitee/ISSUE_TEMPLATE.md +0 -0
  12. {deepfos-1.1.75 → deepfos-1.1.76}/.gitignore +0 -0
  13. {deepfos-1.1.75 → deepfos-1.1.76}/MANIFEST.in +0 -0
  14. {deepfos-1.1.75 → deepfos-1.1.76}/README.md +0 -0
  15. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/__init__.py +0 -0
  16. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/algo/__init__.py +0 -0
  17. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/algo/graph.py +0 -0
  18. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/__init__.py +0 -0
  19. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/business_model.py +0 -0
  20. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/dimension.py +0 -0
  21. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/models/__init__.py +0 -0
  22. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/models/business_model.py +0 -0
  23. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_1/models/dimension.py +0 -0
  24. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_2/__init__.py +0 -0
  25. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_2/dimension.py +0 -0
  26. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/V1_2/models/__init__.py +0 -0
  27. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/__init__.py +0 -0
  28. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/account.py +0 -0
  29. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/accounting_engines.py +0 -0
  30. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/app.py +0 -0
  31. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/approval_process.py +0 -0
  32. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/base.py +0 -0
  33. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/business_model.py +0 -0
  34. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/consolidation.py +0 -0
  35. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/consolidation_process.py +0 -0
  36. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/datatable.py +0 -0
  37. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/deep_pipeline.py +0 -0
  38. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/deepconnector.py +0 -0
  39. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/deepfos_task.py +0 -0
  40. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/deepmodel.py +0 -0
  41. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/dimension.py +0 -0
  42. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/financial_model.py +0 -0
  43. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/journal_model.py +0 -0
  44. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/journal_template.py +0 -0
  45. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/memory_financial_model.py +0 -0
  46. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/__init__.py +0 -0
  47. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/account.py +0 -0
  48. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/accounting_engines.py +0 -0
  49. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/app.py +0 -0
  50. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/approval_process.py +0 -0
  51. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/base.py +0 -0
  52. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/business_model.py +0 -0
  53. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/consolidation.py +0 -0
  54. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/consolidation_process.py +0 -0
  55. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/datatable_mysql.py +0 -0
  56. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/deep_pipeline.py +0 -0
  57. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/deepconnector.py +0 -0
  58. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/deepfos_task.py +0 -0
  59. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/deepmodel.py +0 -0
  60. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/financial_model.py +0 -0
  61. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/journal_model.py +0 -0
  62. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/journal_template.py +0 -0
  63. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/memory_financial_model.py +0 -0
  64. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/platform.py +0 -0
  65. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/python.py +0 -0
  66. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/reconciliation_engine.py +0 -0
  67. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/reconciliation_report.py +0 -0
  68. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/role_strategy.py +0 -0
  69. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/smartlist.py +0 -0
  70. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/space.py +0 -0
  71. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/system.py +0 -0
  72. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/variable.py +0 -0
  73. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/models/workflow.py +0 -0
  74. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/platform.py +0 -0
  75. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/python.py +0 -0
  76. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/reconciliation_engine.py +0 -0
  77. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/reconciliation_report.py +0 -0
  78. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/role_strategy.py +0 -0
  79. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/smartlist.py +0 -0
  80. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/space.py +0 -0
  81. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/system.py +0 -0
  82. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/variable.py +0 -0
  83. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/api/workflow.py +0 -0
  84. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/__init__.py +0 -0
  85. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/jstream.c +0 -0
  86. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/jstream.pyx +0 -0
  87. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/pandas.c +0 -0
  88. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/pandas.pyx +0 -0
  89. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/py_jstream.py +0 -0
  90. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/boost/py_pandas.py +0 -0
  91. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/cache.py +0 -0
  92. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/config.py +0 -0
  93. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/__init__.py +0 -0
  94. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/__init__.py +0 -0
  95. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/_base.py +0 -0
  96. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/constants.py +0 -0
  97. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/cube.py +0 -0
  98. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/formula.py +0 -0
  99. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/syscube.py +0 -0
  100. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/typing.py +0 -0
  101. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/cube/utils.py +0 -0
  102. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/__init__.py +0 -0
  103. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/_base.py +0 -0
  104. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/dimcreator.py +0 -0
  105. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/dimension.py +0 -0
  106. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/dimexpr.py +0 -0
  107. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/dimmember.py +0 -0
  108. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/eledimension.py +0 -0
  109. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/filters.py +0 -0
  110. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/dimension/sysdimension.py +0 -0
  111. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/__init__.py +0 -0
  112. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/_cache.py +0 -0
  113. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/_operator.py +0 -0
  114. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/nodemixin.py +0 -0
  115. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/sqlcondition.py +0 -0
  116. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/core/logictable/tablemodel.py +0 -0
  117. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/__init__.py +0 -0
  118. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/cipher.py +0 -0
  119. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/clickhouse.py +0 -0
  120. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/connector.py +0 -0
  121. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/daclickhouse.py +0 -0
  122. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/dameng.py +0 -0
  123. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/damysql.py +0 -0
  124. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/dbkits.py +0 -0
  125. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/deepengine.py +0 -0
  126. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/deepmodel.py +0 -0
  127. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/deepmodel_kingbase.py +0 -0
  128. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/edb.py +0 -0
  129. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/gauss.py +0 -0
  130. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/kingbase.py +0 -0
  131. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/mysql.py +0 -0
  132. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/oracle.py +0 -0
  133. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/postgresql.py +0 -0
  134. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/sqlserver.py +0 -0
  135. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/db/utils.py +0 -0
  136. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/__init__.py +0 -0
  137. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/accounting.py +0 -0
  138. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/apvlprocess.py +0 -0
  139. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/base.py +0 -0
  140. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/bizmodel.py +0 -0
  141. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/datatable.py +0 -0
  142. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/deep_pipeline.py +0 -0
  143. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/deepconnector.py +0 -0
  144. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/fact_table.py +0 -0
  145. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/finmodel.py +0 -0
  146. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/journal.py +0 -0
  147. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/journal_template.py +0 -0
  148. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/pyscript.py +0 -0
  149. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/reconciliation.py +0 -0
  150. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/rolestrategy.py +0 -0
  151. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/smartlist.py +0 -0
  152. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/variable.py +0 -0
  153. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/element/workflow.py +0 -0
  154. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/exceptions/__init__.py +0 -0
  155. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/exceptions/hook.py +0 -0
  156. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lazy.py +0 -0
  157. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/__init__.py +0 -0
  158. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/_javaobj.py +0 -0
  159. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/asynchronous.py +0 -0
  160. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/concurrency.py +0 -0
  161. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/constant.py +0 -0
  162. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/decorator.py +0 -0
  163. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/deepchart.py +0 -0
  164. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/deepux.py +0 -0
  165. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/discovery.py +0 -0
  166. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/edb_lexer.py +0 -0
  167. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/eureka.py +0 -0
  168. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/filterparser.py +0 -0
  169. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/httpcli.py +0 -0
  170. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/jsonstreamer.py +0 -0
  171. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/msg.py +0 -0
  172. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/nacos.py +0 -0
  173. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/patch.py +0 -0
  174. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/redis.py +0 -0
  175. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/serutils.py +0 -0
  176. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/stopwatch.py +0 -0
  177. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/subtask.py +0 -0
  178. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/sysutils.py +0 -0
  179. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/lib/utils.py +0 -0
  180. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/local.py +0 -0
  181. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/options.py +0 -0
  182. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos/translation.py +0 -0
  183. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/SOURCES.txt +0 -0
  184. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/dependency_links.txt +0 -0
  185. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/not-zip-safe +0 -0
  186. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/requires.txt +0 -0
  187. {deepfos-1.1.75 → deepfos-1.1.76}/deepfos.egg-info/top_level.txt +0 -0
  188. {deepfos-1.1.75 → deepfos-1.1.76}/requirements.txt +0 -0
  189. {deepfos-1.1.75 → deepfos-1.1.76}/setup.cfg +0 -0
  190. {deepfos-1.1.75 → deepfos-1.1.76}/setup.py +0 -0
  191. {deepfos-1.1.75 → deepfos-1.1.76}/versioneer.py +0 -0
@@ -1,3 +1,12 @@
1
+ ## [1.1.76] - 2025-11-06
2
+
3
+ ### 更新
4
+
5
+ * 维度增加dataTypeInfo字段
6
+ * DeepModel增加error_on_empty_link
7
+ * insert_df性能优化
8
+
9
+
1
10
  ## [1.1.75] - 2025-09-17
2
11
 
3
12
  ### 更新
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepfos
3
- Version: 1.1.75
3
+ Version: 1.1.76
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-09-18T10:14:56+0000",
11
+ "date": "2025-11-06T08:50:17+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "874420bc37e43a0b78366335290be2dbff468540",
15
- "version": "1.1.75"
14
+ "full-revisionid": "1f02db295b03468baac5e6df6dfd160ee0eba4a2",
15
+ "version": "1.1.76"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -877,6 +877,7 @@ class DimensionMemberNewDto(BaseModel):
877
877
 
878
878
 
879
879
  class DimensionMemberOperationDto(BaseModel):
880
+ dataTypeInfo: Optional[str] = None
880
881
  #: 变动类型
881
882
  moveType: Optional[str] = None
882
883
  #: 科目类型,科目类特有属性
@@ -542,6 +542,7 @@ class DimensionMemberListDto(BaseModel):
542
542
 
543
543
 
544
544
  class DimensionMemberOperationSw(BaseModel):
545
+ dataTypeInfo: Optional[str] = None
545
546
  #: 变动类型
546
547
  moveType: Optional[str] = None
547
548
  #: 支付类型,科目类型特有
@@ -304,20 +304,43 @@ class ObjectTypeFrame(BaseModel):
304
304
  return exclusive
305
305
 
306
306
 
307
- def _format_link(df: pd.DataFrame, link_name: str):
308
- if all(pd.isnull(df['target'])):
309
- return {'target': pd.NA}
307
+ def _format_link(link_df_fit: pd.DataFrame, link_name: str):
308
+ if link_df_fit.empty:
309
+ return pd.Series(dtype=object), False
310
310
 
311
- record = df.drop(columns=['source']).set_index('target')
312
-
313
- if not record.index.is_unique:
311
+ if link_df_fit.duplicated(subset=['source', 'target']).any():
314
312
  raise MultiLinkTargetNotUnique(
315
313
  f'Multi Link: [{link_name}] relation dataframe中'
316
314
  f'source与target对应存在不唯一性'
317
315
  )
318
316
 
319
- record = record.to_dict(orient='index')
320
- return {'prop': record, 'target': list(record.keys())}
317
+ prop_cols = [col for col in link_df_fit.columns if col not in ['source', 'target']]
318
+ has_props = bool(prop_cols)
319
+
320
+ if has_props:
321
+ sources = link_df_fit['source'].values
322
+ targets = link_df_fit['target'].values
323
+ unique_sources, source_indices = np.unique(sources, return_inverse=True)
324
+
325
+ prop_arrays = {col: link_df_fit[col].values for col in prop_cols}
326
+ result = {}
327
+
328
+ for i in range(len(unique_sources)):
329
+ idx = source_indices == i
330
+ source = unique_sources[i]
331
+ source_targets = targets[idx]
332
+
333
+ indices = np.where(idx)[0]
334
+ prop_dict = {
335
+ source_targets[j]: {col: prop_arrays[col][indices[j]] for col in prop_cols}
336
+ for j in range(len(source_targets))
337
+ }
338
+ result[source] = {'target': source_targets.tolist(), 'prop': prop_dict}
339
+ link = pd.Series(result, dtype=object)
340
+ else:
341
+ link = link_df_fit.groupby('source')['target'].agg(list)
342
+
343
+ return link, has_props
321
344
 
322
345
 
323
346
  class BaseField(PtrInfo):
@@ -486,7 +509,8 @@ def _iter_link_prop_assign(link, business_key, prop_name, prop_type, is_multi):
486
509
  def _iter_single_assign(
487
510
  field: PtrInfo,
488
511
  cast_type: str,
489
- target_main_field: Dict[str, MainField]
512
+ target_main_field: Dict[str, MainField],
513
+ error_on_empty_link: bool = False
490
514
  ) -> str:
491
515
  """
492
516
  生成单字段赋值语句
@@ -495,6 +519,7 @@ def _iter_single_assign(
495
519
  field: 字段信息
496
520
  cast_type: 字段类型
497
521
  target_main_field: 目标字段信息
522
+ error_on_empty_link: 链接字段值不存在时是否抛出异常
498
523
 
499
524
  Returns:
500
525
  赋值语句
@@ -517,30 +542,38 @@ def _iter_single_assign(
517
542
  main_field = target_main_field[link]
518
543
 
519
544
  if main_field.props:
520
- target = (
521
- cast_type + "{" +
522
- ",".join(
523
- _iter_link_prop_assign(link, main_field.business_key, name,
524
- field.prop_type[name], main_field.is_multi)
525
- for name in main_field.props
526
- ) + "}"
545
+ prop_assigns = ','.join(
546
+ _iter_link_prop_assign(link, main_field.business_key, name,
547
+ field.prop_type[name], main_field.is_multi)
548
+ for name in main_field.props
527
549
  )
550
+ prop_block = f" {{{prop_assigns}}}"
528
551
  else:
529
- target = cast_type
552
+ prop_block = ""
530
553
 
531
554
  if main_field.is_multi:
555
+ link_value = f"each_{link}"
556
+ else:
557
+ link_value = f"(json_get(item, '{link}'))"
558
+
559
+ if error_on_empty_link:
560
+ link_expr = f"(<{cast_type}><std::str>{link_value}){prop_block}"
561
+ else:
562
+ link_expr = f"(select detached {cast_type}{prop_block}\nfilter .{main_field.business_key} = <std::str>{link_value})"
563
+
564
+ if main_field.is_multi:
565
+ if main_field.props:
566
+ target_source = f"json_get(item, '{link}', 'target')"
567
+ else:
568
+ target_source = f"item['{link}']"
569
+
532
570
  assign += 'distinct (\n' + textwrap.indent(textwrap.dedent(f"""\
533
- for each_{link} in json_array_unpack(json_get(item, '{link}', 'target'))
571
+ for each_{link} in json_array_unpack({target_source})
534
572
  union (
535
- select detached {target}
536
- filter .{main_field.business_key} = <{main_field.type}>each_{link}
573
+ {link_expr}
537
574
  )"""), TAB) + '\n)'
538
575
  else:
539
- assign += textwrap.dedent(f"""\
540
- assert_single((
541
- select detached {target}
542
- filter .{main_field.business_key} = <{main_field.type}>(json_get(item, '{link}'))
543
- ))""")
576
+ assign += link_expr
544
577
 
545
578
  return assign
546
579
 
@@ -549,9 +582,10 @@ def bulk_insert_by_fields(
549
582
  object_name: str,
550
583
  field_type: List[PtrInfo],
551
584
  target_main_field: Dict[str, MainField],
585
+ error_on_empty_link: bool = False,
552
586
  ):
553
587
  insert_assign_body = ','.join([
554
- _iter_single_assign(field, field.type, target_main_field)
588
+ _iter_single_assign(field, field.type, target_main_field, error_on_empty_link)
555
589
  for field in field_type
556
590
  ])
557
591
  return textwrap.dedent(f"""
@@ -567,16 +601,17 @@ def bulk_upsert_by_fields(
567
601
  field_type: List[PtrInfo],
568
602
  target_main_field: Dict[str, MainField],
569
603
  exclusive_fields: Iterable[str],
570
- update_fields: Iterable[str]
604
+ update_fields: Iterable[str],
605
+ error_on_empty_link: bool = False,
571
606
  ):
572
607
  conflict_on_fields = map(lambda n: f'.{n}', exclusive_fields)
573
608
  insert_assign_body = ','.join([
574
- _iter_single_assign(field, field.type, target_main_field)
609
+ _iter_single_assign(field, field.type, target_main_field, error_on_empty_link)
575
610
  for field in field_type
576
611
  ])
577
612
  update_assign_body = ','.join(
578
613
  [
579
- _iter_single_assign(field, field.type, target_main_field)
614
+ _iter_single_assign(field, field.type, target_main_field, error_on_empty_link)
580
615
  for field in field_type if field.name in update_fields
581
616
  ]
582
617
  )
@@ -599,9 +634,10 @@ def bulk_update_by_fields(
599
634
  target_main_field: Dict[str, MainField],
600
635
  match_fields: Iterable[str],
601
636
  update_fields: Iterable[str],
637
+ error_on_empty_link: bool = False,
602
638
  ):
603
639
  update_assign_body = ','.join([
604
- _iter_single_assign(field, field.type, target_main_field)
640
+ _iter_single_assign(field, field.type, target_main_field, error_on_empty_link)
605
641
  for field in field_type if field.name in update_fields
606
642
  ])
607
643
 
@@ -1374,9 +1410,20 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1374
1410
  ]
1375
1411
  )
1376
1412
  link_df = temp_structure.fit(link_df)
1377
- link = link_df.groupby('source').apply(_format_link, link_name=name)
1378
- data = data.drop(columns=[name], errors='ignore')
1379
- data = data.join(link.to_frame(name), on=bkey)
1413
+ link, has_props = _format_link(link_df, name)
1414
+
1415
+ if not has_props:
1416
+ data = data.drop(columns=[name], errors='ignore')
1417
+ data = data.join(link.to_frame(name), on=bkey, how='left')
1418
+ mask = data[name].isna()
1419
+ if mask.any():
1420
+ empty_series = pd.Series([[]] * mask.sum(), index=data[mask].index, dtype=object)
1421
+ data.loc[mask, name] = empty_series
1422
+ else:
1423
+ bkey_values = data[bkey].values
1424
+ mapped_values = np.array([link.get(key, []) for key in bkey_values], dtype=object)
1425
+ data[name] = mapped_values
1426
+
1380
1427
  return data
1381
1428
 
1382
1429
  async def _collect_bulk_qls(
@@ -1389,7 +1436,8 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1389
1436
  update_fields: Iterable[str] = None,
1390
1437
  exclusive_fields: Iterable[str] = None,
1391
1438
  match_fields: Iterable[str] = None,
1392
- insert: bool = True
1439
+ insert: bool = True,
1440
+ error_on_empty_link: bool = False
1393
1441
  ) -> List[List[QueryWithArgs]]:
1394
1442
  if object_name in self.objects:
1395
1443
  obj = self.objects[object_name]
@@ -1425,10 +1473,10 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1425
1473
  if enable_upsert and update_fields:
1426
1474
  bulk_ql = bulk_upsert_by_fields(
1427
1475
  object_name, field_info, tgt_main_field,
1428
- exclusive_fields, update_fields
1476
+ exclusive_fields, update_fields, error_on_empty_link
1429
1477
  )
1430
1478
  else:
1431
- bulk_ql = bulk_insert_by_fields(object_name, field_info, tgt_main_field)
1479
+ bulk_ql = bulk_insert_by_fields(object_name, field_info, tgt_main_field, error_on_empty_link)
1432
1480
  else:
1433
1481
  if missing := (set(match_fields or [bkey]) - set(field_names)):
1434
1482
  raise ValueError(f"match fields: {missing} 不在提供的数据中")
@@ -1437,7 +1485,7 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1437
1485
  if to_upd := (field_names - match_fields):
1438
1486
  bulk_ql = bulk_update_by_fields(
1439
1487
  object_name, field_info, tgt_main_field,
1440
- match_fields, to_upd
1488
+ match_fields, to_upd, error_on_empty_link
1441
1489
  )
1442
1490
  else:
1443
1491
  bulk_ql = None
@@ -1473,6 +1521,7 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1473
1521
  update_fields: Iterable[str] = None,
1474
1522
  exclusive_fields: Iterable[str] = None,
1475
1523
  commit_per_chunk: bool = False,
1524
+ error_on_empty_link: bool = False,
1476
1525
  ) -> None:
1477
1526
  """以事务执行基于DataFrame字段信息的批量插入数据
1478
1527
 
@@ -1496,6 +1545,9 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1496
1545
  commit_per_chunk: 每次插入后是否提交事务,
1497
1546
  默认为False,即所有数据插入后再提交事务
1498
1547
  该参数仅在非start transaction上下文中生效
1548
+ error_on_empty_link: 链接字段值不存在时是否抛出异常,
1549
+ 默认为False,即不检查链接目标是否存在
1550
+ 当设置为True时,会检查链接目标是否存在,不存在则抛出异常
1499
1551
 
1500
1552
  Notes:
1501
1553
 
@@ -1571,7 +1623,7 @@ class AsyncDeepModel(ElementBase[DeepModelAPI]):
1571
1623
  qls = await self._collect_bulk_qls(
1572
1624
  object_name, data, relation, chunksize,
1573
1625
  enable_upsert, update_fields, exclusive_fields,
1574
- insert=True
1626
+ insert=True, error_on_empty_link=error_on_empty_link
1575
1627
  )
1576
1628
  if commit_per_chunk:
1577
1629
  for ql_chunk in qls:
@@ -1918,6 +1970,7 @@ class DeepModel(AsyncDeepModel, metaclass=SyncMeta):
1918
1970
  update_fields: Iterable[str] = None,
1919
1971
  exclusive_fields: Iterable[str] = None,
1920
1972
  commit_per_chunk: bool = False,
1973
+ error_on_empty_link: bool = False,
1921
1974
  ) -> None:
1922
1975
  ...
1923
1976
 
@@ -1162,12 +1162,25 @@ def _validate_df_for_dimension(df: pd.DataFrame):
1162
1162
  f"You have null value in dataframe. "
1163
1163
  f"column: [{DFLT_NAME_COLUMN}], index: {null_index}.")
1164
1164
 
1165
- if DFLT_PNAME_COLUMN not in df.columns:
1166
- raise ValueError(f"Missing column [{DFLT_PNAME_COLUMN}] in dataframe.")
1165
+ col_parent_name = None
1166
+ col_shared_member = None
1167
+
1168
+ if DFLT_PNAME_COLUMN in df.columns:
1169
+ col_parent_name = DFLT_PNAME_COLUMN
1170
+ elif DFLT_PNAME_COLUMN_V12 in df.columns:
1171
+ col_parent_name = DFLT_PNAME_COLUMN_V12
1167
1172
 
1168
1173
  if SHAREDMEMBER in df.columns:
1174
+ col_shared_member = SHAREDMEMBER
1175
+ elif SHAREDMEMBERV12 in df.columns:
1176
+ col_shared_member = SHAREDMEMBERV12
1177
+
1178
+ if col_parent_name is None:
1179
+ raise ValueError(f"Missing column [{DFLT_PNAME_COLUMN}] or [{DFLT_PNAME_COLUMN_V12}] in dataframe.")
1180
+
1181
+ if col_shared_member is not None:
1169
1182
  unique_df = df.groupby(
1170
- [DFLT_NAME_COLUMN, DFLT_PNAME_COLUMN, SHAREDMEMBER],
1183
+ [DFLT_NAME_COLUMN, col_parent_name, col_shared_member],
1171
1184
  as_index=False
1172
1185
  ).size()
1173
1186
  duplicated = unique_df[unique_df['size'] > 1]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deepfos
3
- Version: 1.1.75
3
+ Version: 1.1.76
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes