deepfos 1.1.60__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. deepfos/__init__.py +6 -0
  2. deepfos/_version.py +21 -0
  3. deepfos/algo/__init__.py +0 -0
  4. deepfos/algo/graph.py +171 -0
  5. deepfos/algo/segtree.py +31 -0
  6. deepfos/api/V1_1/__init__.py +0 -0
  7. deepfos/api/V1_1/business_model.py +119 -0
  8. deepfos/api/V1_1/dimension.py +599 -0
  9. deepfos/api/V1_1/models/__init__.py +0 -0
  10. deepfos/api/V1_1/models/business_model.py +1033 -0
  11. deepfos/api/V1_1/models/dimension.py +2768 -0
  12. deepfos/api/V1_2/__init__.py +0 -0
  13. deepfos/api/V1_2/dimension.py +285 -0
  14. deepfos/api/V1_2/models/__init__.py +0 -0
  15. deepfos/api/V1_2/models/dimension.py +2923 -0
  16. deepfos/api/__init__.py +0 -0
  17. deepfos/api/account.py +167 -0
  18. deepfos/api/accounting_engines.py +147 -0
  19. deepfos/api/app.py +626 -0
  20. deepfos/api/approval_process.py +198 -0
  21. deepfos/api/base.py +983 -0
  22. deepfos/api/business_model.py +160 -0
  23. deepfos/api/consolidation.py +129 -0
  24. deepfos/api/consolidation_process.py +106 -0
  25. deepfos/api/datatable.py +341 -0
  26. deepfos/api/deep_pipeline.py +61 -0
  27. deepfos/api/deepconnector.py +36 -0
  28. deepfos/api/deepfos_task.py +92 -0
  29. deepfos/api/deepmodel.py +188 -0
  30. deepfos/api/dimension.py +486 -0
  31. deepfos/api/financial_model.py +319 -0
  32. deepfos/api/journal_model.py +119 -0
  33. deepfos/api/journal_template.py +132 -0
  34. deepfos/api/memory_financial_model.py +98 -0
  35. deepfos/api/models/__init__.py +3 -0
  36. deepfos/api/models/account.py +483 -0
  37. deepfos/api/models/accounting_engines.py +756 -0
  38. deepfos/api/models/app.py +1338 -0
  39. deepfos/api/models/approval_process.py +1043 -0
  40. deepfos/api/models/base.py +234 -0
  41. deepfos/api/models/business_model.py +805 -0
  42. deepfos/api/models/consolidation.py +711 -0
  43. deepfos/api/models/consolidation_process.py +248 -0
  44. deepfos/api/models/datatable_mysql.py +427 -0
  45. deepfos/api/models/deep_pipeline.py +55 -0
  46. deepfos/api/models/deepconnector.py +28 -0
  47. deepfos/api/models/deepfos_task.py +386 -0
  48. deepfos/api/models/deepmodel.py +308 -0
  49. deepfos/api/models/dimension.py +1576 -0
  50. deepfos/api/models/financial_model.py +1796 -0
  51. deepfos/api/models/journal_model.py +341 -0
  52. deepfos/api/models/journal_template.py +854 -0
  53. deepfos/api/models/memory_financial_model.py +478 -0
  54. deepfos/api/models/platform.py +178 -0
  55. deepfos/api/models/python.py +221 -0
  56. deepfos/api/models/reconciliation_engine.py +411 -0
  57. deepfos/api/models/reconciliation_report.py +161 -0
  58. deepfos/api/models/role_strategy.py +884 -0
  59. deepfos/api/models/smartlist.py +237 -0
  60. deepfos/api/models/space.py +1137 -0
  61. deepfos/api/models/system.py +1065 -0
  62. deepfos/api/models/variable.py +463 -0
  63. deepfos/api/models/workflow.py +946 -0
  64. deepfos/api/platform.py +199 -0
  65. deepfos/api/python.py +90 -0
  66. deepfos/api/reconciliation_engine.py +181 -0
  67. deepfos/api/reconciliation_report.py +64 -0
  68. deepfos/api/role_strategy.py +234 -0
  69. deepfos/api/smartlist.py +69 -0
  70. deepfos/api/space.py +582 -0
  71. deepfos/api/system.py +372 -0
  72. deepfos/api/variable.py +154 -0
  73. deepfos/api/workflow.py +264 -0
  74. deepfos/boost/__init__.py +6 -0
  75. deepfos/boost/py_jstream.py +89 -0
  76. deepfos/boost/py_pandas.py +20 -0
  77. deepfos/cache.py +121 -0
  78. deepfos/config.py +6 -0
  79. deepfos/core/__init__.py +27 -0
  80. deepfos/core/cube/__init__.py +10 -0
  81. deepfos/core/cube/_base.py +462 -0
  82. deepfos/core/cube/constants.py +21 -0
  83. deepfos/core/cube/cube.py +408 -0
  84. deepfos/core/cube/formula.py +707 -0
  85. deepfos/core/cube/syscube.py +532 -0
  86. deepfos/core/cube/typing.py +7 -0
  87. deepfos/core/cube/utils.py +238 -0
  88. deepfos/core/dimension/__init__.py +11 -0
  89. deepfos/core/dimension/_base.py +506 -0
  90. deepfos/core/dimension/dimcreator.py +184 -0
  91. deepfos/core/dimension/dimension.py +472 -0
  92. deepfos/core/dimension/dimexpr.py +271 -0
  93. deepfos/core/dimension/dimmember.py +155 -0
  94. deepfos/core/dimension/eledimension.py +22 -0
  95. deepfos/core/dimension/filters.py +99 -0
  96. deepfos/core/dimension/sysdimension.py +168 -0
  97. deepfos/core/logictable/__init__.py +5 -0
  98. deepfos/core/logictable/_cache.py +141 -0
  99. deepfos/core/logictable/_operator.py +663 -0
  100. deepfos/core/logictable/nodemixin.py +673 -0
  101. deepfos/core/logictable/sqlcondition.py +609 -0
  102. deepfos/core/logictable/tablemodel.py +497 -0
  103. deepfos/db/__init__.py +36 -0
  104. deepfos/db/cipher.py +660 -0
  105. deepfos/db/clickhouse.py +191 -0
  106. deepfos/db/connector.py +195 -0
  107. deepfos/db/daclickhouse.py +171 -0
  108. deepfos/db/dameng.py +101 -0
  109. deepfos/db/damysql.py +189 -0
  110. deepfos/db/dbkits.py +358 -0
  111. deepfos/db/deepengine.py +99 -0
  112. deepfos/db/deepmodel.py +82 -0
  113. deepfos/db/deepmodel_kingbase.py +83 -0
  114. deepfos/db/edb.py +214 -0
  115. deepfos/db/gauss.py +83 -0
  116. deepfos/db/kingbase.py +83 -0
  117. deepfos/db/mysql.py +184 -0
  118. deepfos/db/oracle.py +131 -0
  119. deepfos/db/postgresql.py +192 -0
  120. deepfos/db/sqlserver.py +99 -0
  121. deepfos/db/utils.py +135 -0
  122. deepfos/element/__init__.py +89 -0
  123. deepfos/element/accounting.py +348 -0
  124. deepfos/element/apvlprocess.py +215 -0
  125. deepfos/element/base.py +398 -0
  126. deepfos/element/bizmodel.py +1269 -0
  127. deepfos/element/datatable.py +2467 -0
  128. deepfos/element/deep_pipeline.py +186 -0
  129. deepfos/element/deepconnector.py +59 -0
  130. deepfos/element/deepmodel.py +1806 -0
  131. deepfos/element/dimension.py +1254 -0
  132. deepfos/element/fact_table.py +427 -0
  133. deepfos/element/finmodel.py +1485 -0
  134. deepfos/element/journal.py +840 -0
  135. deepfos/element/journal_template.py +943 -0
  136. deepfos/element/pyscript.py +412 -0
  137. deepfos/element/reconciliation.py +553 -0
  138. deepfos/element/rolestrategy.py +243 -0
  139. deepfos/element/smartlist.py +457 -0
  140. deepfos/element/variable.py +756 -0
  141. deepfos/element/workflow.py +560 -0
  142. deepfos/exceptions/__init__.py +239 -0
  143. deepfos/exceptions/hook.py +86 -0
  144. deepfos/lazy.py +104 -0
  145. deepfos/lazy_import.py +84 -0
  146. deepfos/lib/__init__.py +0 -0
  147. deepfos/lib/_javaobj.py +366 -0
  148. deepfos/lib/asynchronous.py +879 -0
  149. deepfos/lib/concurrency.py +107 -0
  150. deepfos/lib/constant.py +39 -0
  151. deepfos/lib/decorator.py +310 -0
  152. deepfos/lib/deepchart.py +778 -0
  153. deepfos/lib/deepux.py +477 -0
  154. deepfos/lib/discovery.py +273 -0
  155. deepfos/lib/edb_lexer.py +789 -0
  156. deepfos/lib/eureka.py +156 -0
  157. deepfos/lib/filterparser.py +751 -0
  158. deepfos/lib/httpcli.py +106 -0
  159. deepfos/lib/jsonstreamer.py +80 -0
  160. deepfos/lib/msg.py +394 -0
  161. deepfos/lib/nacos.py +225 -0
  162. deepfos/lib/patch.py +92 -0
  163. deepfos/lib/redis.py +241 -0
  164. deepfos/lib/serutils.py +181 -0
  165. deepfos/lib/stopwatch.py +99 -0
  166. deepfos/lib/subtask.py +572 -0
  167. deepfos/lib/sysutils.py +703 -0
  168. deepfos/lib/utils.py +1003 -0
  169. deepfos/local.py +160 -0
  170. deepfos/options.py +670 -0
  171. deepfos/translation.py +237 -0
  172. deepfos-1.1.60.dist-info/METADATA +33 -0
  173. deepfos-1.1.60.dist-info/RECORD +175 -0
  174. deepfos-1.1.60.dist-info/WHEEL +5 -0
  175. deepfos-1.1.60.dist-info/top_level.txt +1 -0
