deepfos 1.1.60__py3-none-any.whl → 1.1.78__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 (68) hide show
  1. deepfos/_version.py +3 -3
  2. deepfos/api/V1_1/models/business_model.py +322 -322
  3. deepfos/api/V1_1/models/dimension.py +1075 -1075
  4. deepfos/api/V1_2/models/dimension.py +1119 -1116
  5. deepfos/api/account.py +1 -0
  6. deepfos/api/app.py +1 -0
  7. deepfos/api/base.py +70 -71
  8. deepfos/api/deep_pipeline.py +1 -1
  9. deepfos/api/deepconnector.py +3 -3
  10. deepfos/api/financial_model.py +12 -0
  11. deepfos/api/models/account.py +130 -130
  12. deepfos/api/models/accounting_engines.py +250 -250
  13. deepfos/api/models/app.py +355 -355
  14. deepfos/api/models/approval_process.py +231 -231
  15. deepfos/api/models/base.py +49 -209
  16. deepfos/api/models/business_model.py +239 -239
  17. deepfos/api/models/consolidation.py +196 -196
  18. deepfos/api/models/consolidation_process.py +31 -31
  19. deepfos/api/models/datatable_mysql.py +78 -78
  20. deepfos/api/models/deep_pipeline.py +20 -9
  21. deepfos/api/models/deepconnector.py +9 -8
  22. deepfos/api/models/deepfos_task.py +118 -118
  23. deepfos/api/models/deepmodel.py +120 -120
  24. deepfos/api/models/dimension.py +613 -610
  25. deepfos/api/models/financial_model.py +691 -663
  26. deepfos/api/models/journal_model.py +120 -120
  27. deepfos/api/models/journal_template.py +185 -185
  28. deepfos/api/models/memory_financial_model.py +131 -131
  29. deepfos/api/models/platform.py +16 -16
  30. deepfos/api/models/python.py +32 -32
  31. deepfos/api/models/reconciliation_engine.py +104 -104
  32. deepfos/api/models/reconciliation_report.py +29 -29
  33. deepfos/api/models/role_strategy.py +213 -213
  34. deepfos/api/models/smartlist.py +86 -86
  35. deepfos/api/models/space.py +312 -312
  36. deepfos/api/models/system.py +299 -297
  37. deepfos/api/models/variable.py +131 -131
  38. deepfos/api/models/workflow.py +290 -270
  39. deepfos/api/platform.py +3 -1
  40. deepfos/api/space.py +1 -0
  41. deepfos/api/system.py +1 -0
  42. deepfos/api/workflow.py +8 -0
  43. deepfos/cache.py +50 -4
  44. deepfos/element/bizmodel.py +2 -2
  45. deepfos/element/deep_pipeline.py +29 -16
  46. deepfos/element/deepconnector.py +36 -1
  47. deepfos/element/deepmodel.py +591 -332
  48. deepfos/element/dimension.py +30 -17
  49. deepfos/element/finmodel.py +542 -101
  50. deepfos/element/journal.py +20 -10
  51. deepfos/element/rolestrategy.py +4 -4
  52. deepfos/element/variable.py +23 -17
  53. deepfos/element/workflow.py +60 -3
  54. deepfos/exceptions/__init__.py +1 -1
  55. deepfos/lib/deepchart.py +14 -13
  56. deepfos/lib/deepux.py +11 -11
  57. deepfos/lib/discovery.py +3 -0
  58. deepfos/lib/filterparser.py +2 -2
  59. deepfos/lib/k8s.py +101 -0
  60. deepfos/lib/msg.py +34 -8
  61. deepfos/lib/serutils.py +34 -9
  62. deepfos/lib/sysutils.py +37 -18
  63. deepfos/lib/utils.py +62 -2
  64. deepfos/options.py +39 -8
  65. {deepfos-1.1.60.dist-info → deepfos-1.1.78.dist-info}/METADATA +7 -7
  66. {deepfos-1.1.60.dist-info → deepfos-1.1.78.dist-info}/RECORD +68 -67
  67. {deepfos-1.1.60.dist-info → deepfos-1.1.78.dist-info}/WHEEL +0 -0
  68. {deepfos-1.1.60.dist-info → deepfos-1.1.78.dist-info}/top_level.txt +0 -0
deepfos/api/platform.py CHANGED
@@ -93,7 +93,8 @@ class StdFileAPI(ChildAPI):
93
93
 
94
94
 
