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,271 @@
1
+ import re
2
+ from deepfos.core.logictable.nodemixin import NodeMixin, TreeRenderer
3
+ from deepfos.lib.decorator import cached_property
4
+
5
+ _RE_ESCAPE_QUOTE = re.compile("^'(?P<body>.*)'")
6
+ _RE_ESCAPE_DQUOTE = re.compile('^"(?P<body>.*)"')
7
+
8
+
9
+ class ASTNode(NodeMixin):
10
+ def __init__(self, value: str):
11
+ self.value = value
12
+ self.is_quoted = False
13
+
14
+ def __str__(self):
15
+ return self.value
16
+
17
+ @cached_property
18
+ def eval(self):
19
+ """解析维度表达式,如果为数字,直接返回,否则提取维度操作返回"""
20
+ val = self.value
21
+ if val.isdigit():
22
+ return int(val)
23
+ for patt in (_RE_ESCAPE_QUOTE, _RE_ESCAPE_DQUOTE):
24
+ rslt = patt.match(val)
25
+ if rslt is not None:
26
+ self.is_quoted = True
27
+ return rslt.group('body')
28
+
29
+ return self.value
30
+
31
+
32
+ class ASTOpBase(NodeMixin):
33
+ """维度表达式语法树中的维度操作节点"""
34
+ def __init__(self, dim_obj, op_name):
35
+ """
36
+ Args:
37
+ dim_obj(Dimension): 维度表达式操作的维度树
38
+ op_name: 维度操作名
39
+ """
40
+ self._op_name = op_name
41
+ self._dim_obj = dim_obj
42
+
43
+ def solve(self):
44
+ """执行该节点的维度操作"""
45
+ args = self.collect_args()
46
+ return self.calc(args)
47
+
48
+ def calc(self, args):
49
+ raise NotImplementedError()
50
+
51
+ def eval(self, node: ASTNode):
52
+ return node.eval
53
+
54
+ def collect_args(self):
55
+ """收集维度操作所需的参数"""
56
+ args = []
57
+ for child in self.children:
58
+ if isinstance(child, ASTNode):
59
+ args.append(self.eval(child))
60
+ elif isinstance(child, ASTOpBase):
61
+ args.append(child.solve())
62
+ else:
63
+ raise TypeError(f"Expect type {ASTOpBase} or {ASTNode}, got {type(child)}")
64
+
65
+ return args
66
+
67
+ def _get_member(self, mbr):
68
+ """获取语法树中指定节点"""
69
+ if isinstance(mbr, str):
70
+ return self._dim_obj[mbr]
71
+ if isinstance(mbr, int):
72
+ return self._dim_obj[str(mbr)]
73
+ return mbr
74
+
75
+ def __str__(self):
76
+ """直接打印当前维度操作节点的操作名"""
77
+ return self._op_name
78
+
79
+
80
+ class ASTOpHierachy(ASTOpBase):
81
+ """
82
+ Operator class for getting dimension hierachy
83
+ 维度表达式语法树中的层级操作节点
84
+ """
85
+ def calc(self, args):
86
+ """
87
+ 计算当前节点的层级结果
88
+
89
+ Args:
90
+ args: 层级操作所需的参数
91
+
92
+ Returns:
93
+ 返回当前节点的层级结果列表
94
+
95
+ """
96
+ hierachy = self._op_name
97
+ member, reverse, *remain = args
98
+ order = -1 if reverse != 0 else 1
99
+
100
+ dim_container = self._dim_obj[str(member)]
101
+ if hierachy in {'Level', 'ILevel'}:
102
+ start, stop = remain
103
+ return getattr(dim_container, hierachy)[start:stop:order]
104
+ else:
105
+ return getattr(dim_container, hierachy)[::order]
106
+
107
+
108
+ class ASTOpAttr(ASTOpBase):
109
+ def eval(self, node: ASTNode):
110
+ val = node.eval
111
+ if node.is_quoted:
112
+ return {'N': False, 'Y': True}.get(val, val)
113
+ else:
114
+ return val
115
+
116
+ def calc(self, args):
117
+ """构建 ``filter`` 过滤字典"""
118
+ key, val = args
119
+ return {key: val}
120
+
121
+
122
+ class ASTOpFilter(ASTOpBase):
123
+ """过滤操作语法树节点"""
124
+ filter_map = {
125
+ "OrFilter": "or",
126
+ "AndFilter": "and",
127
+ "NorFilter": "nor",
128
+ "NAndFilter": "nand",
129
+ }
130
+
131
+ def calc(self, args):
132
+ _filter = self.filter_map[self._op_name]
133
+ dim_container, *conditions = args
134
+ dim_container = self._get_member(dim_container)
135
+
136
+ all_cond = {}
137
+ for cond in conditions:
138
+ all_cond.update(cond)
139
+
140
+ return dim_container.where(_filter, **all_cond)
141
+
142
+
143
+ class ASTOpRemove(ASTOpBase):
144
+ """删除操作语法树节点"""
145
+ def calc(self, args):
146
+ dim_container, *remain = args
147
+ dim_container = self._get_member(dim_container)
148
+
149
+ to_remove = []
150
+ for item in remain:
151
+ to_remove.append(self._get_member(item))
152
+
153
+ return dim_container.remove(*to_remove)
154
+
155
+
156
+ class ASTOpRoot(ASTOpBase):
157
+ """语法树根节点,将维度表达式最终结果收集,并存储到 ``Dimension`` 中的查询集"""
158
+ def __init__(self, dim_obj):
159
+ super().__init__(dim_obj, 'Root')
160
+ self._dim_obj = dim_obj
161
+
162
+ def calc(self, args):
163
+ to_select = (self._get_member(mbr) for mbr in args)
164
+ return self._dim_obj.select(*to_select)
165
+
166
+ def __str__(self):
167
+ return 'DummyRoot'
168
+
169
+
170
+ class ASTOpFactory:
171
+ """语法树维度操作节点工程,可以根据 ``cls_map`` 创建不同的维度操作节点"""
172
+ cls_map = {
173
+ 'Remove': ASTOpRemove,
174
+ "OrFilter": ASTOpFilter,
175
+ "AndFilter": ASTOpFilter,
176
+ "NorFilter": ASTOpFilter,
177
+ "NAndFilter": ASTOpFilter,
178
+ "Attr": ASTOpAttr,
179
+ "Base": ASTOpHierachy,
180
+ "IBase": ASTOpHierachy,
181
+ "Children": ASTOpHierachy,
182
+ "IChildren": ASTOpHierachy,
183
+ "Descendant": ASTOpHierachy,
184
+ "IDescendant": ASTOpHierachy,
185
+ "Level": ASTOpHierachy,
186
+ "ILevel": ASTOpHierachy,
187
+ }
188
+
189
+ def __new__(cls, dim, value):
190
+ target_cls = cls.cls_map.get(value)
191
+ if target_cls is None:
192
+ raise ValueError(f"Unknow Expression: {value}")
193
+ return target_cls(dim, value)
194
+
195
+
196
+ class DimExprAnalysor:
197
+ """基于语法树的维度表达式分析器"""
198
+ def __init__(self, dimension, dim_expr):
199
+ self.dim = dimension
200
+ self.dummy_root = ASTOpRoot(dimension)
201
+ for expr in dim_expr.split(";"):
202
+ self._gen_ast(expr)
203
+
204
+ def _gen_ast(self, expr):
205
+ """创建语法树"""
206
+ root_stack = [self.dummy_root]
207
+ dim = self.dim
208
+ end_bracket = False
209
+
210
+ tmp_string = []
211
+ last_char = ')'
212
+
213
+ for char in expr:
214
+ if char == '(':
215
+ node = ASTOpFactory(dim, ''.join(tmp_string))
216
+ tmp_string.clear()
217
+ node.set_parent(root_stack[-1])
218
+ root_stack.append(node)
219
+ elif char == ',':
220
+ if not end_bracket:
221
+ node = ASTNode(''.join(tmp_string))
222
+ tmp_string.clear()
223
+ node.set_parent(root_stack[-1])
224
+ else:
225
+ end_bracket = False
226
+ elif char == ')':
227
+ if not end_bracket:
228
+ node = ASTNode(''.join(tmp_string))
229
+ tmp_string.clear()
230
+ root = root_stack.pop(-1)
231
+ node.set_parent(root)
232
+ end_bracket = True
233
+ else:
234
+ root_stack.pop(-1)
235
+ else:
236
+ if char == ' ' and last_char in {')', ','}:
237
+ char = last_char # 去除连续空格
238
+ else:
239
+ tmp_string.append(char)
240
+
241
+ last_char = char
242
+
243
+ if tmp_string:
244
+ node = ASTNode(''.join(tmp_string))
245
+ node.set_parent(root_stack[-1])
246
+
247
+ def show_ast(self):
248
+ """
249
+ 打印语法树
250
+
251
+ Example:
252
+ .. code-block:: python
253
+
254
+ # dim 是加载维度表达式的维度树
255
+ dim_expr = DimExprAnalysor(dim, 'Base(node, 0)')
256
+ dim_expr.show_ast()
257
+ # 执行上述代码会打印如下所示的语法树:
258
+ '''
259
+ DummyRoot
260
+ └── Base
261
+ ├── node
262
+ └── 0
263
+ '''
264
+
265
+ """
266
+ print(TreeRenderer().render(self.dummy_root))
267
+ return self
268
+
269
+ def solve(self):
270
+ """计算维度表达式结果,返回已加载执行维度表达式的维度,结果存储在 `selected` 集合中"""
271
+ return self.dummy_root.solve()
@@ -0,0 +1,155 @@
1
+ from deepfos.core.logictable.nodemixin import ShareableNodeMixin
2
+ from ._base import MemberContainer, MemberBase, pack_filter, flatten
3
+
4
+
5
+ class GeneralMemberProxy(MemberContainer):
6
+ def __init__(self, *anchor_mbrs, hierarchy=None, node_attr=None):
7
+ super().__init__(*anchor_mbrs, hierarchy=hierarchy)
8
+ self.node_attr = node_attr
9
+
10
+ def _get_all_member(self):
11
+ super()._get_all_member()
12
+ return flatten(getattr(mbr, self.node_attr) for mbr in self.anchor_mbrs)
13
+
14
+
15
+ class LevelMemberProxy(GeneralMemberProxy):
16
+ @property
17
+ def members(self):
18
+ include = self.node_attr.startswith('i')
19
+ levels = flatten(list(mbr.iter_level(self.start, self.stop, include)) for mbr in self.anchor_mbrs)
20
+ return self.apply_filter(levels)
21
+
22
+ def __getitem__(self, item):
23
+ super().__getitem__(item)
24
+
25
+ start, stop = item.start, item.stop
26
+ if start is None:
27
+ raise ValueError("Start level is not specified.")
28
+
29
+ if stop is None:
30
+ raise ValueError("Stop level is not specified.")
31
+
32
+ if stop <= start:
33
+ raise ValueError("Stop level should be greater than start.")
34
+
35
+ self.start, self.stop = start, stop
36
+ return self
37
+
38
+ def __str__(self):
39
+ order = 1 if self._reversed else 0
40
+
41
+ if self.start is None or self.stop is None:
42
+ raise RuntimeError(
43
+ "start|stop level is not specified. "
44
+ "Use slice [] syntax to indicated level detail.")
45
+ raw_expr = ';'.join(
46
+ f"{self.hierarchy}({anchor},{order},{self.start},{self.stop})"
47
+ for anchor in self.anchor_mbrs)
48
+
49
+ return pack_filter(raw_expr, self._filters)
50
+
51
+
52
+ class AsMbrProxy:
53
+ def __init__(self, data_mapping, proxy_cls=GeneralMemberProxy):
54
+ self._dmap = data_mapping
55
+ self.proxy_cls = proxy_cls
56
+
57
+ def __get__(self, instance, owner=None):
58
+ proxy = self.proxy_cls(instance, hierarchy=self.name, node_attr=self._dmap)
59
+ return proxy
60
+
61
+ def __set_name__(self, owner, name):
62
+ self.name = name
63
+
64
+
65
+ class DimMember(MemberBase, ShareableNodeMixin):
66
+ def __init__(self, name):
67
+ super(DimMember, self).__init__(name)
68
+ self.extra_attrs = ()
69
+
70
+ #: 寻找以当前节点为根的维度树的叶子节点。
71
+ Base = AsMbrProxy("base")
72
+ #: 寻找以当前节点为根的维度树的叶子节点,包含自身。
73
+ IBase = AsMbrProxy("ibase")
74
+ #: 寻找当前节点的直接孩子节点。
75
+ Children = AsMbrProxy("children")
76
+ #: 寻找当前节点的直接孩子节点, 包含自身。
77
+ IChildren = AsMbrProxy("ichildren")
78
+ #: 寻找当前节点的后继节点。
79
+ Descendant = AsMbrProxy("descendant")
80
+ #: 寻找当前节点的后继节点,包含自身。
81
+ IDescendant = AsMbrProxy("idescendant")
82
+ #: level节点。
83
+ Level = AsMbrProxy("level", LevelMemberProxy)
84
+ #: level节点,包含自身。
85
+ ILevel = AsMbrProxy("ilevel", LevelMemberProxy)
86
+
87
+ @property
88
+ def data(self):
89
+ """返回当前维度成员的成员名, ``list`` 类型。"""
90
+ return [self.name]
91
+
92
+ def to_dict(self, *attrs, name, parent_name, show_all=False, exclude=None):
93
+ """
94
+ 将当前维度成员及其指定属性存储为字典。
95
+
96
+ Args:
97
+ *attrs(dict): 字典需要包含的维度成员指定属性
98
+ name(str): 维度成员名
99
+ parent_name(str): 维度成员的父节点名
100
+ show_all(bool): 显示成员的所有属性
101
+ exclude: 需要排除(不输出)的属性
102
+
103
+ Returns:
104
+ 包含当前维度成员指定信息的字典
105
+
106
+ """
107
+ if show_all:
108
+ attrs = self.extra_attrs
109
+
110
+ if isinstance(exclude, str):
111
+ exclude = {exclude}
112
+ else:
113
+ exclude = exclude or set()
114
+
115
+ rtn = {attr: getattr(self, attr) for attr in attrs if attr not in exclude}
116
+ rtn[name] = self.name
117
+ parent = self.parent
118
+ rtn[parent_name] = None if not parent else [p.name for p in parent]
119
+ return rtn
120
+
121
+ def where(self, method, **kwargs):
122
+ """
123
+ 判断当前维度成员的属性按照 ``method`` 是否符合指定属性。
124
+
125
+ Args:
126
+ method(str): 判断方法,包含 ``and` , ``nand`` , ``or`` , ``nor``
127
+ **kwargs: 要求的属性
128
+
129
+ Returns:
130
+ 成员对象容器
131
+
132
+ Warnings:
133
+ 返回值是成员对象容器,需要调用容器的 ``members`` 或 ``data`` 才能执行操作。
134
+ 此函数一般用于和 ``Dimension`` 的 ``select`` 搭配使用,不推荐单独使用。
135
+
136
+ """
137
+ return MemberContainer(self).where(method, **kwargs)
138
+
139
+ def remove(self, *to_remove):
140
+ """
141
+ 移除当前成员对象
142
+
143
+ Args:
144
+ *to_remove(DimMember): 需要移除的成员对象
145
+
146
+ Returns:
147
+ 成员对象容器
148
+
149
+ Warnings:
150
+ 返回值是成员对象容器,需要调用容器的 ``members`` 才能执行操作。
151
+ 如果当前成员对象存在于 ``*to_remove`` 中,则移除当前成员对象,否则,直接返回。
152
+ 此函数一般用于和 ``Dimension`` 的 ``select`` 搭配使用,不推荐单独使用。
153
+
154
+ """
155
+ return MemberContainer(self).remove(*to_remove)
@@ -0,0 +1,22 @@
1
+ from ._base import DimensionBase, MemberBase
2
+ from deepfos.element.dimension import Dimension as EleDimension
3
+
4
+
5
+ class ElementDimension(DimensionBase):
6
+ def __init__(self, dimension: EleDimension):
7
+ self.ele = dimension
8
+ super(ElementDimension, self).__init__(dimension.element_name)
9
+
10
+ def load_expr(self, expr) -> 'ElementDimension':
11
+ self.selected = selected = []
12
+ for record in self.ele.query(
13
+ expr, fields=['name', 'aggweight'],
14
+ as_model=False
15
+ ):
16
+ mbr = MemberBase(record['name'])
17
+ mbr.weight = record['aggweight']
18
+ selected.append(mbr)
19
+ return self
20
+
21
+ def __getitem__(self, item):
22
+ return item
@@ -0,0 +1,99 @@
1
+
2
+ __all__ = ['AndFilter', 'NAndFilter', 'OrFilter', 'NorFilter', 'RemoveFilter', 'BaseFilter']
3
+
4
+ import functools
5
+
6
+ _NOTSET = object()
7
+
8
+
9
+ class BaseFilter:
10
+ def __init__(self, attr_kv_pairs, objs=None):
11
+ """
12
+ Args:
13
+ attr_kv_pairs(dict): 属性键值对
14
+ objs: 被过滤的对象
15
+ """
16
+ self.objs = objs
17
+ self.attr_kv_pairs = attr_kv_pairs
18
+
19
+ def iter_single(self, obj):
20
+ for attr, val in self.attr_kv_pairs.items():
21
+ actual = getattr(obj, attr, _NOTSET)
22
+ if actual is _NOTSET:
23
+ yield False
24
+ else:
25
+ yield val == actual
26
+
27
+ def filter_strategy(self, obj):
28
+ """过滤策略"""
29
+ raise NotImplementedError()
30
+
31
+ def apply(self):
32
+ """执行过滤策略"""
33
+ return self.apply_to(self.objs)
34
+
35
+ def apply_to(self, objs):
36
+ """返回符合过滤策略的对象列表"""
37
+ return [obj for obj in objs if self.filter_strategy(obj)]
38
+
39
+ def __str__(self):
40
+ return self.__class__.__name__
41
+
42
+
43
+ class AndFilter(BaseFilter):
44
+ """筛选符合全部属性要求的节点"""
45
+ def filter_strategy(self, obj):
46
+ return all(self.iter_single(obj))
47
+
48
+
49
+ class NAndFilter(AndFilter):
50
+ """筛选除了符合全部属性要求节点的节点"""
51
+ def filter_strategy(self, obj):
52
+ return not super().filter_strategy(obj)
53
+
54
+
55
+ class OrFilter(BaseFilter):
56
+ """筛选符合任意一项属性要求的节点"""
57
+ def filter_strategy(self, obj):
58
+ return any(self.iter_single(obj))
59
+
60
+
61
+ class NorFilter(OrFilter):
62
+ """筛选不符合全部属性要求的节点"""
63
+ def filter_strategy(self, obj):
64
+ return not super().filter_strategy(obj)
65
+
66
+
67
+ class RemoveFilter:
68
+ def __init__(self, to_remove, mbr_getter=None):
69
+ """
70
+ Args:
71
+ to_remove(list): 列表元素为 ``DimMember`` 类型,需要移除的节点
72
+ mbr_getter:
73
+ """
74
+ self.to_remove = to_remove
75
+ self.getter = mbr_getter or (lambda x: x)
76
+
77
+ def apply_to(self, total):
78
+ """
79
+ Args:
80
+ total(list): ``DimMember`` 对象列表,从中移除 ``to_remove`` 中的对象
81
+
82
+ Returns:
83
+ 返回 ``DimMember`` 对象列表
84
+
85
+ Tips:
86
+ 如果需要被移除的对象不存在于 ``total`` 中,则不做任何事
87
+
88
+ """
89
+ if not self.to_remove:
90
+ return total
91
+ to_remove = functools.reduce(
92
+ lambda x, y: x | y,
93
+ (set(self.getter(obj)) for obj in self.to_remove),
94
+ set()
95
+ )
96
+ return [obj for obj in total if obj not in to_remove]
97
+
98
+ def __str__(self):
99
+ return 'Remove'