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,168 @@
1
+ from typing import Union
2
+
3
+ import pandas as pd
4
+
5
+ from deepfos.core.logictable import MetaTable
6
+ from deepfos.lib.utils import unpack_expr
7
+ from deepfos.element.dimension import Dimension as EleDimension
8
+ from deepfos.element.datatable import DataTableClickHouse, DataTableMySQL
9
+ from ._base import DimensionBase, MemberBase, MemberContainer, NAME_DFLT
10
+ from .dimexpr import DimExprAnalysor
11
+
12
+ # -----------------------------------------------------------------------------
13
+ # typing
14
+ T_AbsDataTable = Union[DataTableMySQL, DataTableClickHouse]
15
+
16
+
17
+ # -----------------------------------------------------------------------------
18
+ # core
19
+ class AsMbrContainer:
20
+ def __init__(self, func, include_self=False):
21
+ self.func = func
22
+ self.include_self = include_self
23
+
24
+ def __get__(self, instance, owner=None):
25
+ with instance.tbl_dim.temporary_lock(name__in=instance.name_list):
26
+ with self.func(instance):
27
+ rslt = instance.data_tbl.data
28
+ if self.include_self:
29
+ # noinspection PyProtectedMember
30
+ rslt = rslt.append(instance._data)
31
+ return SysDimMemberContainer(rslt, *instance.split(), hierarchy=self.name)
32
+
33
+ def __set_name__(self, owner, name):
34
+ self.name = name
35
+
36
+
37
+ class SysDimension(DimensionBase):
38
+ """
39
+ 系统维度
40
+
41
+ 绕过维度元素,使用维度底层数据表创建的维度
42
+
43
+ Args:
44
+ dimname: 维度名称
45
+ tbl_closure: 维度绑定的closure表,记录维度层级关系
46
+ tbl_dim: 维度数据表
47
+ name_only: 是否仅需要维度名 (Cube用)
48
+ folder_id: 维度所在文件夹ID
49
+ path: 维度所在绝对路径
50
+
51
+ """
52
+ def __init__(
53
+ self,
54
+ dimname: str,
55
+ tbl_closure: T_AbsDataTable = None,
56
+ tbl_dim: T_AbsDataTable = None,
57
+ name_only: bool = False,
58
+ folder_id: str = None,
59
+ path: str = None,
60
+ server_name: str = None,
61
+ ):
62
+ super().__init__(dimname)
63
+ self._name_only = name_only
64
+ if tbl_closure is None or tbl_dim is None:
65
+ tbl_dim, tbl_closure = self._get_datatable(folder_id, path, server_name)
66
+
67
+ self._create_tree(tbl_closure, tbl_dim, name_only)
68
+
69
+ def _create_tree(self, tbl_closure, tbl_dim, name_only: bool):
70
+ # 组建table_dimension和table_closure的关联关系
71
+ # 父表为table_closure,以不同字段关联两张table_dimension
72
+ self.tbl_closure = MetaTable(tbl_closure.table_name, tuple(), {"datatable": tbl_closure})
73
+ self.tbl_dim = MetaTable(
74
+ tbl_dim.table_name, tuple(),
75
+ {"datatable": tbl_dim, "parent": {"cls": self.tbl_closure, 'on': ('id',), "alias": ('ancestor',)}}
76
+ )
77
+ self.data_tbl = MetaTable(
78
+ tbl_dim.table_name + '_data', tuple(),
79
+ {
80
+ "datatable": tbl_dim,
81
+ "parent": {"cls": self.tbl_closure, 'alias': ('descendants',), 'on': ('id',)}
82
+ }
83
+ )
84
+ if name_only:
85
+ self.data_tbl.fields = (NAME_DFLT,)
86
+
87
+ def _get_datatable(self, folder_id: str, path: str, server_name: str = None):
88
+ # 获取table_dimension和table_closure的真实表名
89
+ dim = EleDimension(self.name, folder_id=folder_id, path=path, server_name=server_name)
90
+ return dim.table_dimension, dim.table_closure
91
+
92
+ def __getitem__(self, item):
93
+ if self._name_only:
94
+ data = pd.DataFrame(data={NAME_DFLT: [item]})
95
+ return SysDimMember(item, self.tbl_closure, self.tbl_dim, self.data_tbl, data)
96
+ return SysDimMember(item, self.tbl_closure, self.tbl_dim, self.data_tbl)
97
+
98
+
99
+ _base = lambda self: self.data_tbl.temporary_lock(is_base__eq=1)
100
+ _children = lambda self: self.tbl_closure.temporary_lock(distance__eq=1)
101
+ _descendant = lambda self: self.tbl_closure.temporary_lock(distance__ne=0)
102
+
103
+
104
+ class SysDimMember(MemberBase):
105
+ def __init__(self, name, tbl_closure, tbl_dim, data_tbl, data=None):
106
+ super().__init__(name)
107
+ self.tbl_closure = tbl_closure
108
+ self.tbl_dim = tbl_dim
109
+ self.data_tbl = data_tbl
110
+ self.name_list = (name, ) if isinstance(name, str) else name
111
+ if data is None:
112
+ self._data = self._fetch_data()
113
+ else:
114
+ self._data = data
115
+ if len(self.name_list) != len(self._data):
116
+ unknown = set(self.name_list) - set(self._data.name)
117
+ raise ValueError(f"Dimension {unknown!r} does not exist.")
118
+
119
+ def _fetch_data(self):
120
+ with self.tbl_dim.temporary_lock(name__in=self.name_list):
121
+ return self.tbl_dim.data
122
+
123
+ Base = AsMbrContainer(_base)
124
+ IBase = AsMbrContainer(_base, include_self=True)
125
+ Children = AsMbrContainer(_children)
126
+ IChildren = AsMbrContainer(_children, include_self=True)
127
+ Descendant = AsMbrContainer(_descendant)
128
+ IDescendant = AsMbrContainer(_descendant, include_self=True)
129
+
130
+ @property
131
+ def members(self):
132
+ return list(self._data.itertuples(index=False))
133
+
134
+ def __str__(self):
135
+ return ';'.join(self.name_list)
136
+
137
+ def where(self, method, **kwargs):
138
+ return SysDimMemberContainer(self._data, *self.split()).where(method, **kwargs)
139
+
140
+ def remove(self, *to_remove):
141
+ return SysDimMemberContainer(self._data, *self.split()).remove(*to_remove)
142
+
143
+ def split(self):
144
+ """分解为仅行单个成员的SysDimMember"""
145
+ if len(self.name_list) == 1:
146
+ return [self]
147
+
148
+ rtn = []
149
+ for idx, name in enumerate(self.name_list):
150
+ rtn.append(self.__class__(
151
+ name, self.tbl_dim, self.tbl_closure, self.data_tbl,
152
+ data=self._data.iloc[idx:idx+1]))
153
+ return rtn
154
+
155
+
156
+ class SysDimMemberContainer(MemberContainer):
157
+ def __init__(self, data, *anchor_mbr, hierarchy=None):
158
+ super().__init__(*anchor_mbr, hierarchy=hierarchy)
159
+ self.__data = data
160
+
161
+ def _get_all_member(self):
162
+ return list(self.__data.itertuples(index=False))
163
+
164
+
165
+ def read_expr(dim_expr):
166
+ dimname, expr = unpack_expr(dim_expr)
167
+ dim = SysDimension(dimname)
168
+ return DimExprAnalysor(dim, expr).solve()
@@ -0,0 +1,5 @@
1
+ from .sqlcondition import SQLCondition
2
+ from .tablemodel import BaseTable, MetaTable
3
+ from .nodemixin import TreeRenderer
4
+
5
+ __all__ = ['SQLCondition', 'BaseTable', 'MetaTable', 'TreeRenderer']
@@ -0,0 +1,141 @@
1
+ from typing import Iterable, Optional
2
+ from collections import UserDict, defaultdict
3
+ import itertools
4
+
5
+ import pandas as pd
6
+ from loguru import logger
7
+ from .sqlcondition import SQLCondition
8
+
9
+
10
+ class Cache(UserDict):
11
+ def __init__(self, *args, **kwds):
12
+ super(Cache, self).__init__(*args, **kwds)
13
+ self.__ref_count = defaultdict(int)
14
+ self.__idx_map = {}
15
+ self._counter = itertools.count(1).__next__
16
+
17
+ def pop_by_score(self, score_func=None, highest=False):
18
+ if not self:
19
+ raise KeyError('dictionary is empty')
20
+
21
+ score_func = score_func or self._score_idx_plus_ref
22
+
23
+ sorted_keys = sorted(self.__idx_map.items(), key=score_func, reverse=highest)
24
+ pop_key = sorted_keys[0][0]
25
+ pop_val = self.pop(pop_key)
26
+ self.__idx_map.pop(pop_key)
27
+ return pop_key, pop_val
28
+
29
+ def _score_idx_plus_ref(self, key_with_idx, weight_idx=0.8, weight_ref=1):
30
+ key, idx = key_with_idx
31
+ ref_count = self.__ref_count[key]
32
+ return idx * weight_idx + ref_count * weight_ref
33
+
34
+ def __getitem__(self, item):
35
+ val = super(Cache, self).__getitem__(item)
36
+ self.__ref_count[item] += 1
37
+ return val
38
+
39
+ def __setitem__(self, key, value):
40
+ rslt = super(Cache, self).__setitem__(key, value)
41
+ self.__idx_map[key] = self._counter()
42
+ return rslt
43
+
44
+
45
+ class Fields:
46
+ def __init__(
47
+ self,
48
+ fields: Optional[Iterable[str]],
49
+ extra_fields: Optional[Iterable[str]] = None
50
+ ):
51
+ if fields is None:
52
+ self.flds = None
53
+ else:
54
+ extra_fields = extra_fields or []
55
+ all_flds = {*fields, *extra_fields}
56
+ if any(fld.strip() == '*' for fld in all_flds):
57
+ self.flds = None
58
+ else:
59
+ self.flds = all_flds
60
+
61
+ def __le__(self, other: 'Fields'):
62
+ if other.flds is None:
63
+ return True
64
+ elif self.flds is None:
65
+ return other.flds is None
66
+ else:
67
+ return self.flds <= other.flds
68
+
69
+
70
+ class DataProxy:
71
+ def __init__(self, max_size=10):
72
+ self._data_cache = Cache()
73
+ self._cond_cache = dict()
74
+ self._fields_cache = {}
75
+ if not max_size >= 1:
76
+ raise ValueError("Max size must be positive.")
77
+ self._max_size = max_size
78
+
79
+ def make_cache(
80
+ self,
81
+ key: SQLCondition,
82
+ fields: Optional[Iterable[str]],
83
+ value: pd.DataFrame,
84
+ force_update: bool = False
85
+ ):
86
+ series_code = key.serialized
87
+
88
+ if not force_update and series_code in self._cond_cache \
89
+ and Fields(fields) <= self._fields_cache[series_code]:
90
+ logger.debug("Found a better version in cache. Skip update.")
91
+ return
92
+
93
+ self._data_cache[series_code] = value
94
+ self._cond_cache[series_code] = key
95
+ self._fields_cache[series_code] = Fields(fields)
96
+
97
+ if len(self._data_cache) > self._max_size:
98
+ rm_key, _ = self._data_cache.pop_by_score()
99
+ logger.debug(f'Removed cache with lowest score:\n{_}')
100
+ self._cond_cache.pop(rm_key)
101
+ self._fields_cache.pop(rm_key)
102
+
103
+ def get_data(self, key: SQLCondition, fields: Optional[Iterable[str]]):
104
+ series_code = key.serialized
105
+ if series_code in self._data_cache:
106
+ fields_memo = Fields(fields)
107
+ if fields_memo <= self._fields_cache[series_code]:
108
+ logger.debug("Found perfect-match from cache.")
109
+ if fields_memo.flds is None:
110
+ return self._data_cache[series_code]
111
+ else:
112
+ return self._data_cache[series_code][list(fields)]
113
+
114
+ for sql_cnd in self._cond_cache.values():
115
+ # 不用小于号是为了避免重复调用__eq__
116
+ if key <= sql_cnd:
117
+ series_code = sql_cnd.serialized
118
+ fields_memo = Fields(fields, key.all_fields)
119
+
120
+ if fields_memo <= self._fields_cache[series_code]:
121
+ cache = self._data_cache[sql_cnd.serialized]
122
+ data = self.query_from_cache(cache, key)
123
+ if fields_memo.flds is None:
124
+ return data
125
+ else:
126
+ return data[list(fields)]
127
+ return None
128
+
129
+ @staticmethod
130
+ def query_from_cache(cache: pd.DataFrame, key: SQLCondition):
131
+ logger.debug(f"Query {key!r} from cache:\n{cache}")
132
+ query_str = key.to_pandasql()
133
+ if query_str is None:
134
+ data = cache
135
+ else:
136
+ data = cache.query(query_str)
137
+ fields = key.fields
138
+ if fields:
139
+ data = data.merge(key.val_list, on=fields, how='inner')
140
+ logger.debug(f"Got DATA from cache:\n{data}")
141
+ return data.reset_index(drop=True)