95
95
  """
96
- data = FormData()
96
+ # platform server does not recognize 7bit encoding
97
+ data = FormData(quote_fields=False)
97
98
  data.add_field('file', file, filename=file_name)
98
99
  return {'body': data,
99
100
  'param': {
@@ -174,6 +175,7 @@ class FilePyAPI(ChildAPI):
174
175
  class PlatformAPI(RootAPI):
175
176
  """文件上传服务接口"""
176
177
  prefix = lambda: OPTION.server.platform_file
178
+ server_name = "platform-file-server"
177
179
 
178
180
  @cached_property
179
181
  def file(self) -> StdFileAPI:
deepfos/api/space.py CHANGED
@@ -522,6 +522,7 @@ class SpaceInternalAPI(ChildAPI):
522
522
  class SpaceAPI(RootAPI):
523
523
  """空间服务接口"""
524
524
  prefix = lambda: OPTION.server.space
525
+ server_name = "space-server"
525
526
 
526
527
  @cached_property
527
528
  def app(self) -> SpaceAppAPI:
deepfos/api/system.py CHANGED
@@ -312,6 +312,7 @@ class Space(ChildAPI):
312
312
  class SystemAPI(RootAPI):
313
313
  """系统服务接口"""
314
314
  prefix = lambda: OPTION.server.system
315
+ server_name = "system-server"
315
316
 
316
317
  @cached_property
317
318
  def data_source(self) -> SysDataSourceAPI:
deepfos/api/workflow.py CHANGED
@@ -188,6 +188,14 @@ class ProcessTask(ChildAPI):
188
188
  """
189
189
  return {'body': userTaskQueryDTO}
190
190
 
191
+ @get('outcomes')
192
+ def outcomes(self, taskId: str) -> Union[List[OutComeDto], Awaitable[List[OutComeDto]]]:
193
+ """
194
+ 获取用户任务outcome
195
+
196
+ """
197
+ return {'param': {'taskId': taskId}}
198
+
191
199
 
192
200
  class Version(ChildAPI):
193
201
  endpoint = '/version'
deepfos/cache.py CHANGED
@@ -106,16 +106,62 @@ class SpaceSeperatedBase(CustomedCache):
106
106
 
107
107
 
108
108
  class AppSeperatedTTLCache(TTLCache, AppSeperatedBase):
109
- pass
109
+ def popitem(self):
110
+ """Remove and return the `(key, value)` pair least recently used that
111
+ has not already expired.
112
+
113
+ """
114
+ with self.timer as time:
115
+ self.expire(time)
116
+ try:
117
+ key = next(iter(self._TTLCache__links))
118
+ except StopIteration:
119
+ raise KeyError("%s is empty" % type(self).__name__) from None
120
+ else:
121
+ value = TTLCache.__getitem__(self, key)
122
+ TTLCache.__delitem__(self, key)
123
+ return key, value
110
124
 
111
125
 
112
126
  class SpaceSeperatedTTLCache(TTLCache, SpaceSeperatedBase):
113
- pass
127
+ def popitem(self):
128
+ """Remove and return the `(key, value)` pair least recently used that
129
+ has not already expired.
130
+
131
+ """
132
+ with self.timer as time:
133
+ self.expire(time)
134
+ try:
135
+ key = next(iter(self._TTLCache__links))
136
+ except StopIteration:
137
+ raise KeyError("%s is empty" % type(self).__name__) from None
138
+ else:
139
+ value = TTLCache.__getitem__(self, key)
140
+ TTLCache.__delitem__(self, key)
141
+ return key, value
114
142
 
115
143
 
116
144
  class AppSeperatedLRUCache(LRUCache, AppSeperatedBase):
117
- pass
145
+ def popitem(self):
146
+ """Remove and return the `(key, value)` pair least recently used."""
147
+ try:
148
+ key = next(iter(self._LRUCache__order))
149
+ except StopIteration:
150
+ raise KeyError("%s is empty" % type(self).__name__) from None
151
+ else:
152
+ value = LRUCache.__getitem__(self, key)
153
+ LRUCache.__delitem__(self, key)
154
+ return key, value
118
155
 
119
156
 
120
157
  class SpaceSeperatedLRUCache(LRUCache, SpaceSeperatedBase):