@@ -0,0 +1,472 @@
1
+ import json
2
+ from typing import Tuple, List, Dict
3
+
4
+ import pandas as pd
5
+
6
+ from .dimmember import DimMember
7
+ from ._base import (
8
+ DimensionBase, MemberContainer,
9
+ NAME_DFLT, PNAME_DFLT, IS_SHARED_DFLT
10
+ )
11
+ from .dimcreator import *
12
+ from deepfos.options import OPTION
13
+ from deepfos.core.logictable.nodemixin import bfs, TreeRenderer
14
+
15
+
16
+ class Dimension(DimensionBase):
17
+ """基础维度,拥有完整维度树,对维度成员的查询全部在本地进行。"""
18
+
19
+ def __init__(self, dim_name=None, root=None):
20
+ super().__init__(dim_name)
21
+ #: 维度树的根节点
22
+ self.root = root
23
+ #: 维度成员名-成员实例 构成的字典
24
+ self._members_memo = {}
25
+ self._update_member_dict()
26
+
27
+ def __get__(self, instance, owner=None):
28
+ return self
29
+
30
+ def _update_member_dict(self):
31
+ """更新维度树的维度成员关系字典"""
32
+ if self.root is None:
33
+ return
34
+ self._members_memo = {
35
+ node.name: node
36
+ for node in self.root.family
37
+ }
38
+
39
+ def __set_name__(self, owner, name):
40
+ self.name = name
41
+
42
+ @classmethod
43
+ def from_df(
44
+ cls,
45
+ dim_name: str,
46
+ df: pd.DataFrame,
47
+ name_col: str = NAME_DFLT,
48
+ parent_name_col: str = PNAME_DFLT,
49
+ is_shared_col: str = IS_SHARED_DFLT,
50
+ extra_info: Tuple = (),
51
+ ):
52
+ """
53
+ 从 ``Dataframe`` 创建维度,数据必须至少含有父节点名称列和当前节点名称列。
54
+
55
+ Args:
56
+ dim_name: 维度名称
57
+ df: 创建维度的数据源
58
+ name_col: 当前节点名称列的列名
59
+ parent_name_col: 父节点名称列的列名
60
+ is_shared_col: 是否共享节点列的列名
61
+ extra_info: 其他属性列,若提供,会成为维度成员的额外属性
62
+
63
+ Returns:
64
+ 创建完成的维度对象
65
+
66
+ Example:
67
+ .. code-block:: python
68
+
69
+ # df 是已经加载好的 DataFrame 数据
70
+ dim = Dimension.from_df('dim', df)
71
+
72
+ """
73
+ ins = cls(dim_name)
74
+ tree_creator = DataFrameTreeCreator(
75
+ df, name_col, parent_name_col, is_shared_col, extra_info)
76
+ ins.root, ins._members_memo = tree_creator.create_tree()
77
+ return ins
78
+
79
+ @classmethod
80
+ def from_db(
81
+ cls,
82
+ dbconn,
83
+ dim_name: str,
84
+ name_col: str = NAME_DFLT,
85
+ parent_name_col: str = PNAME_DFLT,
86
+ is_shared_col: str = IS_SHARED_DFLT,
87
+ extra_info: Tuple = (),
88
+ ):
89
+ """
90
+ 由数据库创建维度,数据必须至少含有父节点名称列和当前节点名称列。
91
+
92
+ Args:
93
+ dim_name: 维度名称
94
+ dbconn: 创建维度的数据源
95
+ name_col: 当前节点名称列的列名
96
+ parent_name_col: 父节点名称列的列名
97
+ is_shared_col: 是否共享节点列的列名
98
+ extra_info: 其他属性列,若提供,会成为维度成员的额外属性
99
+
100
+ Returns:
101
+ 创建完成的维度对象
102
+
103
+ Example:
104
+ .. code-block:: python
105
+
106
+ # dbconn 是已经创建好的数据库连接对象
107
+ dim = Dimension.from_db(dbconn, 'dim')
108
+
109
+ """
110
+ ins = cls(dim_name)
111
+ tree_creator = DBTreeCreator(
112
+ dbconn, dim_name, name_col, parent_name_col, is_shared_col, extra_info)
113
+ ins.root, ins._members_memo = tree_creator.create_tree()
114
+ return ins
115
+
116
+ @classmethod
117
+ def from_json(
118
+ cls,
119
+ dim_name: str,
120
+ jsn: List[Dict],
121
+ name_col: str = NAME_DFLT,
122
+ parent_name_col: str = PNAME_DFLT,
123
+ is_shared_col: str = IS_SHARED_DFLT,
124
+ extra_info: Tuple = (),
125
+ ):
126
+ """
127
+ 从 ``json`` 中创建维度,数据必须至少含有父节点名称列和当前节点名称列。
128
+
129
+ Args:
130
+ dim_name: 维度名称
131
+ jsn: 创建维度的数据源
132
+ name_col: 当前节点名称列的列名
133
+ parent_name_col: 父节点名称列的列名
134
+ is_shared_col: 是否共享节点列的列名
135
+ extra_info: 其他属性列,若提供,会成为维度成员的额外属性
136
+
137
+ Returns:
138
+ 创建完成的维度对象
139
+
140
+ Notes:
141
+ 当需要设置额外属性且额外属性只有一个时,也需要使用 ``tuple`` 输入,具体如下例所示。
142
+
143
+ Example:
144
+ .. code-block:: python
145
+
146
+ # data 为建树所需的 Json 数据
147
+ js = json.loads(data)
148
+ # attribute为唯一的额外属性
149
+ dim = Dimension.from_json('dim', js, extra_info=(attribute,))
150
+
151
+ """
152
+ ins = cls(dim_name)
153
+ tree_creator = JsonTreeCreator(
154
+ jsn, name_col, parent_name_col, is_shared_col, extra_info)
155
+ ins.root, ins._members_memo = tree_creator.create_tree()
156
+ return ins
157
+
158
+ @classmethod
159
+ def from_api(
160
+ cls,
161
+ dim_name: str,
162
+ api: List[Dict],
163
+ name_col: str = NAME_DFLT,
164
+ parent_name_col: str = PNAME_DFLT,
165
+ is_shared_col: str = IS_SHARED_DFLT,
166
+ extra_info: Tuple = (),
167
+ fetch_all: bool = False
168
+ ):
169
+ """
170
+ 从系统的 ``API`` 中创建维度,数据必至少含有父节点名称列和当前节点名称列。
171
+
172
+ Args:
173
+ dim_name: 维度名称
174
+ api: 维度接口
175
+ name_col: 当前节点名称列的列名
176
+ parent_name_col: 父节点名称列的列名
177
+ is_shared_col: 是否共享节点列的列名
178
+ extra_info: 其他属性列,若提供,会成为维度成员的额外属性
179
+ fetch_all: 取出从API中获取的全部数据
180
+
181
+ Returns:
182
+ 创建完成的维度对象
183
+
184
+ Example:
185
+ .. code-block:: python
186
+
187
+ # api 是需要调用的 API 接口
188
+ dim = Dimension.from_api('dim', api)
189
+
190
+ """
191
+ ins = cls(dim_name)
192
+ tree_creator = ApiTreeCreator(
193
+ dim_name, api, name_col, parent_name_col, is_shared_col,
194
+ extra_info, fetch_all)
195
+ ins.root, ins._members_memo = tree_creator.create_tree()
196
+ return ins
197
+
198
+ def __getitem__(self, item):
199
+ """
200
+ 获取维度成员
201
+
202
+ 存在两种情况::
203
+
204
+ mbr = dim['A'] # 得到DimMember对象
205
+ mbr_container = dim['A', 'B'] # 得到MemberContainer对象
206
+
207
+ """
208
+ try:
209
+ if isinstance(item, str):
210
+ return self._members_memo[item]
211
+ else:
212
+ # for better error information
213
+ members = list(item)
214
+ for idx, item in enumerate(members):
215
+ members[idx] = self._members_memo[item]
216
+ return MemberContainer(*members)
217
+ except KeyError:
218
+ raise KeyError(f"Member '{item}' does not belong to current dimension.") from None
219
+
220
+ def resolve_member(self, member):
221
+ """
222
+ 返回维度树中指定的维度成员对象。
223
+
224
+ Args:
225
+ member: 维度成员,可为成员名或维度成员
226
+
227
+ Returns:
228
+ 指定的维度成员对象
229
+
230
+ Raises:
231
+ ValueError: 维度成员不存在于维度树中或者输入数据类型不符合要求
232
+ KeyError: member为成员名且该成员不存在于维度树中
233
+
234
+ """
235
+ if isinstance(member, DimMember):
236
+ if member not in self:
237
+ raise ValueError(f"Member '{member}' does not belong to current dimension.")
238
+ return member
239
+ elif isinstance(member, str):
240
+ if member in self._members_memo:
241
+ return self._members_memo[member]
242
+ else:
243
+ raise KeyError(f"Member '{member}' does not belong to current dimension.")
244
+ else:
245
+ raise TypeError(f"Expect str or {DimMember.__name__}, got {type(member).__name__}.")
246
+
247
+ def delete(self, member, update_memo=True):
248
+ """
249
+ 删除维度成员及其子树,删除的成员成员维度必须在维度树中。
250
+
251
+ Args:
252
+ member: 维度成员,可为成员名或维度成员
253
+ update_memo(bool): 是否更新 ``_members_memo`` 字典
254
+
255
+ Notes:
256
+ 为确保正常获取成员, ``update_memo`` 需设置为 ``True`` ,
257
+ 但如果需要连续删除多个成员时,建议删除最后一个时设置为 ``True`` ,
258
+ 其余为 ``False`` 。
259
+ 删除的维度成员可以为根节点,删除后树为空。
260
+
261
+ """
262
+ self.resolve_member(member).set_parent(None)
263
+ if member is self.root:
264
+ self.root = None
265
+ self._members_memo = {}
266
+ self.selected = {}
267
+ else:
268
+ if update_memo:
269
+ self._update_member_dict()
270
+
271
+ def __contains__(self, item):
272
+ """判断节点是否存在于维度树中"""
273
+ return item in self._members_memo.values()
274
+
275
+ def attach(self, node, attach_to, update_memo=True):
276
+ """
277
+ 将维度成员及其子树接入当前维度树指定节点,接入节点必须存在于维度中。
278
+
279
+ Args:
280
+ node(DimMember): 待加入的维度成员
281
+ attach_to(DimMember): 接入的节点
282
+ update_memo(bool): 是否更新 ``_members_memo``
283
+
284
+ Notes:
285
+ 为确保正常获取成员, ``update_memo`` 需设置为 ``True`` ,
286
+ 但如果需要连续加入多个成员时,建议加入最后一个时设置为 ``True`` ,
287
+ 其余为 ``False`` 。
288
+
289
+ """
290
+ member = self.resolve_member(attach_to)
291
+ node.set_parent(member)
292
+ if update_memo:
293
+ self._update_member_dict()
294
+
295
+ def to_multidict(self, *attrs, name=NAME_DFLT, parent_name=PNAME_DFLT,
296
+ show_all=False, incl_root=True, exclude=None):
297
+ """
298
+ 将维度树中的维度成员及其指定属性存储为字典。
299
+
300
+ Args:
301
+ *attrs(dict): 字典需要包含的维度成员指定属性
302
+ name(str): 维度成员名
303
+ parent_name(str): 维度成员的父节点名
304
+ incl_root(bool): 是否包含根节点
305
+ show_all(bool): 显示成员的所有属性
306
+ exclude(bool): 需要排除(不输出)的属性
307
+
308
+ Returns:
309
+ 包含所有维度成员的字典列表
310
+
311
+ Example:
312
+ .. code-block:: python
313
+
314
+ # 指定 base, children 属性存储在字典中
315
+ dim_dict = dim.to_multidict('base', 'children')
316
+ # 执行上述代码就会生成如下字典列表, 其中 base 和 children 的值为维度成员对象:
317
+ '''
318
+ [{'base': ..., 'children': ..., 'name': ..., 'parent_name': ...}, ...]
319
+ '''
320
+
321
+ """
322
+ family = self.root.family if incl_root else self.root.iter_descendants()
323
+ return [member.to_dict(
324
+ *attrs, name=name, parent_name=parent_name,
325
+ show_all=show_all, exclude=exclude
326
+ ) for member in family]
327
+
328
+ def to_json(self, *attrs, path):
329
+ """
330
+ 将维度对象中的维度成员及其指定属性存储在 ``path`` 中。
331
+
332
+ Args:
333
+ *attrs(dict): 需要存储的维度成员指定属性
334
+ path(str): 存储路径
335
+
336
+ """
337
+ with open(path, 'wt', encoding='utf8') as f:
338
+ json.dump(self.to_multidict(*attrs), f)
339
+
340
+ def save(self, conn=None, mode='replace'):
341
+ """
342
+ 保存维度成员
343
+
344
+ Args:
345
+ conn: 连接对象
346
+ mode(str): 保存编辑模式, ``replace`` 为增量编辑, ``update`` 为全量编辑
347
+
348
+ Raises:
349
+ ValueError: 选择的模式不是 ``replace`` 或 ``update``
350
+
351
+ """
352
+ valid_mode = ('replace', 'update')
353
+ if mode not in valid_mode:
354
+ raise ValueError(f"Unknown mode: '{mode}', valid modes are {valid_mode}.")
355
+
356
+ conn_info = conn or OPTION.system.conn_info
357
+ from deepfos.api.apifoundation import FoundationApi # noqa
358
+ api = FoundationApi(conn_info)
359
+ dim_data = self.to_multidict(show_all=True, incl_root=False)
360
+
361
+ if mode == 'replace':
362
+ api.save_dimension_member(self.name, dim_data, 1)
363
+ else:
364
+ for data in dim_data:
365
+ api.update_dimension_member(self.name, data)
366
+
367
+ def render(self):
368
+ return TreeRenderer().render(self.root)
369
+
370
+
371
+ class SortedDimension(Dimension):
372
+ def __init__(self, dim_name):
373
+ super().__init__(dim_name)
374
+
375
+ def __getitem__(self, item):
376
+ if not isinstance(item, slice):
377
+ return super().__getitem__(item)
378
+
379
+ # start, stop are both None
380
+ if item.start is None and item.stop is None:
381
+ mbrs = list(bfs(self.root))[item]
382
+ return MemberContainer(*mbrs)
383
+
384
+ step = item.step or 1
385
+
386
+ if item.start and item.stop:
387
+ # none of start, stop is None
388
+ node_start = super().__getitem__(item.start)
389
+ node_stop = super().__getitem__(item.stop)
390
+
391
+ if node_start.depth != node_stop.depth:
392
+ raise ValueError(f'{node_start}和{node_stop}不在同一层')
393
+
394
+ ancestor = node_start.common_ancestor(node_stop)
395
+ depth = node_start.depth - ancestor.depth
396
+ mbrs_same_depht = list(bfs(ancestor, depth=depth, include=False))
397
+ start = mbrs_same_depht.index(node_start)
398
+ stop = mbrs_same_depht.index(node_stop)
399
+ stop = stop + (1 if step > 0 else -1)
400
+ else:
401
+ # one of start, stop is None
402
+ valid_node = super().__getitem__(item.start or item.stop)
403
+ target_depth = valid_node.depth
404
+ mbrs_same_depht = list(
405
+ node for node in bfs(self.root, depth=target_depth)
406
+ if node.depth == target_depth)
407
+ idx = mbrs_same_depht.index(valid_node)
408
+
409
+ if item.stop is None:
410
+ start, stop = idx, None
411
+ else:
412
+ start, stop = None, idx + (1 if step > 0 else -1)
413
+
414
+ idx_slice = slice(start, stop, step)
415
+ return MemberContainer(*mbrs_same_depht[idx_slice])
416
+
417
+ @classmethod
418
+ def from_db(cls, dbconn, dim_name, name_col=NAME_DFLT, parent_name_col=PNAME_DFLT, extra_info=tuple()):
419
+ ins = cls(dim_name)
420
+ tree_creator = DBTreeCreator(dbconn, dim_name, name_col, parent_name_col, extra_info)
421
+ ins.root, ins._members_memo = tree_creator.create_tree()
422
+ ins.sort()
423
+ return ins
424
+
425
+ @classmethod
426
+ def from_df(cls, dim_name, df, name_col=NAME_DFLT, parent_name_col=PNAME_DFLT, extra_info=tuple()):
427
+ ins = cls(dim_name)
428
+ tree_creator = DataFrameTreeCreator(df, name_col, parent_name_col, extra_info)
429
+ ins.root, ins._members_memo = tree_creator.create_tree()
430
+ ins.sort()
431
+ return ins
432
+
433
+ @classmethod
434
+ def from_json(cls, dim_name, jsn, name_col=NAME_DFLT, parent_name_col=PNAME_DFLT, extra_info=tuple()):
435
+ ins = cls(dim_name)
436
+ tree_creator = JsonTreeCreator(jsn, name_col, parent_name_col, extra_info)
437
+ ins.root, ins._members_memo = tree_creator.create_tree()
438
+ ins.sort()
439
+ return ins
440
+
441
+ @classmethod
442
+ def from_api(cls, dim_name, api, name_col=NAME_DFLT, parent_name_col=PNAME_DFLT,
443
+ extra_info=tuple(), fetch_all=False):
444
+ ins = cls(dim_name)
445
+ tree_creator = ApiTreeCreator(dim_name, api, name_col, parent_name_col, extra_info, fetch_all)
446
+ ins.root, ins._members_memo = tree_creator.create_tree()
447
+ ins.sort()
448
+ return ins
449
+
450
+ def attach(self, node, attach_to, update_memo=True):
451
+ member = self.resolve_member(attach_to)
452
+ node.set_parent(member)
453
+ self.sort(root_node=member)
454
+ if update_memo:
455
+ self._update_member_dict()
456
+
457
+ def sort(self, func=lambda x: x.name, root_node=None):
458
+ """
459
+ 给指定节点的后继节点进行排序
460
+
461
+ Args:
462
+ func(function): 排序方式,默认为按照节点名进行排序
463
+ root_node(DimMember): 需要对后继节点进行排序的节点,默认为根节点
464
+
465
+ Returns:
466
+ 排序后的维度树
467
+ """
468
+ if not root_node:
469
+ root_node = self.root
470
+ for node in root_node.idescendant:
471
+ if len(node.children) > 1:
472
+ node.children.sort(key=func)