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.
- deepfos/__init__.py +6 -0
- deepfos/_version.py +21 -0
- deepfos/algo/__init__.py +0 -0
- deepfos/algo/graph.py +171 -0
- deepfos/algo/segtree.py +31 -0
- deepfos/api/V1_1/__init__.py +0 -0
- deepfos/api/V1_1/business_model.py +119 -0
- deepfos/api/V1_1/dimension.py +599 -0
- deepfos/api/V1_1/models/__init__.py +0 -0
- deepfos/api/V1_1/models/business_model.py +1033 -0
- deepfos/api/V1_1/models/dimension.py +2768 -0
- deepfos/api/V1_2/__init__.py +0 -0
- deepfos/api/V1_2/dimension.py +285 -0
- deepfos/api/V1_2/models/__init__.py +0 -0
- deepfos/api/V1_2/models/dimension.py +2923 -0
- deepfos/api/__init__.py +0 -0
- deepfos/api/account.py +167 -0
- deepfos/api/accounting_engines.py +147 -0
- deepfos/api/app.py +626 -0
- deepfos/api/approval_process.py +198 -0
- deepfos/api/base.py +983 -0
- deepfos/api/business_model.py +160 -0
- deepfos/api/consolidation.py +129 -0
- deepfos/api/consolidation_process.py +106 -0
- deepfos/api/datatable.py +341 -0
- deepfos/api/deep_pipeline.py +61 -0
- deepfos/api/deepconnector.py +36 -0
- deepfos/api/deepfos_task.py +92 -0
- deepfos/api/deepmodel.py +188 -0
- deepfos/api/dimension.py +486 -0
- deepfos/api/financial_model.py +319 -0
- deepfos/api/journal_model.py +119 -0
- deepfos/api/journal_template.py +132 -0
- deepfos/api/memory_financial_model.py +98 -0
- deepfos/api/models/__init__.py +3 -0
- deepfos/api/models/account.py +483 -0
- deepfos/api/models/accounting_engines.py +756 -0
- deepfos/api/models/app.py +1338 -0
- deepfos/api/models/approval_process.py +1043 -0
- deepfos/api/models/base.py +234 -0
- deepfos/api/models/business_model.py +805 -0
- deepfos/api/models/consolidation.py +711 -0
- deepfos/api/models/consolidation_process.py +248 -0
- deepfos/api/models/datatable_mysql.py +427 -0
- deepfos/api/models/deep_pipeline.py +55 -0
- deepfos/api/models/deepconnector.py +28 -0
- deepfos/api/models/deepfos_task.py +386 -0
- deepfos/api/models/deepmodel.py +308 -0
- deepfos/api/models/dimension.py +1576 -0
- deepfos/api/models/financial_model.py +1796 -0
- deepfos/api/models/journal_model.py +341 -0
- deepfos/api/models/journal_template.py +854 -0
- deepfos/api/models/memory_financial_model.py +478 -0
- deepfos/api/models/platform.py +178 -0
- deepfos/api/models/python.py +221 -0
- deepfos/api/models/reconciliation_engine.py +411 -0
- deepfos/api/models/reconciliation_report.py +161 -0
- deepfos/api/models/role_strategy.py +884 -0
- deepfos/api/models/smartlist.py +237 -0
- deepfos/api/models/space.py +1137 -0
- deepfos/api/models/system.py +1065 -0
- deepfos/api/models/variable.py +463 -0
- deepfos/api/models/workflow.py +946 -0
- deepfos/api/platform.py +199 -0
- deepfos/api/python.py +90 -0
- deepfos/api/reconciliation_engine.py +181 -0
- deepfos/api/reconciliation_report.py +64 -0
- deepfos/api/role_strategy.py +234 -0
- deepfos/api/smartlist.py +69 -0
- deepfos/api/space.py +582 -0
- deepfos/api/system.py +372 -0
- deepfos/api/variable.py +154 -0
- deepfos/api/workflow.py +264 -0
- deepfos/boost/__init__.py +6 -0
- deepfos/boost/py_jstream.py +89 -0
- deepfos/boost/py_pandas.py +20 -0
- deepfos/cache.py +121 -0
- deepfos/config.py +6 -0
- deepfos/core/__init__.py +27 -0
- deepfos/core/cube/__init__.py +10 -0
- deepfos/core/cube/_base.py +462 -0
- deepfos/core/cube/constants.py +21 -0
- deepfos/core/cube/cube.py +408 -0
- deepfos/core/cube/formula.py +707 -0
- deepfos/core/cube/syscube.py +532 -0
- deepfos/core/cube/typing.py +7 -0
- deepfos/core/cube/utils.py +238 -0
- deepfos/core/dimension/__init__.py +11 -0
- deepfos/core/dimension/_base.py +506 -0
- deepfos/core/dimension/dimcreator.py +184 -0
- deepfos/core/dimension/dimension.py +472 -0
- deepfos/core/dimension/dimexpr.py +271 -0
- deepfos/core/dimension/dimmember.py +155 -0
- deepfos/core/dimension/eledimension.py +22 -0
- deepfos/core/dimension/filters.py +99 -0
- deepfos/core/dimension/sysdimension.py +168 -0
- deepfos/core/logictable/__init__.py +5 -0
- deepfos/core/logictable/_cache.py +141 -0
- deepfos/core/logictable/_operator.py +663 -0
- deepfos/core/logictable/nodemixin.py +673 -0
- deepfos/core/logictable/sqlcondition.py +609 -0
- deepfos/core/logictable/tablemodel.py +497 -0
- deepfos/db/__init__.py +36 -0
- deepfos/db/cipher.py +660 -0
- deepfos/db/clickhouse.py +191 -0
- deepfos/db/connector.py +195 -0
- deepfos/db/daclickhouse.py +171 -0
- deepfos/db/dameng.py +101 -0
- deepfos/db/damysql.py +189 -0
- deepfos/db/dbkits.py +358 -0
- deepfos/db/deepengine.py +99 -0
- deepfos/db/deepmodel.py +82 -0
- deepfos/db/deepmodel_kingbase.py +83 -0
- deepfos/db/edb.py +214 -0
- deepfos/db/gauss.py +83 -0
- deepfos/db/kingbase.py +83 -0
- deepfos/db/mysql.py +184 -0
- deepfos/db/oracle.py +131 -0
- deepfos/db/postgresql.py +192 -0
- deepfos/db/sqlserver.py +99 -0
- deepfos/db/utils.py +135 -0
- deepfos/element/__init__.py +89 -0
- deepfos/element/accounting.py +348 -0
- deepfos/element/apvlprocess.py +215 -0
- deepfos/element/base.py +398 -0
- deepfos/element/bizmodel.py +1269 -0
- deepfos/element/datatable.py +2467 -0
- deepfos/element/deep_pipeline.py +186 -0
- deepfos/element/deepconnector.py +59 -0
- deepfos/element/deepmodel.py +1806 -0
- deepfos/element/dimension.py +1254 -0
- deepfos/element/fact_table.py +427 -0
- deepfos/element/finmodel.py +1485 -0
- deepfos/element/journal.py +840 -0
- deepfos/element/journal_template.py +943 -0
- deepfos/element/pyscript.py +412 -0
- deepfos/element/reconciliation.py +553 -0
- deepfos/element/rolestrategy.py +243 -0
- deepfos/element/smartlist.py +457 -0
- deepfos/element/variable.py +756 -0
- deepfos/element/workflow.py +560 -0
- deepfos/exceptions/__init__.py +239 -0
- deepfos/exceptions/hook.py +86 -0
- deepfos/lazy.py +104 -0
- deepfos/lazy_import.py +84 -0
- deepfos/lib/__init__.py +0 -0
- deepfos/lib/_javaobj.py +366 -0
- deepfos/lib/asynchronous.py +879 -0
- deepfos/lib/concurrency.py +107 -0
- deepfos/lib/constant.py +39 -0
- deepfos/lib/decorator.py +310 -0
- deepfos/lib/deepchart.py +778 -0
- deepfos/lib/deepux.py +477 -0
- deepfos/lib/discovery.py +273 -0
- deepfos/lib/edb_lexer.py +789 -0
- deepfos/lib/eureka.py +156 -0
- deepfos/lib/filterparser.py +751 -0
- deepfos/lib/httpcli.py +106 -0
- deepfos/lib/jsonstreamer.py +80 -0
- deepfos/lib/msg.py +394 -0
- deepfos/lib/nacos.py +225 -0
- deepfos/lib/patch.py +92 -0
- deepfos/lib/redis.py +241 -0
- deepfos/lib/serutils.py +181 -0
- deepfos/lib/stopwatch.py +99 -0
- deepfos/lib/subtask.py +572 -0
- deepfos/lib/sysutils.py +703 -0
- deepfos/lib/utils.py +1003 -0
- deepfos/local.py +160 -0
- deepfos/options.py +670 -0
- deepfos/translation.py +237 -0
- deepfos-1.1.60.dist-info/METADATA +33 -0
- deepfos-1.1.60.dist-info/RECORD +175 -0
- deepfos-1.1.60.dist-info/WHEEL +5 -0
- 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)
|