121
- pass
158
+ def popitem(self):
159
+ """Remove and return the `(key, value)` pair least recently used."""
160
+ try:
161
+ key = next(iter(self._LRUCache__order))
162
+ except StopIteration:
163
+ raise KeyError("%s is empty" % type(self).__name__) from None
164
+ else:
165
+ value = LRUCache.__getitem__(self, key)
166
+ LRUCache.__delitem__(self, key)
167
+ return key, value
@@ -57,8 +57,8 @@ def dataframe_to_records(
57
57
 
58
58
 
59
59
  class TableNode(MetaTable):
60
- table_structure: TableStructure = None
61
- name: str = None
60
+ table_structure: Optional[TableStructure] = None
61
+ name: Optional[str] = None
62
62
 
63
63
 
64
64
  def create_table(struct: TableStructure, parent: BaseTable = None) -> TableNode:
@@ -1,17 +1,19 @@
1
1
  import asyncio
2
2
  import time
3
+ import warnings
3
4
  from math import ceil
4
5
  from typing import Any, TYPE_CHECKING, List
5
6
 
6
7
  from deepfos import OPTION
7
8
  from deepfos.api.deep_pipeline import DeepPipelineAPI
8
- from deepfos.api.models.deep_pipeline import RunInfo, FlowInfo
9
+ from deepfos.api.models.deep_pipeline import RunInfo, FlowInfo, RunInfoWithParam
9
10
  from deepfos.element.base import ElementBase, SyncMeta
10
11
  from deepfos.exceptions import (
11
12
  APIResponseError, RunIdInvalid, RunTerminated,
12
13
  ReleaseFlowTimeout, RunFailedError, ReleaseFlowNotExists,
13
14
  )
14
15
  from deepfos.lib.asynchronous import future_property
16
+ from deepfos.lib.constant import UNSET
15
17
  from deepfos.lib.decorator import cached_property
16
18
 
17
19
  errcode_map = {
@@ -47,7 +49,7 @@ class AsyncDeepPipeline(ElementBase[DeepPipelineAPI]):
47
49
 
48
50
  async def run(
49
51
  self,
50
- parameter: Any = None,
52
+ parameter: Any = UNSET,
51
53
  timeout: int = None,
52
54
  in_process: bool = True,
53
55
  ) -> Any:
@@ -57,25 +59,29 @@ class AsyncDeepPipeline(ElementBase[DeepPipelineAPI]):
57
59
  Args:
58
60
  parameter: 执行参数
59
61
  timeout: 超时时间(秒)
60
- in_process: 是否在同一个进程执行
62
+ in_process: 是否在同一个进程执行(仅作新旧兼容,实际只会在同一个进程执行,即不带启停启动)
61
63
 
62
64
  Returns:
63
65
  执行结果
64
66
  """
65
- run_id = await self.run_async(parameter, in_process)
67
+ if not in_process:
68
+ warnings.warn(
69
+ '同步启动固定为同一个进程执行(不带启停启动),in_process参数为False不会影响该行为'
70
+ )
71
+ run_id = await self.run_async(parameter, True)
66
72
  return await self.result(run_id, timeout)
67
73
 
68
74
  async def run_async(
69
75
  self,
70
- parameter: Any = None,
71
- in_process: bool = True,
76
+ parameter: Any = UNSET,
77
+ in_process: bool = False,
72
78
  ) -> str:
73
79
  """
74
80
  异步启动数据流
75
81
 
76
82
  Args:
77
83
  parameter: 执行参数
78
- in_process: 是否在同一个进程执行
84
+ in_process: 是否在同一个进程执行,默认False,即带启停启动
79
85
 
80
86
  Returns:
81
87
  执行ID
@@ -83,14 +89,21 @@ class AsyncDeepPipeline(ElementBase[DeepPipelineAPI]):
83
89
  if not self.has_approved_release:
84
90
  raise ReleaseFlowNotExists('暂无启用中状态的数据流版本')
85
91
 
86
- return await self.async_api.run.run_async(
87
- RunInfo(
92
+ if parameter is UNSET:
93
+ payload = RunInfo(
94
+ elementName=self.element_name,
95
+ folderId=self.element_info.folderId,
96
+ inProcess=in_process
97
+ )
98
+ else:
99
+ payload = RunInfoWithParam(
88
100
  elementName=self.element_name,
89
101
  parameter=parameter,
90
102
  folderId=self.element_info.folderId,
91
103
  inProcess=in_process
92
104
  )
93
- )
105
+
106
+ return await self.async_api.run.run_async(payload)
94
107
 
95
108
  async def result(self, run_id: str, timeout: int = None) -> Any:
96
109
  """
@@ -134,14 +147,14 @@ class AsyncDeepPipeline(ElementBase[DeepPipelineAPI]):
134
147
  async def run_batch(
135
148
  self,
136
149
  parameters: List[Any],
137
- in_process: bool = True,
150
+ in_process: bool = False,
138
151
  ) -> List[str]:
139
152
  """
140
153
  批量异步启动数据流
141
154
 
142
155
  Args:
143
156
  parameters: 执行参数列表
144
- in_process: 是否在同一个进程执行
157
+ in_process: 是否在同一个进程执行,默认False,即带启停启动
145
158
 
146
159
  Returns:
147
160
  执行ID列表
@@ -162,7 +175,7 @@ class DeepPipeline(AsyncDeepPipeline, metaclass=SyncMeta):
162
175
  if TYPE_CHECKING: # pragma: no cover
163
176
  def run(
164
177
  self,
165
- parameter: Any = None,
178
+ parameter: Any = UNSET,
166
179
  timeout: int = None,
167
180
  in_process: bool = True,
168
181
  ) -> Any:
@@ -170,8 +183,8 @@ class DeepPipeline(AsyncDeepPipeline, metaclass=SyncMeta):
170
183
 
171
184
  def run_async(
172
185
  self,
173
- parameter: Any = None,
174
- in_process: bool = True,
186
+ parameter: Any = UNSET,
187
+ in_process: bool = False,
175
188
  ) -> str:
176
189
  ...
177
190
 
@@ -181,6 +194,6 @@ class DeepPipeline(AsyncDeepPipeline, metaclass=SyncMeta):
181
194
  def run_batch(
182
195
  self,
183
196
  parameters: List[Any],
184
- in_process: bool = True,
197
+ in_process: bool = False,
185
198
  ):
186
199
  ...
@@ -1,7 +1,10 @@
1
1
  import base64
2
+ import binascii
3
+ import os
2
4
 
3
5
  from deepfos.api.deepconnector import DeepConnectorAPI
4
6
  from deepfos.api.models import BaseModel
7
+ from deepfos.db.cipher import AES
5
8
  from deepfos.element.base import ElementBase, SyncMeta
6
9
  from deepfos.lib.asynchronous import future_property
7
10
  from deepfos.lib.decorator import cached_property
@@ -9,6 +12,22 @@ from deepfos.lib.decorator import cached_property
9
12
  __all__ = ['AsyncDeepConnector', 'DeepConnector', 'ConnectionInfo']
10
13
 
11
14
 
15
+ def decrypt(secret, cipher_text, encoding='utf8'):
16
+ pwd_padded = b''
17
+ for i in range(len(cipher_text))[::32]:
18
+ pwd_padded += AES(secret).decrypt(
19
+ base64.b16decode(cipher_text[i: i + 32])
20
+ )
21
+ if pwd_padded[-1] in range(1, 17):
22
+ pad_length = pwd_padded[-1]
23
+ pad_char = chr(pwd_padded[-1])
24
+ guess_pad = pad_char * pwd_padded[-1]
25
+
26
+ if pwd_padded.decode(encoding).endswith(guess_pad):
27
+ return pwd_padded.decode(encoding)[:-pad_length:]
28
+ return pwd_padded.decode(encoding)
29
+
30
+
12
31
  class ConnectionInfo(BaseModel):
13
32
  host: str
14
33
  port: int
@@ -45,12 +64,28 @@ class AsyncDeepConnector(ElementBase[DeepConnectorAPI]):
45
64
  info = await api.datasource.connection_info(
46
65
  element_info=ele_info,
47
66
  )
67
+ if info.encryptType == 'AES':
68
+ try:
69
+ password = decrypt(
70
+ os.environ.get('EXPORT_DEEPFOS_AES_KEY', '!ABCD-EFGH-IJKL@').encode(),
71
+ info.password,
72
+ encoding='utf-8'
73
+ )
74
+ except ValueError:
75
+ raise ValueError(
76
+ '连接器连接信息解密失败,请检查公共环境变量:EXPORT_DEEPFOS_AES_KEY'
77
+ ) from None
78
+ else:
79
+ try:
80
+ password = base64.decodebytes(info.password.encode()).decode()
81
+ except binascii.Error:
82
+ password = info.password
48
83
  return ConnectionInfo(
49
84
  host=info.connectionHost,
50
85
  port=info.connectionPort,
51
86
  db=info.dbName,
52
87
  user=info.username,
53
- password=base64.decodebytes(info.password.encode()).decode(),
88
+ password=password,
54
89
  dbtype=info.serviceName,
55
90
  )
56
91