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,506 @@
1
+ import functools
2
+ from abc import ABC, abstractmethod
3
+ from collections.abc import Iterable
4
+ from contextlib import contextmanager
5
+ from operator import attrgetter
6
+ from typing import List
7
+ from deepfos.lib.constant import SHAREDMEMBER
8
+ from .filters import *
9
+ from .dimexpr import DimExprAnalysor
10
+
11
+ filter_map = {
12
+ "or": OrFilter,
13
+ "and": AndFilter,
14
+ "nor": NorFilter,
15
+ "nand": NAndFilter,
16
+ }
17
+
18
+ NAME_DFLT = "name"
19
+ PNAME_DFLT = "parent_name"
20
+ IS_SHARED_DFLT = SHAREDMEMBER
21
+
22
+
23
+ def pack_filter(member_expr, filters):
24
+ """给维度表达式增加 ``Attr`` , ``Remove`` ,以及各种 ``Filter`` """
25
+ if not filters:
26
+ return member_expr
27
+
28
+ rtn = member_expr
29
+ for fltr in filters:
30
+ if isinstance(fltr, BaseFilter):
31
+ attr_conds = (f"Attr({k},{v!r})" for k, v in fltr.attr_kv_pairs.items())
32
+ rtn = f"{fltr}({rtn},{','.join(attr_conds)})"
33
+ else:
34
+ rtn = f"{fltr}({rtn},{','.join(map(str, fltr.to_remove))})"
35
+
36
+ return rtn
37
+
38
+
39
+ def flatten(nested_list):
40
+ """
41
+ 展开多级列表
42
+
43
+ Args:
44
+ nested_list: 多级列表
45
+
46
+ Returns:
47
+ 只含简单元素的列表
48
+
49
+ """
50
+ rtn = []
51
+ for item in nested_list:
52
+ if isinstance(item, list):
53
+ rtn.extend(flatten(item))
54
+ else:
55
+ rtn.append(item)
56
+ return rtn
57
+
58
+
59
+ class AbstractMember(ABC):
60
+ @abstractmethod
61
+ def members(self):
62
+ pass
63
+
64
+ @abstractmethod
65
+ def __str__(self):
66
+ pass
67
+
68
+ def contribute(self, value):
69
+ weight = getattr(self, 'weight', 1)
70
+ if not weight:
71
+ weight = 1
72
+ return value * float(weight)
73
+
74
+ def calculate(self, **args):
75
+ return sum(args.values())
76
+
77
+
78
+ class MemberBase(AbstractMember):
79
+ def __init__(self, name):
80
+ self.name = name
81
+
82
+ @property
83
+ def members(self):
84
+ """
85
+ 由 `DimMember`` 继承,返回只包含节点自身列表
86
+ """
87
+ return [self]
88
+
89
+ def __str__(self):
90
+ return self.name
91
+
92
+
93
+ class MemberContainer(AbstractMember):
94
+ """维度成员容器,成员容器旨在一次性使用。"""
95
+ def __init__(self, *anchor_mbrs, hierarchy=None):
96
+ self.anchor_mbrs = list(anchor_mbrs)
97
+ # self.anchor_mbrs = anchor_mbr if isinstance(anchor_mbr, list) else [anchor_mbr]
98
+ self.hierarchy = hierarchy
99
+ self._reversed = False
100
+ self._filters = []
101
+
102
+ def _get_all_member(self):
103
+ """返回容器中的所有维度成员,如果维度成员含有层级,则以层级结果代替原维度成员。"""
104
+ if self.hierarchy is None:
105
+ return self.anchor_mbrs
106
+
107
+ @property
108
+ def members(self):
109
+ """
110
+ 返回容器中所有维度成员, ``reverse`` 设置返回顺序, 默认正序。
111
+ 如果有过滤操作,则先执行过滤,再返回结果。
112
+ """
113
+ reverse_flag = -1 if self._reversed else 1
114
+ return self.apply_filter(self._get_all_member()[::reverse_flag])
115
+
116
+ @property
117
+ def data(self):
118
+ """返回容器中所有维度成员的维度成员名。"""
119
+ return [member.name for member in self.members]
120
+
121
+ def apply_filter(self, total):
122
+ """
123
+ 执行过滤器列表中所有过滤器。
124
+
125
+ Args:
126
+ total(list): 需要过滤的所有维度成员
127
+
128
+ Returns:
129
+ 符合过滤条件的维度成员列表,存储在 ``selected`` 中。
130
+
131
+ """
132
+ remain = total
133
+ for fltr in self._filters:
134
+ remain = fltr.apply_to(remain)
135
+ return remain
136
+
137
+ def reverse(self):
138
+ """逆序输出维度成员。"""
139
+ self._reversed = True
140
+ return self
141
+
142
+ def __getitem__(self, item):
143
+ """
144
+ 正序或逆序输出容器中的维度成员。
145
+
146
+ Examples:
147
+ literal blocks::
148
+ ``MemberContainer``[::1]
149
+
150
+ ``MemberContainer``[1:3:1]
151
+
152
+ Warnings:
153
+ 只支持正序或者逆序输出全部维度成员,不支持只输出切片的部分成员。
154
+ 上面两个例子的效果相同。
155
+
156
+ """
157
+ if not isinstance(item, slice):
158
+ raise TypeError("Only slice type is supported")
159
+ if item.step == -1:
160
+ self._reversed = True
161
+ return self
162
+
163
+ def __str__(self):
164
+ """
165
+ 显示当前维度成员集对应的维度表达式。
166
+
167
+ Warning:
168
+ 调用的 ``pack_filter`` 中会调用 ``str`` 方法,因此这里有递归。
169
+
170
+ """
171
+ order = 1 if self._reversed else 0
172
+
173
+ total_expr = []
174
+ for mbr in self.anchor_mbrs:
175
+ if self.hierarchy is None:
176
+ expr = str(mbr)
177
+ else:
178
+ expr = f"{self.hierarchy}({mbr},{order})"
179
+ total_expr.append(pack_filter(expr, self._filters))
180
+ return ';'.join(total_expr)
181
+
182
+ def where(self, method, **kwargs):
183
+ """
184
+ 筛选维度成员。
185
+
186
+ Args:
187
+ method(str): 筛选维度成员的方法,共有 ``and`` , ``nand`` , ``or`` , ``nor`` 四种
188
+ **kwargs(dict): 筛选条件
189
+
190
+ Notes:
191
+ 不返回结果,只有在显示容器中的维度成员时,才会执行所有过滤器,获得结果。
192
+
193
+ Raises:
194
+ ValueError: ``method`` 不在于四种方法中或者筛选条件 ``**kwargs`` 为空。
195
+
196
+ """
197
+ filter_cls = filter_map.get(method.lower())
198
+
199
+ if filter_cls is None:
200
+ raise ValueError(f"Unsupported method: {method}.")
201
+
202
+ if not kwargs:
203
+ raise ValueError("Filter condition should not be empty.")
204
+
205
+ self._filters.append(filter_cls(kwargs))
206
+ return self
207
+
208
+ def remove(self, *to_remove: AbstractMember):
209
+ """
210
+ 从已选择的维度成员中移除维度成员。
211
+
212
+ Args:
213
+ *to_remove(DimMember): 需要从维度成员容器中移除的维度成员
214
+
215
+ Notes:
216
+ 不返回任何结果,只将过滤器加入到过滤器列表中。
217
+
218
+ """
219
+ to_remove = _as_abstract_member(to_remove)
220
+ self._filters.append(RemoveFilter(to_remove, attrgetter('members')))
221
+ return self
222
+
223
+ @property
224
+ def attr(self):
225
+ """
226
+ 属性映射,返回容器中维度成员对应的属性值,
227
+ 属性为多个时,对每个维度成员都进行指定属性的返回。
228
+ """
229
+ return AttrMapper(self.members)
230
+
231
+
232
+ def finalize(func):
233
+ @functools.wraps(func)
234
+ def wrapper(self, *args, **kwargs):
235
+ for idx, obj in enumerate(self.selected):
236
+ if isinstance(obj, Puppet):
237
+ self.selected[idx] = obj.puppet_apply()
238
+ return func(self, *args, **kwargs)
239
+ return wrapper
240
+
241
+
242
+ class DimensionBase:
243
+ """维度基类"""
244
+ def __init__(self, dim_name=None):
245
+ self.name = dim_name
246
+ self.selected = []
247
+
248
+ def select(self, *dim_members: AbstractMember):
249
+ """选择维度成员
250
+
251
+ Args:
252
+ *dim_members: 需要加入到 ``selected`` 中的维度成员
253
+
254
+ Returns:
255
+ 不返回任何结果,只改变 ``selected`` 中的维度成员
256
+
257
+ Raises:
258
+ ValueError: 加入的维度成员 ``dim_members`` 为空
259
+ """
260
+ if not dim_members:
261
+ raise ValueError("No dimension member to select.")
262
+
263
+ self.selected = _as_abstract_member(dim_members)
264
+ return self
265
+
266
+ def to_expr(self):
267
+ """输出维度表达式
268
+
269
+ 获取当前查询集下,等价的维度表达式
270
+
271
+ Example:
272
+ .. code-block:: python
273
+
274
+ # 向 selected 集中添加维度成员
275
+ dim.select(dim['Q1', 'Q2', 'Q3', 'Q4'])
276
+ print(dim.to_expr())
277
+ # 设维度树名为Dimension,则对应的维度表达式如下所示:
278
+ '''
279
+ Dimension{Q1;Q2;Q3;Q4}
280
+ '''
281
+
282
+ """
283
+ return f"{self.name}{{{self.expr_body}}}"
284
+
285
+ @property
286
+ @finalize
287
+ def expr_body(self) -> str:
288
+ """维度表达式花括号内的部分"""
289
+ return ';'.join(map(str, self.selected))
290
+
291
+ @property
292
+ @finalize
293
+ def members(self):
294
+ """获取当前查询集下,所有维度成员对象"""
295
+ return sum((member.members for member in self.selected), [])
296
+
297
+ @property
298
+ def data(self) -> List[str]:
299
+ """获取当前查询集下,所有维度成员名"""
300
+ return [member.name for member in self.members]
301
+
302
+ @property
303
+ def activated(self):
304
+ """维度是否激活,等价于是否选择了维度成员"""
305
+ return len(self.selected) > 0
306
+
307
+ @property
308
+ def loc(self):
309
+ """单次选择维度成员,在清空 ``selected`` 集后加入"""
310
+ return Locator(self)
311
+
312
+ @property
313
+ def exloc(self):
314
+ """单次选择维度成员,增量加入到 ``selected`` 集"""
315
+ return Locator(self, append=True)
316
+
317
+ def __getitem__(self, item):
318
+ raise NotImplementedError()
319
+
320
+ @contextmanager
321
+ def multi_loc(self, do_remove=False):
322
+ """在上下文中多次选择维度成员"""
323
+ self.selected = []
324
+ if do_remove:
325
+ yield Locator(self, append=True), Remover(self)
326
+ else:
327
+ yield Locator(self, append=True)
328
+
329
+ def load_expr(self, expr) -> 'DimensionBase':
330
+ """
331
+ 加载维度表达式
332
+
333
+ Args:
334
+ expr(str): 维度表达式
335
+
336
+ Returns:
337
+ 不返回任何结果,改变查询集
338
+
339
+ Notes:
340
+ 维度表达式中的维度成员不需要带引号,使用 ``filter`` 时不能直接使用字典形式的键值对,
341
+ 而是使用 ``Attr`` 获取属性作为键,而后跟上值,在传入的时候,会以字典的形式传入,
342
+ 此时将传入的多参数转变成键值字典,所有调用的属性或者函数必须首字母大写。
343
+
344
+ Examples:
345
+ 较为复杂的唯独表达式例,其中 ``uds`` 为额外属性, ``value`` 为指定的属性值:
346
+
347
+ .. code-block:: python
348
+
349
+ dim.load_expr("AndFilter(Base(#root, 0), Attr(uds, value))")
350
+
351
+ """
352
+ return DimExprAnalysor(self, expr).solve()
353
+
354
+ @contextmanager
355
+ def load_expr_temporary(self, expr):
356
+ """一次性加载维度表达式,存储结果"""
357
+ selected_bak = self.selected[:]
358
+ try:
359
+ self.load_expr(expr)
360
+ yield
361
+ finally:
362
+ self.selected = selected_bak
363
+
364
+ @property
365
+ def attr(self):
366
+ """属性映射
367
+
368
+ 返回查询集中维度成员对应的属性值,
369
+ 属性为多个时,对每个维度成员都进行指定属性的返回
370
+ """
371
+ return AttrMapper(self.members)
372
+
373
+ @finalize
374
+ def classify_selected(self):
375
+ """分类查询集
376
+
377
+ 将查询集按照 ``DimMember`` 类型和 ``MemberContainer`` 类型分成两类。
378
+
379
+ Returns:
380
+ ``DimMember`` 类型的对象列表和 ``MemberContainer`` 类型的对象列表
381
+
382
+ """
383
+ members = []
384
+ mbr_containers = []
385
+
386
+ for mbr in self.selected:
387
+ if isinstance(mbr, MemberBase):
388
+ members.append(mbr)
389
+ elif isinstance(mbr, MemberContainer):
390
+ mbr_containers.append(mbr)
391
+ return members, mbr_containers
392
+
393
+ def clear(self):
394
+ self.selected.clear()
395
+
396
+
397
+ class ATTR:
398
+ __slots__ = ('attr', 'callable', 'args', 'kwargs')
399
+
400
+ def __init__(self, attr):
401
+ self.attr = attr
402
+ self.callable = False
403
+ self.args = None
404
+ self.kwargs = None
405
+
406
+
407
+ class Puppet:
408
+ """
409
+ 链式调用代理
410
+
411
+ Examples:
412
+ 简单的代理,此时不执行操作:
413
+ literal blocks::
414
+ dim.loc('Q1').iter_to_root()
415
+
416
+ """
417
+ def __init__(self, bound):
418
+ """bound的类型时DimMember"""
419
+ self.__bound = bound
420
+ self.__stack = []
421
+
422
+ def __getattr__(self, item):
423
+ """成员属性"""
424
+ self.__stack.append(ATTR(item))
425
+ return self
426
+
427
+ def __call__(self, *args, **kwargs):
428
+ """成员方法"""
429
+ last_attr = self.__stack[-1]
430
+ last_attr.callable = True
431
+ last_attr.args = args
432
+ last_attr.kwargs = kwargs
433
+
434
+ def puppet_apply(self):
435
+ rslt = self.__bound
436
+ for attr in self.__stack:
437
+ if attr.callable:
438
+ rslt = getattr(rslt, attr.attr)(*attr.args, **attr.kwargs)
439
+ else:
440
+ rslt = getattr(rslt, attr.attr)
441
+ return rslt
442
+
443
+
444
+ class Locator:
445
+ """选择维度成员加入 ``selected`` 集合中"""
446
+ def __init__(self, dim_obj: DimensionBase, append=False):
447
+ """
448
+ Args:
449
+ dim_obj: 维度树
450
+ append: 选择增量还是全量,增量则会在原基础上加入,全量则清除后加入
451
+
452
+ Warnings:
453
+ 默认将当前selected集合中的维度成员加入
454
+ """
455
+ self._append = append
456
+ self._obj = dim_obj
457
+ self._puppets = dim_obj.selected
458
+
459
+ def __call__(self, *items):
460
+ """items为维度成员名"""
461
+ if len(items) == 1:
462
+ item = items[0]
463
+ else:
464
+ item = items
465
+ puppet = Puppet(self._obj[item])
466
+ if not self._append:
467
+ self._puppets.clear()
468
+ self._puppets.append(puppet)
469
+ return puppet
470
+
471
+
472
+ class Remover:
473
+ def __init__(self, dim_obj: DimensionBase):
474
+ self._obj = dim_obj
475
+
476
+ def __call__(self, *items):
477
+ if len(items) == 1:
478
+ item = items[0]
479
+ else:
480
+ item = items
481
+ puppet = Puppet(self._obj[item])
482
+ return puppet
483
+
484
+
485
+ class AttrMapper:
486
+ """属性映射"""
487
+ def __init__(self, obj_itor):
488
+ self._obj_itor = obj_itor
489
+
490
+ def __getitem__(self, item):
491
+ if isinstance(item, str):
492
+ return [getattr(obj, item) for obj in self._obj_itor]
493
+
494
+ elif isinstance(item, Iterable):
495
+ return [self[it] for it in item]
496
+
497
+
498
+ def _as_abstract_member(members) -> List[AbstractMember]:
499
+ rtn = []
500
+ for mbr in members:
501
+ if isinstance(mbr, Puppet):
502
+ mbr = mbr.puppet_apply()
503
+ if not isinstance(mbr, AbstractMember):
504
+ raise TypeError(f"Expect type: {AbstractMember}, got {type(mbr)}.")
505
+ rtn.append(mbr)
506
+ return rtn
@@ -0,0 +1,184 @@
1
+ import pandas as pd
2
+ from deepfos.options import OPTION
3
+ from .dimmember import DimMember
4
+
5
+ __all__ = [
6
+ 'TreeCreator',
7
+ 'JsonTreeCreator', 'DBTreeCreator',
8
+ 'DataFrameTreeCreator', 'ApiTreeCreator'
9
+ ]
10
+
11
+
12
+ class TreeCreator:
13
+ def __init__(self, raw_data):
14
+ self.raw = raw_data
15
+
16
+ def iter_node(self):
17
+ """迭代节点, 取出数据中的每条元数据"""
18
+ raise NotImplementedError()
19
+
20
+ def get_node_name(self, node):
21
+ """获取节点名"""
22
+ raise NotImplementedError()
23
+
24
+ def get_node_parent_name(self, node):
25
+ """获取父节点名"""
26
+ raise NotImplementedError()
27
+
28
+ def get_node_is_shared(self, node):
29
+ """获取父节点名"""
30
+ raise NotImplementedError()
31
+
32
+ def set_extra_attrs(self, member, node):
33
+ """设置节点额外属性"""
34
+ raise NotImplementedError()
35
+
36
+ def create_tree(self):
37
+ """
38
+ 建树
39
+
40
+ Raises:
41
+ ValueError: 节点名不为 ``str`` 或者多个根节点
42
+ ValueError: 无根节点
43
+ """
44
+ dim_memo = {}
45
+
46
+ root = None
47
+ for node in self.iter_node():
48
+ name = self.get_node_name(node)
49
+ is_shared = self.get_node_is_shared(node)
50
+
51
+ if name not in dim_memo:
52
+ dim_memo[name] = DimMember(name)
53
+ member = dim_memo[name]
54
+
55
+ if is_shared:
56
+ shared_mbr = DimMember(name)
57
+ self.set_extra_attrs(shared_mbr, node)
58
+ member.add_shared(shared_mbr)
59
+ continue
60
+
61
+ self.set_extra_attrs(member, node)
62
+
63
+ parent_name = self.get_node_parent_name(node)
64
+
65
+ if not isinstance(parent_name, str) or not parent_name:
66
+ if root is not None:
67
+ raise ValueError("Cannot create tree because there are more than one root in data.")
68
+ root = member
69
+ else:
70
+ if parent_name not in dim_memo:
71
+ parent = DimMember(parent_name)
72
+ dim_memo[parent_name] = parent
73
+ member.set_parent(dim_memo[parent_name])
74
+
75
+ if root is None:
76
+ raise ValueError("No root found from given data.")
77
+
78
+ return root, dim_memo
79
+
80
+
81
+ class DataFrameTreeCreator(TreeCreator):
82
+ def __init__(self, raw_data, name_col, parent_name_col, is_shared_col, extra_attrs=None):
83
+ super().__init__(raw_data)
84
+ self.is_shared_col = is_shared_col
85
+ self.parent_name_col = parent_name_col
86
+ self.name_col = name_col
87
+ self.extra_attrs = extra_attrs
88
+
89
+ def iter_node(self):
90
+ for row in self.raw.itertuples(index=False):
91
+ yield row
92
+
93
+ def get_node_name(self, node):
94
+ return getattr(node, self.name_col)
95
+
96
+ def get_node_parent_name(self, node):
97
+ return getattr(node, self.parent_name_col)
98
+
99
+ def get_node_is_shared(self, node):
100
+ return getattr(node, self.is_shared_col)
101
+
102
+ def set_extra_attrs(self, member, node):
103
+ """
104
+ 设置节点额外属性
105
+
106
+ Args:
107
+ member(DimMember): 节点对象
108
+ node: 一条元数据
109
+ """
110
+ extra_attrs = self.extra_attrs or self.raw.columns
111
+
112
+ for attr in extra_attrs:
113
+ if hasattr(node, attr):
114
+ val = getattr(node, attr)
115
+ else:
116
+ val = getattr(node, attr.lower(), None)
117
+
118
+ setattr(member, attr, val)
119
+ member.extra_attrs = tuple(extra_attrs)
120
+
121
+
122
+ class DBTreeCreator(DataFrameTreeCreator):
123
+ def __init__(self, dbconn, dimname, name_col, parent_name_col, is_shared_col, extra_attrs=None):
124
+ self.dimname = dimname
125
+ self.dbconn = dbconn
126
+
127
+ super().__init__(self.get_raw_data(), name_col, parent_name_col, is_shared_col, extra_attrs)
128
+
129
+ def get_raw_data(self):
130
+ """从数据库中筛选出数据表建树"""
131
+ return self.dbconn.query_dfs(f"SELECT * FROM {self.get_dim_table()}")
132
+
133
+ def get_dim_table(self):
134
+ sql = f"SELECT table_dimension FROM app{OPTION.system.app_id}_dimension_info WHERE name='{self.dimname}'"
135
+ return self.dbconn.query_dfs(sql).iloc[0, 0]
136
+
137
+
138
+ class JsonTreeCreator(DataFrameTreeCreator):
139
+ def iter_node(self):
140
+ for node in self.raw:
141
+ yield node
142
+
143
+ def get_node_name(self, node):
144
+ return node.get(self.name_col)
145
+
146
+ def get_node_parent_name(self, node):
147
+ return node.get(self.parent_name_col)
148
+
149
+ def get_node_is_shared(self, node):
150
+ return node.get(self.is_shared_col)
151
+
152
+ def set_extra_attrs(self, member, node):
153
+ if self.extra_attrs is None:
154
+ return
155
+
156
+ member.extra_attrs = tuple(self.extra_attrs)
157
+
158
+ for attr in self.extra_attrs:
159
+ if attr in node:
160
+ val = node[attr]
161
+ else:
162
+ val = node.get(attr.lower(), None)
163
+ setattr(member, attr, val)
164
+
165
+
166
+ class ApiTreeCreator(DataFrameTreeCreator):
167
+ def __init__(
168
+ self, dimname, api,
169
+ name_col, parent_name_col, is_shared_col,
170
+ extra_attrs=None, fetch_all=False
171
+ ):
172
+ super().__init__(None, name_col, parent_name_col, is_shared_col, extra_attrs)
173
+ self.dimname = dimname
174
+ self.api = api
175
+ self.fetch_all = fetch_all
176
+ self.raw = self.get_raw_data()
177
+
178
+ def get_raw_data(self):
179
+ if self.fetch_all:
180
+ cols = ''
181
+ else:
182
+ cols = ','.join((*self.extra_attrs, self.name_col, self.parent_name_col))
183
+ rslt = self.api.api_get_dimmbr(self.dimname + "{IDescendant(#root,0)}", cols, '1')["resultList"]
184
+ return pd.DataFrame(rslt)