cloudpss 4.1.1b7__py3-none-any.whl → 4.5.13__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 (66) hide show
  1. cloudpss/__init__.py +2 -3
  2. cloudpss/asyncio/__init__.py +8 -0
  3. cloudpss/asyncio/job/__init__.py +5 -0
  4. cloudpss/asyncio/job/job.py +116 -0
  5. cloudpss/asyncio/job/messageStreamReceiver.py +121 -0
  6. cloudpss/asyncio/job/messageStreamSender.py +45 -0
  7. cloudpss/asyncio/model/__init__.py +5 -0
  8. cloudpss/asyncio/model/model.py +257 -0
  9. cloudpss/asyncio/model/revision.py +41 -0
  10. cloudpss/asyncio/model/topology.py +34 -0
  11. cloudpss/asyncio/utils/__init__.py +6 -0
  12. cloudpss/{utils → asyncio/utils}/httpAsyncRequest.py +2 -2
  13. cloudpss/dslab/dataManageModel.py +43 -14
  14. cloudpss/dslab/dslab.py +35 -9
  15. cloudpss/dslab/files/curveData.py +35066 -35042
  16. cloudpss/dslab/files/files.py +21 -13
  17. cloudpss/function/functionExecution.py +74 -5
  18. cloudpss/ieslab/DataManageModel.py +144 -9
  19. cloudpss/ieslab/EvaluationModel.py +80 -9
  20. cloudpss/ieslab/IESLabOpt.py +235 -0
  21. cloudpss/ieslab/IESLabPlan.py +82 -4
  22. cloudpss/ieslab/IESLabSimulation.py +59 -32
  23. cloudpss/ieslab/PlanModel.py +222 -18
  24. cloudpss/ieslab/__init__.py +2 -1
  25. cloudpss/job/TemplateCompiler.py +273 -0
  26. cloudpss/job/TemplateManager.py +37 -0
  27. cloudpss/job/job.py +136 -141
  28. cloudpss/job/jobReceiver.py +8 -2
  29. cloudpss/job/messageStreamReceiver.py +42 -99
  30. cloudpss/job/messageStreamSender.py +5 -42
  31. cloudpss/job/{view/EMTView.py → result/EMTResult.py} +57 -14
  32. cloudpss/job/result/IESLabSimulationResult.py +5 -0
  33. cloudpss/job/result/IESLabTypicalDayResult.py +134 -0
  34. cloudpss/job/{view/IESView.py → result/IESResult.py} +7 -5
  35. cloudpss/job/{view/PowerFlowView.py → result/PowerFlowResult.py} +2 -2
  36. cloudpss/job/result/__init__.py +40 -0
  37. cloudpss/job/{view/view.py → result/result.py} +38 -8
  38. cloudpss/model/implements/diagram.py +140 -0
  39. cloudpss/model/jobDefinitions.py +6 -6
  40. cloudpss/model/model.py +245 -226
  41. cloudpss/model/revision.py +30 -35
  42. cloudpss/model/topology.py +26 -15
  43. cloudpss/runner/IESLabEvaluationResult.py +14 -6
  44. cloudpss/runner/IESLabPlanResult.py +91 -35
  45. cloudpss/runner/IESLabTypicalDayResult.py +62 -50
  46. cloudpss/runner/MessageStreamReceiver.py +5 -100
  47. cloudpss/runner/result.py +6 -1
  48. cloudpss/runner/runner.py +97 -53
  49. cloudpss/utils/IO.py +3 -1
  50. cloudpss/utils/graphqlUtil.py +3 -2
  51. cloudpss/utils/httprequests.py +19 -10
  52. cloudpss/version.py +1 -1
  53. {cloudpss-4.1.1b7.dist-info → cloudpss-4.5.13.dist-info}/METADATA +2 -2
  54. cloudpss-4.5.13.dist-info/RECORD +80 -0
  55. cloudpss/dslab/DSLabFinancialResult.py +0 -96
  56. cloudpss/job/jobMachine.py +0 -11
  57. cloudpss/job/jobPolicy.py +0 -129
  58. cloudpss/job/jobQueue.py +0 -14
  59. cloudpss/job/jobTres.py +0 -6
  60. cloudpss/job/view/IESLabSimulationView.py +0 -5
  61. cloudpss/job/view/IESLabTypicalDayView.py +0 -27
  62. cloudpss/job/view/__init__.py +0 -42
  63. cloudpss-4.1.1b7.dist-info/RECORD +0 -72
  64. /cloudpss/{utils → asyncio/utils}/AsyncIterable.py +0 -0
  65. {cloudpss-4.1.1b7.dist-info → cloudpss-4.5.13.dist-info}/WHEEL +0 -0
  66. {cloudpss-4.1.1b7.dist-info → cloudpss-4.5.13.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,15 @@
1
- from cloudpss.runner.IESLabPlanResult import IESLabPlanResult
2
- from cloudpss.runner.runner import HttpRunner, Runner
1
+ from cloudpss.runner.IESLabPlanResult import IESLabPlanResult, IESLabOptResult
2
+ from cloudpss.runner.runner import HttpRunner, HttpOPTRunner
3
+ from cloudpss.model import Model
4
+ from cloudpss.model.revision import ModelRevision
3
5
  from ..utils import request, fileLoad
4
6
  import json
5
7
  from enum import IntEnum, unique
6
8
 
7
9
 
8
10
  class IESLabPlanModel(object):
9
- _baseUri = 'api/ieslab-plan/taskmanager/getSimuLastTasks'
11
+ _baseUri = 'api/ieslab-plan/rest'
12
+ _runUri = 'api/ieslab-plan/taskmanager'
10
13
 
11
14
  def __init__(self, simulationId):
12
15
  '''
@@ -14,18 +17,18 @@ class IESLabPlanModel(object):
14
17
  '''
15
18
  self.simulationId = simulationId
16
19
  self.optimizationInfo = self.GetOptimizationInfo()
17
- self.OptimizationMode = OptimizationMode
18
20
 
19
- def _fetchItemData(self, url):
21
+ def _fetchItemData(self, url, params):
20
22
  '''
21
23
  获取当前算例的优化目标设置信息
22
24
 
23
- :return: enum 类型,代表经济性优化和环保性优化的类型
25
+ :return: List 类型,包括优化目标和全局参数储能动作灵敏度,若没有设置则返回 []
24
26
  '''
25
- r = request('GET', url, params={"simuid": self.simulationId})
27
+ r = request('GET', url, params=params)
26
28
  data = json.loads(r.text)
27
- return data
29
+ return data['results']
28
30
 
31
+
29
32
  def GetOptimizationInfo(self):
30
33
  '''
31
34
  获取当前算例的优化目标设置信息
@@ -50,8 +53,8 @@ class IESLabPlanModel(object):
50
53
  '''
51
54
  self.optimizationInfo = optType
52
55
  return True
53
-
54
- def run(self) -> Runner[IESLabPlanResult]:
56
+
57
+ def run(self) -> HttpRunner[IESLabPlanResult]:
55
58
  '''
56
59
  生成方案优选算例
57
60
 
@@ -61,10 +64,9 @@ class IESLabPlanModel(object):
61
64
  if isRunning:
62
65
  raise Exception('该算例正在运行!请从浏览器算例页面点击结束运行或者调用IESPlan对象的kill接口终止计算后重试!')
63
66
  else:
64
- url = 'api/ieslab-plan/taskmanager/runOptimization'
65
- if self.optimizationInfo is None:
66
- self.optimizationInfo = OptimizationMode['经济性']
67
- optType = self.optimizationInfo.value or 0
67
+ url = f'{self._runUri}/runOptimization'
68
+ optType = self.optimizationInfo if self.optimizationInfo is not None else OptimizationMode.经济性
69
+ optTypeValue = optType.value if isinstance(optType, OptimizationMode) else 0
68
70
  try:
69
71
  r = request('GET',
70
72
  url,
@@ -73,7 +75,7 @@ class IESLabPlanModel(object):
73
75
  self.simulationId,
74
76
  "optPara":
75
77
  json.dumps({
76
- "OptimizationMode": optType,
78
+ "OptimizationMode": optTypeValue,
77
79
  "ProjectPeriod": "20"
78
80
  })
79
81
  })
@@ -82,7 +84,7 @@ class IESLabPlanModel(object):
82
84
  except:
83
85
  raise Exception('生成方案优选算例失败')
84
86
 
85
- def GetRunner(self) -> Runner[IESLabPlanResult]:
87
+ def GetRunner(self) -> HttpRunner[IESLabPlanResult]:
86
88
  '''
87
89
  获得运行实例
88
90
 
@@ -100,7 +102,7 @@ class IESLabPlanModel(object):
100
102
  data = res.get('data', {})
101
103
  if data is not None:
102
104
  taskID = data.get('task_id', '')
103
- url = f'api/ieslab-plan/taskmanager/removeOptimizationTask'
105
+ url = f'{self._runUri}/removeOptimizationTask'
104
106
  try:
105
107
  r = request('GET',
106
108
  url,
@@ -128,7 +130,208 @@ class IESLabPlanModel(object):
128
130
  status = data.get('status', '')
129
131
  if status == 'stop':
130
132
  isRunning = False
131
- logs = IESLabPlanResult(self.simulationId).GetLogs()
133
+ try:
134
+
135
+ logs = IESLabPlanResult(self.simulationId).GetLogs()
136
+ if logs is not None:
137
+ for log in logs:
138
+ if(log.get('data', '') == 'run ends'):
139
+ isRunning = False
140
+ break
141
+ except:
142
+ return False
143
+ return isRunning
144
+
145
+
146
+
147
+ class IESLabOptModel(object):
148
+ _baseUri = 'api/ieslab-opt/rest'
149
+ _runUri = 'api/ieslab-opt/taskmanager'
150
+
151
+
152
+ def __init__(self, simulationId, rid):
153
+ '''
154
+ 初始化
155
+ '''
156
+ self.simulationId = simulationId
157
+ self.rid = rid
158
+ self.optimizationInfo = self.GetOptimizationInfo()
159
+
160
+ def _fetchItemData(self, url, params):
161
+ '''
162
+ 获取当前算例的优化目标设置信息
163
+
164
+ :return: List 类型,包括优化目标和全局参数储能动作灵敏度,若没有设置则返回 []
165
+ '''
166
+ r = request('GET', url, params=params)
167
+ data = json.loads(r.text)
168
+ return data['results']
169
+
170
+ def GetOptimizationInfo(self):
171
+ '''
172
+ 获取当前算例的优化目标设置信息
173
+
174
+ :return: Dict 类型,例如:{'OptGoal': <OptimizationMode.经济性: 0>, 'StoSen': "10", '@debug': '', 'clustering_algorithm': '0', 'num_method': '0', 'PowUnPrice': '1000', 'HeatAbandonPrice': '1000'}
175
+ '''
176
+ try:
177
+ url = f'{self._baseUri}/simuOpt/'
178
+ params = {"simu_id": self.simulationId}
179
+ r = self._fetchItemData(url, params)
180
+ if (len(r) == 0):
181
+ return {
182
+ "OptGoal": OptimizationMode['经济性'],
183
+ "StoSen": "10",
184
+ "@debug": "",
185
+ "clustering_algorithm": "0",
186
+ "num_method": "0",
187
+ "PowUnPrice": "1000",
188
+ "HeatAbandonPrice": "1000"
189
+ }
190
+ else:
191
+ value = json.loads(r[0]['opt_params'])
192
+ return {
193
+ "OptGoal": OptimizationMode(int(value['OptGoal'])),
194
+ "StoSen": value['StoSen'],
195
+ "@debug": value["@debug"],
196
+ "clustering_algorithm": value["clustering_algorithm"],
197
+ "num_method": value["num_method"],
198
+ "PowUnPrice": value["PowUnPrice"],
199
+ "HeatAbandonPrice": value["HeatAbandonPrice"]
200
+ }
201
+ except:
202
+ raise Exception('获得优化目标设置失败')
203
+
204
+ def SetOptimizationInfo(self, data: dict):
205
+ '''
206
+ 设置当前算例的优化目标
207
+
208
+ :param data: dict 类型,例如:{'OptGoal': <OptimizationMode.经济性: 0>, 'StoSen': "10", '@debug': '', 'clustering_algorithm': '0', 'num_method': '0', 'PowUnPrice': '1000', 'HeatAbandonPrice': '1000'}
209
+
210
+ :return: boolean 类型,为 True 则设置成功
211
+ '''
212
+ try:
213
+ url = f'{self._baseUri}/simuOpt/'
214
+ params = {"simu_id": self.simulationId}
215
+ r = self._fetchItemData(url, params)
216
+ opt_params = {
217
+ "OptGoal": data.get('OptGoal', ''),
218
+ "StoSen": data.get('StoSen', ''),
219
+ "@debug": data.get('@debug', ''),
220
+ "clustering_algorithm": data.get('clustering_algorithm', ''),
221
+ "num_method": data.get('num_method', ''),
222
+ "PowUnPrice": data.get('PowUnPrice', ''),
223
+ "HeatAbandonPrice": data.get('HeatAbandonPrice', '')
224
+ }
225
+ if(len(r) == 0):
226
+ payload = {
227
+ "simu_id": self.simulationId,
228
+ "opt_params": json.dumps(opt_params)
229
+ }
230
+ r = request('POST',
231
+ url,
232
+ data=json.dumps(payload))
233
+ return True
234
+ else:
235
+ url2 = f'{self._baseUri}/simuOpt/{r[0]["id"]}/'
236
+ payload = {
237
+ "simu_id": self.simulationId,
238
+ "opt_params": json.dumps(opt_params),
239
+ "id": r[0]["id"]
240
+ }
241
+ r = request('PUT',
242
+ url2,
243
+ data=json.dumps(payload))
244
+ return True
245
+ except:
246
+ return False
247
+
248
+ def run(self) -> HttpOPTRunner[IESLabOptResult]:
249
+ '''
250
+ 生成方案优选算例
251
+
252
+ :return: Runner[IESLabOptResult]
253
+ '''
254
+ isRunning = self.GetLastTaskResult()
255
+ if isRunning:
256
+ raise Exception('该算例正在运行!请从浏览器算例页面点击结束运行或者调用IESPlan对象的kill接口终止计算后重试!')
257
+ else:
258
+ # 通过 rid 获取 model
259
+ model = Model.fetch(self.rid)
260
+ # 通过 model 获取 revision
261
+ revision = ModelRevision.create(model.revision, model.revision.hash)
262
+ hash = revision.get('hash', '')
263
+ url = f'{self._runUri}/runOptimization'
264
+ opt = {
265
+ "OptGoal": self.optimizationInfo.get('OptGoal', 0).value,
266
+ "StoSen": self.optimizationInfo.get('StoSen', 10),
267
+ "@debug": self.optimizationInfo.get('@debug', ''),
268
+ "clustering_algorithm": self.optimizationInfo.get('clustering_algorithm', '0'),
269
+ "num_method": self.optimizationInfo.get('num_method', '0'),
270
+ "PowUnPrice": self.optimizationInfo.get('PowUnPrice', '1000'),
271
+ "HeatAbandonPrice": self.optimizationInfo.get('HeatAbandonPrice', '1000'),
272
+ }
273
+ try:
274
+ r = request('GET',
275
+ url,
276
+ params={
277
+ "simuid":
278
+ self.simulationId,
279
+ "optPara":
280
+ json.dumps(opt),
281
+ "revision": hash
282
+ })
283
+ data = json.loads(r.text)
284
+ return HttpOPTRunner({}, self.simulationId)
285
+ except:
286
+ raise Exception('生成方案优选算例失败')
287
+
288
+ def GetRunner(self) -> HttpOPTRunner[IESLabOptResult]:
289
+ '''
290
+ 获得运行实例
291
+
292
+ :return: Runner[IESLabOptResult]
293
+ '''
294
+ return HttpOPTRunner({}, self.simulationId)
295
+
296
+ def kill(self) -> bool:
297
+ '''
298
+ 停止并删除当前运行的优化算例
299
+ '''
300
+ res = IESLabOptResult(self.simulationId).getLastTaskResult()
301
+ error = res.get('error', 0)
302
+ if error == 0:
303
+ data = res.get('data', {})
304
+ if data is not None:
305
+ taskID = data.get('task_id', '')
306
+ url = f'{self._runUri}/removeOptimizationTask'
307
+ try:
308
+ r = request('GET',
309
+ url,
310
+ params={
311
+ "taskid": taskID,
312
+ "stopFlag": '2'
313
+ })
314
+ json.loads(r.text)
315
+ return True
316
+ except:
317
+ return False
318
+
319
+ def GetLastTaskResult(self)-> bool:
320
+ '''
321
+ 获取最后一次运行的taskID的运行结果与日志
322
+
323
+ :return: boolean 类型
324
+ '''
325
+ isRunning = True
326
+ res = IESLabOptResult(self.simulationId).getLastTaskResult()
327
+ error = res.get('error', 0)
328
+ if error == 0:
329
+ data = res.get('data', {})
330
+ if data is not None:
331
+ status = data.get('status', '')
332
+ if status == 'stop':
333
+ isRunning = False
334
+ logs = IESLabOptResult(self.simulationId).GetLogs()
132
335
  if logs is not None:
133
336
  for log in logs:
134
337
  if(log.get('data', '') == 'run ends'):
@@ -137,6 +340,7 @@ class IESLabPlanModel(object):
137
340
  return isRunning
138
341
 
139
342
 
343
+
140
344
  # @unique
141
345
  class OptimizationMode(IntEnum):
142
346
  经济性 = 0
@@ -1,4 +1,5 @@
1
1
  from .IESLabSimulation import IESLabSimulation
2
2
  from .IESLabPlan import IESLabPlan
3
3
  from .PlanModel import OptimizationMode
4
- __all__ = ['IESLabSimulation','IESLabPlan', 'OptimizationMode']
4
+ from .IESLabOpt import IESLabOpt
5
+ __all__ = ['IESLabSimulation','IESLabPlan', 'OptimizationMode', 'IESLabOpt']
@@ -0,0 +1,273 @@
1
+ import json
2
+ from collections import namedtuple
3
+ from typing import Any, Dict, List, Union
4
+
5
+ PARSER_STATUS_TEXT = 0
6
+ PARSER_STATUS_EXPRESSION_SIMPLE = 1
7
+ PARSER_STATUS_EXPRESSION_COMPLEX = 2
8
+
9
+ def is_identifier_char(char):
10
+ char_code = ord(char)
11
+ return ((char_code >= 97 and char_code <= 122) or
12
+ (char_code >= 65 and char_code <= 90) or
13
+ (char_code >= 48 and char_code <= 57) or
14
+ char_code == 95)
15
+
16
+ INTERPOLATION_CHAR = '$'
17
+ INTERPOLATION_EXPRESSION_START = '{'
18
+ INTERPOLATION_EXPRESSION_END = '}'
19
+
20
+ def parse_interpolation_impl(template, start, length):
21
+ templates = []
22
+ values = []
23
+ current_template = ''
24
+ current_value = ''
25
+ expression_complex_depth = 0
26
+ status = PARSER_STATUS_TEXT
27
+ end = start + length - 1
28
+
29
+ i = start
30
+ while i <= end:
31
+ if status == PARSER_STATUS_TEXT:
32
+ next_interpolation_char = template.find(INTERPOLATION_CHAR, i)
33
+ if next_interpolation_char < 0 or next_interpolation_char >= end:
34
+ current_template += template[i:end + 1]
35
+ break
36
+ current_template += template[i:next_interpolation_char]
37
+ next_char = template[next_interpolation_char + 1]
38
+ i = next_interpolation_char
39
+ if next_char == INTERPOLATION_CHAR:
40
+ current_template += INTERPOLATION_CHAR
41
+ i += 1
42
+ continue
43
+ if next_char == INTERPOLATION_EXPRESSION_START:
44
+ templates.append(current_template)
45
+ current_template = ''
46
+ status = PARSER_STATUS_EXPRESSION_COMPLEX
47
+ expression_complex_depth = 1
48
+ i += 1
49
+ continue
50
+ if is_identifier_char(next_char):
51
+ templates.append(current_template)
52
+ current_template = ''
53
+ current_value = next_char
54
+ status = PARSER_STATUS_EXPRESSION_SIMPLE
55
+ i += 1
56
+ continue
57
+ current_template += INTERPOLATION_CHAR
58
+ continue
59
+
60
+ char = template[i]
61
+ if status == PARSER_STATUS_EXPRESSION_SIMPLE:
62
+ if is_identifier_char(char):
63
+ current_value += char
64
+ i += 1
65
+ continue
66
+ values.append(current_value)
67
+ current_value = ''
68
+ status = PARSER_STATUS_TEXT
69
+ continue
70
+
71
+ if status == PARSER_STATUS_EXPRESSION_COMPLEX:
72
+ if char == INTERPOLATION_EXPRESSION_START:
73
+ expression_complex_depth += 1
74
+ elif char == INTERPOLATION_EXPRESSION_END:
75
+ expression_complex_depth -= 1
76
+ if expression_complex_depth == 0:
77
+ values.append(current_value.strip())
78
+ current_value = ''
79
+ status = PARSER_STATUS_TEXT
80
+ i += 1
81
+ continue
82
+ current_value += char
83
+ i += 1
84
+ continue
85
+
86
+ if status == PARSER_STATUS_TEXT:
87
+ templates.append(current_template)
88
+ elif status == PARSER_STATUS_EXPRESSION_SIMPLE:
89
+ values.append(current_value)
90
+ templates.append('')
91
+ else:
92
+ raise ValueError('Unexpected end of input')
93
+
94
+ return {
95
+ 'type': 'interpolation',
96
+ 'templates': templates,
97
+ 'values': values,
98
+ }
99
+
100
+ # 是否为 ArrayBuffer
101
+ def is_array_buffer(value: Any) -> bool:
102
+ return isinstance(value, (memoryview, bytearray))
103
+
104
+ # 是否为 Error
105
+ def is_error(value: Any) -> bool:
106
+ return isinstance(value, Exception)
107
+
108
+
109
+ def parse_template(template: str) -> Any:
110
+ if not template:
111
+ return ''
112
+ if template.startswith('='):
113
+ return {
114
+ 'type': 'formula',
115
+ 'value': template[1:].strip(),
116
+ }
117
+ if template.startswith('$'):
118
+ result = parse_interpolation_impl(template, 1, len(template)-1)
119
+ if len(result['templates']) == 0:
120
+ return result['templates'][0]
121
+ return result
122
+ return template
123
+ # KNOWN_ERRORS = [EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError]
124
+
125
+ # 模板序列号
126
+ seq = 0
127
+
128
+ # 创建模板
129
+ class TemplateCompiler:
130
+ def __init__(self, template: Any, options: Dict[str, Any]):
131
+ self.template = template
132
+ self.options = options
133
+ self.params = {}
134
+ self.copyable = []
135
+
136
+ # 构建求值
137
+ def build_eval(self, expression: str, type_: str) -> str:
138
+ evaluator = self.options['evaluator']
139
+ if 'evaluator' not in self.params:
140
+ self.params['evaluator'] = evaluator.get('inject',None)
141
+ return evaluator['compile'](expression, type_)
142
+
143
+ # 构建字符串
144
+ def build_string(self, str_: str) -> Union[str, bool]:
145
+ parsed = parse_template(str_)
146
+ if isinstance(parsed, str):
147
+ return json.dumps(parsed), False
148
+ if parsed['type'] == 'formula':
149
+ return self.build_eval(parsed['value'], parsed['type']), True
150
+ result = ''
151
+ for i in range(len(parsed['templates'])):
152
+ if parsed['templates'][i]:
153
+ result += (result and '+' or '') + json.dumps(parsed['templates'][i])
154
+ if i < len(parsed['values']):
155
+ if not result:
156
+ result = '""'
157
+ result += '+' + self.build_eval(parsed['values'][i], parsed['type'])
158
+ return result, True
159
+
160
+ # 构建 Error
161
+ def build_error(self, err: Exception) -> str:
162
+ constructor="Error"
163
+ if err.__class__.__name__ == constructor:
164
+ return f'new {constructor}({self.build_string(err.message)[0]})'
165
+ return f'Object.assign(new {constructor}({self.build_string(err.message)[0]}), {{name: {self.build_string(err.name)[0]}}})'
166
+
167
+ # 构建数组
168
+ def build_array(self, arr: List[Any]) -> str:
169
+ return f'[{", ".join(self.build_value(v) for v in arr)}]'
170
+
171
+ # 构建 ArrayBuffer
172
+ def build_array_buffer(self, buffer: Union[memoryview, bytearray]) -> str:
173
+ self.copyable.append(buffer[:])
174
+ return f'copyable[{len(self.copyable) - 1}][:]'
175
+
176
+ # 构建 ArrayBufferView
177
+ def build_array_buffer_view(self, view: memoryview) -> str:
178
+ self.copyable.append(view.tobytes())
179
+ return f'new {view.__class__.__name__}(copyable[{len(self.copyable) - 1}][:])'
180
+
181
+ # 构建对象
182
+ def build_object(self, obj: Dict[str, Any]) -> str:
183
+ result = ''
184
+ for key, value in obj.items():
185
+ if result:
186
+ result += ',\n'
187
+ if self.options['objectKeyMode'] == 'ignore':
188
+ result += json.dumps(key)
189
+ else:
190
+ e, is_expression = self.build_string(key)
191
+ if is_expression:
192
+ result += f'[{e}]'
193
+ else:
194
+ result += e
195
+ result += ':'
196
+ result += self.build_value(value)
197
+ return '{' + result + '}'
198
+
199
+ # 构建值
200
+ def build_value(self, value: Any) -> str:
201
+ if value is None:
202
+ return 'null'
203
+ if value is True:
204
+ return 'true'
205
+ if value is False:
206
+ return 'false'
207
+ if isinstance(value, (int, float)):
208
+ return str(value)
209
+ if isinstance(value, str):
210
+ return self.build_string(value)[0]
211
+ if isinstance(value, Exception):
212
+ return self.build_error(value)
213
+ if isinstance(value, list):
214
+ return self.build_array(value)
215
+ if is_array_buffer(value):
216
+ return self.build_array_buffer(value)
217
+ if isinstance(value, memoryview):
218
+ return self.build_array_buffer_view(value)
219
+ if isinstance(value, dict):
220
+ return self.build_object(value)
221
+ raise ValueError(f'Unsupported value: {type(value)}')
222
+
223
+ # 构建模板
224
+ def build(self) -> Any:
225
+ global seq
226
+ source = self.build_value(self.template)
227
+ if self.copyable:
228
+ self.params['copyable'] = self.copyable
229
+ params = list(self.params.items())
230
+ try:
231
+ result = eval(f'lambda context: ({source})')
232
+ result.source = source
233
+ return result
234
+ except Exception as e:
235
+ raise ValueError(f'Failed to compile template: {source}\n{str(e)}')
236
+
237
+
238
+
239
+ def template(templates,options={}):
240
+ def compile_template(expression, type):
241
+ if type == 'formula':
242
+ return f'context[{json.dumps(expression)}]'
243
+ elif type == 'interpolation':
244
+ return f"context[{json.dumps(expression)}] ?? ''"
245
+ raise ValueError(f'Unsupported type: {type}')
246
+ opt = {
247
+ 'objectKeyMode': 'template',
248
+ 'evaluator':{
249
+ 'compile':compile_template
250
+ },
251
+ **options
252
+ }
253
+ return TemplateCompiler(templates, opt).build()
254
+
255
+
256
+
257
+ if __name__ == "__main__":
258
+
259
+ message =[1, 1, {'component_load_5_无功功率': [0], 'component_load_5_有功功率': [0], 'time': ['placeholder']}, {'data': {'title': '负荷5功率(kW)', 'traces': [{'name': '有功功率', 'type': 'scatter', 'x': '=time', 'y': '=component_load_5_有功功率'}, {'name': '无功功率', 'type': 'scatter', 'x': '=time', 'y': '=component_load_5_无功功率'}], 'xAxis': {'title': 'time'}, 'yAxis': {'title': '功率(kW)'}}, 'key': '/component_load_5_功率(kW)', 'type': 'plot', 'verb': 'append', 'version': 1}]
260
+ id =message[0]
261
+
262
+ templates=message[3:]
263
+
264
+ x= template(templates)
265
+
266
+ values=[1, 1, {'component_load_5_无功功率': [5.44544554016478], 'component_load_5_有功功率': [16.3363363363363], 'time': ['2021-08-19 09:00:00']}]
267
+
268
+ print(x)
269
+
270
+ data= values[2]
271
+ s=x(data)
272
+
273
+ print(s)
@@ -0,0 +1,37 @@
1
+ import logging
2
+ from cloudpss.job.TemplateCompiler import template
3
+ class TemplateManager():
4
+
5
+ def __init__(self) -> None:
6
+ self.templateMap = {}
7
+
8
+ def isCreate(self, value):
9
+ return type(value) == list and len(value) > 3 and type(value[0]) == int and value[1] == 1
10
+
11
+ def create(self, value):
12
+ if not self.isCreate(value):
13
+ print("is create")
14
+ return
15
+ id =value[0]
16
+
17
+ templates=value[3:]
18
+ if self.templateMap.get(id,None) is not None:
19
+ logging.debug(f"template {id} is already exist")
20
+
21
+ self.templateMap[id] = {'template':template(templates),'value':value}
22
+
23
+
24
+
25
+ def isInvoke(self, value):
26
+ return type(value) == list and len(value) == 3 and type(value[0]) == int and value[1] == 1
27
+
28
+ def invoke(self, value):
29
+ if not self.isInvoke(value):
30
+ return []
31
+ id,_version,args = value
32
+
33
+ t = self.templateMap.get(id,None)
34
+ if t is None:
35
+ return []
36
+ return t['template'](args)
37
+