cloudpss 4.0.2__py3-none-any.whl → 4.1.1a1__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.
cloudpss/model/model.py CHANGED
@@ -1,52 +1,58 @@
1
+ import asyncio
1
2
  import os
2
3
  import re
3
- import io
4
- import json
5
- import yaml
6
- import gzip
7
4
  from copy import deepcopy
8
5
 
6
+ from cloudpss.job.job import Job
7
+ from cloudpss.utils.IO import IO
8
+ from cloudpss.utils.httpAsyncRequest import graphql_fetch
9
+
9
10
  from .revision import ModelRevision
10
11
  from .jobDefinitions import JOB_DEFINITIONS
11
- from ..utils import request, fileLoad, graphql_request
12
12
  from ..verify import userName
13
13
 
14
- from cloudpss.runner.result import PowerFlowResult, EMTResult, Result, IESResult
15
- from cloudpss.runner.runner import Runner
14
+ from cloudpss.runner.result import IESResult
15
+ from cloudpss.runner.runner import Runner
16
16
 
17
17
 
18
18
  class Model(object):
19
19
  """
20
- CloudPSS工程类,用于处理加载后的工程数据
20
+ CloudPSS工程类,用于处理加载后的工程数据
21
21
 
22
- 实例变量说明:
22
+ 实例变量说明:
23
23
 
24
- rid 项目的 rid
24
+ rid 项目的 rid
25
25
 
26
- name 项目的名称
26
+ name 项目的名称
27
27
 
28
- description 项目的描述
28
+ description 项目的描述
29
29
 
30
- revision 当前项目的版本信息
30
+ revision 当前项目的版本信息
31
31
 
32
- configs 当前项目的所有参数方案
32
+ configs 当前项目的所有参数方案
33
33
 
34
- jobs 当前项目的所有计算方案
34
+ jobs 当前项目的所有计算方案
35
35
 
36
- context 当前项目的上下文相关信息
36
+ context 当前项目的上下文相关信息
37
37
 
38
38
  """
39
+
39
40
  context: dict
40
41
  jobs: list
41
42
  configs: list
42
43
 
43
44
  def __init__(self, model: dict = {}):
44
45
  """
45
- 项目初始化
46
+ 项目初始化
46
47
  """
47
48
  for k, v in model.items():
48
- if k == 'revision':
49
- self.revision = ModelRevision(v)
49
+ if k == "revision":
50
+ if "version" in v and v["version"] < 5:
51
+ self.revision = ModelRevision(v)
52
+ else:
53
+ raise Exception(
54
+ "当前SDK版本(ver 3.X.X)不兼容该项目文件,请先升级项目文件。具体方法:将该项目文件导入至XStudio 3.X.X平台后重新保存至本地后即可。"
55
+ )
50
56
 
51
57
  else:
52
58
  self.__dict__[k] = v
@@ -56,42 +62,42 @@ class Model(object):
56
62
 
57
63
  def toJSON(self):
58
64
  """
59
- 类对象序列化为 dict
60
- :return: dict
65
+ 类对象序列化为 dict
66
+ :return: dict
61
67
  """
62
- model = {**self.__dict__, 'revision': self.revision.toJSON()}
68
+ model = {**self.__dict__, "revision": self.revision.toJSON()}
63
69
  return model
64
70
 
65
71
  def getAllComponents(self):
66
72
  """
67
- 获取实现
73
+ 获取实现
68
74
 
69
- :return: 所有元件信息
75
+ :return: 所有元件信息
70
76
 
71
- >>> model.getAllComponents()
72
- {
73
- 'canvas_0_2': Component 实例
74
- }
77
+ >>> model.getAllComponents()
78
+ {
79
+ 'canvas_0_2': Component 实例
80
+ }
75
81
  """
76
82
  diagramImplement = self.revision.getImplements().getDiagram()
77
83
  if diagramImplement is None:
78
- raise ValueError('不存在拓扑实现')
84
+ raise ValueError("不存在拓扑实现")
79
85
  return diagramImplement.getAllComponents()
80
86
 
81
87
  def getComponentsByRid(self, rid: str):
82
88
  """
83
- 通过指定元件类型获取元件
89
+ 通过指定元件类型获取元件
84
90
 
85
- :params str: 元件类型
91
+ :params str: 元件类型
86
92
 
87
- :type rid: str
93
+ :type rid: str
88
94
 
89
- :return: 按照元件的 rid 过滤后的 dict<>
95
+ :return: 按照元件的 rid 过滤后的 dict<>
90
96
 
91
- >>> model.getComponentsByRid('model/CloudPSS/newInductorRouter')
92
- {
93
- 'canvas_0_2': Component 实例
94
- }
97
+ >>> model.getComponentsByRid('model/CloudPSS/newInductorRouter')
98
+ {
99
+ 'canvas_0_2': Component 实例
100
+ }
95
101
 
96
102
  """
97
103
 
@@ -99,8 +105,7 @@ class Model(object):
99
105
 
100
106
  cells = {}
101
107
  for key, val in v.items():
102
-
103
- if not val.shape.startswith('diagram-component'):
108
+ if not val.shape.startswith("diagram-component"):
104
109
  continue
105
110
  if val.definition == rid:
106
111
  cells[key] = val
@@ -108,14 +113,14 @@ class Model(object):
108
113
 
109
114
  def getComponentByKey(self, componentKey: str):
110
115
  """
111
- 通过元件的 key 获取对应的元件
116
+ 通过元件的 key 获取对应的元件
112
117
 
113
- :params key: key 元件的key
118
+ :params key: key 元件的key
114
119
 
115
- :Return: Component 实例
120
+ :Return: Component 实例
116
121
 
117
- >>> model.getComponentByKey('canvas_0_757')
118
- Component 实例
122
+ >>> model.getComponentByKey('canvas_0_757')
123
+ Component 实例
119
124
  """
120
125
 
121
126
  v = self.getAllComponents()
@@ -123,144 +128,158 @@ class Model(object):
123
128
 
124
129
  def getModelJob(self, name):
125
130
  """
126
- 获取指定名称的计算方案
131
+ 获取指定名称的计算方案
127
132
 
128
- :params Name: Name 参数名称
133
+ :params Name: Name 参数名称
129
134
 
130
- :return: 同名计算方案数组
135
+ :return: 同名计算方案数组
131
136
 
132
- >>> model.getModelJob('电磁暂态方案 1')
137
+ >>> model.getModelJob('电磁暂态方案 1')
133
138
  """
134
139
  jobs = []
135
140
 
136
141
  for val in self.jobs:
137
- if val['name'] == name:
142
+ if val["name"] == name:
138
143
  jobs.append(val)
139
144
 
140
145
  return jobs
141
146
 
142
147
  def createJob(self, jobType: str, name):
143
148
  """
144
- 创建一个计算方案
145
- 创建出的方案默认不加入到项目中,需要加入请调用 addJob
149
+ 创建一个计算方案
150
+ 创建出的方案默认不加入到项目中,需要加入请调用 addJob
146
151
 
147
- :params jobType: 方案类型
148
- 电磁暂态仿真方案 emtp
149
- 移频电磁暂态仿真方案 sfemt
150
- 潮流计算方案 powerFlow
152
+ :params jobType: 方案类型
153
+ 电磁暂态仿真方案 emtp
154
+ 移频电磁暂态仿真方案 sfemt
155
+ 潮流计算方案 powerFlow
151
156
 
152
- :return: 返回一个指定类型的计算方案
157
+ :return: 返回一个指定类型的计算方案
153
158
 
154
- >>> model.createJob('emtp','emtp job')
155
- 计算方案
159
+ >>> model.createJob('emtp','emtp job')
160
+ 计算方案
156
161
  """
157
162
  job = deepcopy(JOB_DEFINITIONS[jobType])
158
- job['name'] = name
163
+ job["name"] = name
159
164
  return job
160
165
 
161
166
  def addJob(self, job: dict):
162
167
  """
163
- 将计算方案添加到工程中
168
+ 将计算方案添加到工程中
164
169
 
165
- :params job: 计算方案 dict
170
+ :params job: 计算方案 dict
166
171
 
167
- >>> job = model.createJob('emtp','emtp job')
168
- model.addJob(job)
172
+ >>> job = model.createJob('emtp','emtp job')
173
+ model.addJob(job)
169
174
  """
170
175
 
171
176
  self.jobs.append(job)
172
177
 
173
178
  def getModelConfig(self, name):
174
179
  """
175
- 获取指定名称的参数方案
180
+ 获取指定名称的参数方案
176
181
 
177
- :params name: 参数方案名称
182
+ :params name: 参数方案名称
178
183
 
179
- :return: 同名的方案数组
184
+ :return: 同名的方案数组
180
185
 
181
- >>> model.getModelConfig('参数方案 1')
186
+ >>> model.getModelConfig('参数方案 1')
182
187
  """
183
188
  configs = []
184
189
 
185
190
  for val in self.configs:
186
- if val['name'] == name:
191
+ if val["name"] == name:
187
192
  configs.append(val)
188
193
 
189
194
  return configs
190
195
 
191
196
  def createConfig(self, name):
192
197
  """
193
- 创建一个参数方案
194
- 根据项目的第一个参数方案生成一个方案
195
- 创建出的方案默认不加入到项目中,需要加入请调用 addConfig
196
- :params name: 参数方案名称
198
+ 创建一个参数方案
199
+ 根据项目的第一个参数方案生成一个方案
200
+ 创建出的方案默认不加入到项目中,需要加入请调用 addConfig
201
+ :params name: 参数方案名称
197
202
 
198
- :return: 返回一个参数方案 dict
203
+ :return: 返回一个参数方案 dict
199
204
 
200
- >>> job = model.createConfig('my config')
201
- 参数方案
205
+ >>> job = model.createConfig('my config')
206
+ 参数方案
202
207
  """
203
208
 
204
209
  config = deepcopy(self.configs[0])
205
- config['name'] = name
210
+ config["name"] = name
206
211
  return config
207
212
 
208
213
  def addConfig(self, config):
209
214
  """
210
- 将参数方案添加到工程中
215
+ 将参数方案添加到工程中
211
216
 
212
- :params config: 参数方案 dict
217
+ :params config: 参数方案 dict
213
218
 
214
- >>> config = model.createConfig('my config')
215
- model.addConfig(config)
219
+ >>> config = model.createConfig('my config')
220
+ model.addConfig(config)
216
221
  """
217
222
 
218
223
  self.configs.append(config)
219
224
  return config
220
225
 
221
226
  @staticmethod
222
- def fetchMany(name=None, pageSize=10, pageOffset=0):
227
+ def fetchMany(name=None, cursor=[]):
228
+ return asyncio.run(Model.fetchManyAsync(name, cursor))
229
+
230
+ @staticmethod
231
+ async def fetchManyAsync(name=None, cursor=[]):
223
232
  """
224
- 获取用户可以运行的项目列表
233
+ 获取用户可以运行的项目列表
225
234
 
226
- :params name: 查询名称,模糊查询
227
- :params pageSize: 分页大小
228
- :params pageOffset: 分页开始位置
235
+ :params name: 查询名称,模糊查询
236
+ :params cursor: 游标
229
237
 
230
- :return: 按分页信息返回项目列表
238
+ :return: 按分页信息返回项目列表
231
239
 
232
- >>> data=Model.fetchMany()
233
- [
240
+ >>> data= await Model.fetchManyAsync()
241
+ {
242
+ items: [
234
243
  {'rid': 'model/admin/share-test', 'name': '1234', 'description': '1234'}
235
244
  ...
236
- ]
245
+ ],
246
+ cursor: ["1699353593000"],
247
+
248
+ }
249
+
250
+
237
251
  """
252
+ query = """query($input:ModelsInput!){models(input:$input){cursor total count items{rid name description owner tags updatedAt pages{pageId resource key path mode}access{permission role}}}}"""
253
+ variables = {
254
+ "cursor": cursor,
255
+ "limit": 10,
256
+ "orderBy": ["updatedAt<"],
257
+ "permissionEveryone": ["b_any", 2**16],
258
+ }
259
+ if name is not None:
260
+ variables["_search"] = name
261
+
262
+ data = await graphql_fetch(query, {"input": variables})
238
263
 
239
- r = request('GET',
240
- 'api/resources/type/model/permission/write',
241
- params={
242
- 'page_offset': pageOffset,
243
- 'page_size': pageSize,
244
- 'search': name
245
- })
246
- modelList = json.loads(r.text)
264
+ if "errors" in data:
265
+ raise Exception(data["errors"][0]["message"])
247
266
 
248
- return [{
249
- 'rid': '/'.join([val['type'], val['owner'], val['key']]),
250
- 'name': val['name'],
251
- 'description': val['description']
252
- } for val in modelList]
267
+ return data["data"]["models"]
253
268
 
254
269
  @staticmethod
255
270
  def fetch(rid):
271
+ return asyncio.run(Model.fetchAsync(rid))
272
+
273
+ @staticmethod
274
+ async def fetchAsync(rid):
256
275
  """
257
- 获取项目
276
+ 获取项目
258
277
 
259
- :params rid: 项目 rid
278
+ :params rid: 项目 rid
260
279
 
261
- :return: 返回一个项目实例
280
+ :return: 返回一个项目实例
262
281
 
263
- >>> model=Model.fetch('model/Demo/test')
282
+ >>> model=Model.fetch('model/Demo/test')
264
283
 
265
284
  """
266
285
  query = """
@@ -273,6 +292,12 @@ class Model(object):
273
292
  name
274
293
  rid
275
294
  tags
295
+ keywords
296
+ permissions{
297
+ member
298
+ moderator
299
+ everyone
300
+ }
276
301
  revision {
277
302
  author
278
303
  documentation
@@ -287,229 +312,247 @@ class Model(object):
287
312
  }
288
313
  }
289
314
  """
290
- data = graphql_request(query, {'rid': rid})
291
- if 'errors' in data:
292
- raise Exception(data['errors'][0]['message'])
293
- return Model(data['data']['model'])
315
+ data = await graphql_fetch(query, {"rid": rid})
316
+ if "errors" in data:
317
+ raise Exception(data["errors"][0]["message"])
318
+ return Model(data["data"]["model"])
319
+
320
+ def run(self, job=None, config=None, name=None, policy=None, **kwargs):
321
+ return asyncio.run(self.runAsync(job, config, name, policy, **kwargs))
294
322
 
295
- def run(self, job=None, config=None, name=None, **kwargs):
323
+ async def runAsync(self, job=None, config=None, name=None, policy=None, **kwargs):
296
324
  """
297
325
 
298
- 调用仿真
326
+ 调用仿真
299
327
 
300
- :params job: 调用仿真时使用的计算方案,不指定将使用算例保存时选中的计算方案
301
- :params config: 调用仿真时使用的参数方案,不指定将使用算例保存时选中的参数方案
302
- :params name: 任务名称,为空时使用项目的参数方案名称和计算方案名称
328
+ :params job: 调用仿真时使用的计算方案,不指定将使用算例保存时选中的计算方案
329
+ :params config: 调用仿真时使用的参数方案,不指定将使用算例保存时选中的参数方案
330
+ :params name: 任务名称,为空时使用项目的参数方案名称和计算方案名称
303
331
 
304
- :return: 返回一个运行实例
332
+ :return: 返回一个Job实例
305
333
 
306
- >>> runner=model.run(job,config,'')
307
- runner
334
+ >>> job=model.run(job,config,'')
335
+ job
308
336
 
309
337
  """
310
338
  if job is None:
311
- currentJob = self.context['currentJob']
339
+ currentJob = self.context["currentJob"]
312
340
  job = self.jobs[currentJob]
313
341
  if config is None:
314
- currentConfig = self.context['currentConfig']
342
+ currentConfig = self.context["currentConfig"]
315
343
  config = self.configs[currentConfig]
316
- return self.revision.run(job, config, name, self.rid, **kwargs)
344
+ revision = await self.revision.run(
345
+ job, config, name, self.rid, policy, **kwargs
346
+ )
347
+ return await Job.create(
348
+ revision["hash"], job, config, name, self.rid, policy, **kwargs
349
+ )
317
350
 
318
351
  def iesSimulationRun(self, job=None, config=None, name=None, **kwargs):
319
352
  return self.run(job=job, config=config, name=name, kwargs=kwargs)
320
353
 
321
354
  @staticmethod
322
- def load(filePath):
355
+ def load(filePath, format="yaml"):
323
356
  """
324
- 加载本地项目文件
357
+ 加载本地项目文件
325
358
 
326
- :params file: 文件目录
359
+ :params file: 文件目录
327
360
 
328
- :return: 返回一个项目实例
361
+ :format 默认格式为yaml
329
362
 
330
- >>> model = Model.load('filePath')
363
+ :return: 返回一个项目实例
364
+
365
+ >>> model = Model.load('filePath')
331
366
 
332
367
  """
333
368
 
334
369
  if not os.path.exists(filePath):
335
- raise FileNotFoundError('未找到文件')
336
- data = fileLoad(filePath)
370
+ raise FileNotFoundError("未找到文件")
371
+ data = IO.load(filePath, format)
337
372
  return Model(data)
338
373
 
339
374
  @staticmethod
340
- def dump(model, file):
375
+ def dump(model, file, format="yaml", compress="gzip"):
341
376
  """
342
- 下载项目文件
377
+ 下载项目文件
343
378
 
344
- :params model: 项目
345
- :params file: 文件路径
379
+ :params model: 项目
380
+ :params file: 文件路径
381
+ :params format: 文件格式
382
+ :params compress: 是否压缩 压缩格式目前支持gzip 为None时不压缩
346
383
 
347
- :return: 无
384
+ :return: 无
348
385
 
349
- >>> Model.dump(model,file)
386
+ >>> Model.dump(model,file)
350
387
  """
351
388
 
352
- data = model.toJSON()
353
-
354
- yamlData = yaml.dump(data)
355
- with gzip.open(file, 'w') as output:
356
- with io.TextIOWrapper(output, encoding='utf-8') as enc:
357
- enc.write(yamlData)
389
+ IO.dump(model, file, format, compress)
358
390
 
359
391
  def save(self, key=None):
392
+ return asyncio.run(self.saveAsync(key))
393
+
394
+ async def saveAsync(self, key=None):
360
395
  """
361
- 保存/创建项目
396
+ 保存/创建项目
397
+
398
+ key 不为空时如果远程存在相同的资源名称时将覆盖远程项目。
399
+ key 为空时如果项目 rid 不存在则抛异常,需要重新设置 key。
400
+ 如果保存时,当前用户不是该项目的拥有者时,将重新创建项目,重建项目时如果参数的 key 为空将使用当前当前项目的 key 作为资源的 key ,当资源的 key 和远程冲突时保存失败
362
401
 
363
- key 不为空时如果远程存在相同的资源名称时将覆盖远程项目。
364
- key 为空时如果项目 rid 不存在则抛异常,需要重新设置 key。
365
- 如果保存时,当前用户不是该项目的拥有者时,将重新创建项目,重建项目时如果参数的 key 为空将使用当前当前项目的 key 作为资源的 key ,当资源的 key 和远程冲突时保存失败
402
+ :params: model 项目
403
+ :params: key 资源 id 的唯一标识符,
366
404
 
367
- :params: model 项目
368
- :params: key 资源 id 的唯一标识符,
369
-
370
- :return: 保存成功/保存失败
371
-
372
- >>> model.save(model)
373
- model.save(model,'newKey') # 另存为新的项目
405
+ :return: 保存成功/保存失败
406
+
407
+ >>> model.save(model)
408
+ model.save(model,'newKey') # 另存为新的项目
374
409
 
375
410
  """
376
411
  username = userName()
377
412
 
378
413
  if key is not None:
379
- matchObj = re.match(r'^[-_A-Za-z0-9]+$', key, re.I | re.S)
414
+ matchObj = re.match(r"^[-_A-Za-z0-9]+$", key, re.I | re.S)
380
415
  if matchObj:
381
- self.rid = 'model/' + username + '/' + key
416
+ self.rid = "model/" + username + "/" + key
382
417
  try:
383
- r = request('GET', 'api/resources/' + self.rid)
384
- return Model.update(self)
418
+ return await Model.updateAsync(self)
385
419
  except:
386
- return Model.create(self)
420
+ return await Model.createAsync(self)
387
421
  else:
388
- raise Exception('key 能包含字母数子和下划线')
422
+ raise Exception("key 能包含字母数子和下划线")
389
423
  else:
390
- t = '(?<=/)\\S+(?=/)'
424
+ t = "(?<=/)\\S+(?=/)"
391
425
  owner = re.search(t, self.rid)
392
426
  if owner is None:
393
- raise Exception('rid 错误,请传入 key')
427
+ raise Exception("rid 错误,请传入 key")
394
428
  elif owner[0] != username:
395
429
  rid = re.sub(t, username, self.rid)
396
430
  try:
397
- r = request('GET', 'api/resources/' + self.rid)
398
- return Model.create(self)
431
+ return await Model.createAsync(self)
399
432
  except:
400
- raise Exception(rid + ' 该资源已存在,无法重复创建,请修改 key')
433
+ raise Exception(rid + " 该资源已存在,无法重复创建,请修改 key")
401
434
 
402
- return Model.update(self)
435
+ return await Model.updateAsync(self)
403
436
 
404
437
  @staticmethod
405
438
  def create(model):
439
+ return asyncio.run(Model.createAsync(model))
440
+
441
+ @staticmethod
442
+ async def createAsync(model):
406
443
  """
407
- 新建项目
444
+ 新建项目
408
445
 
409
- :params: model 项目
446
+ :params: model 项目
410
447
 
411
- :return: 保存成功/保存失败
448
+ :return: 保存成功/保存失败
412
449
 
413
- >>> Model.create(model)
414
- 保存成功
450
+ >>> Model.create(model)
451
+ 保存成功
415
452
  """
416
453
  # Model.update(model)
417
- t = '(?<=/)\\S+(?=/)'
454
+ t = "(?<=/)\\S+(?=/)"
418
455
  username = userName()
419
456
  owner = re.search(t, model.rid)
420
457
 
421
458
  if owner is None:
422
- raise Exception('rid 错误,无法保存')
459
+ raise Exception("rid 错误,无法保存")
423
460
  elif owner[0] != username:
424
- raise Exception('rid 错误,无法保存')
461
+ raise Exception("rid 错误,无法保存")
425
462
 
426
463
  modelQuery = """
427
464
  mutation($a:CreateModelInput!){createModel(input:$a){
428
465
  rid
429
466
  }}
430
467
  """
431
- isPublic = model.context.get('auth', '') != 'private'
432
- isComponent = model.context.get('category', '') == 'component'
433
- publicRead = model.context.get('publicRead', '') != False
468
+ isPublic = model.context.get("auth", "") != "private"
469
+ isComponent = model.context.get("category", "") == "component"
470
+ publicRead = model.context.get("publicRead", "") != False
434
471
  auth = (65539 if publicRead else 65537) if isPublic else 0
435
- revision = ModelRevision.create(model.revision, model.revision.hash)
436
-
437
- return graphql_request(
438
- modelQuery, {
439
- 'a': {
440
- 'rid': model.rid,
441
- 'revision': revision['hash'],
442
- 'context': model.context,
443
- 'configs': model.configs,
444
- 'jobs': model.jobs,
445
- 'name': model.name,
446
- 'description': model.description,
447
- 'tags': model.tags,
472
+ revision = await ModelRevision.create(model.revision, model.revision.hash)
473
+
474
+ return await graphql_fetch(
475
+ modelQuery,
476
+ {
477
+ "a": {
478
+ "rid": model.rid,
479
+ "revision": revision["hash"],
480
+ "context": model.context,
481
+ "configs": model.configs,
482
+ "jobs": model.jobs,
483
+ "name": model.name,
484
+ "description": model.description,
485
+ "tags": model.tags,
448
486
  "permissions": {
449
487
  "moderator": 1,
450
488
  "member": 1,
451
489
  "everyone": auth,
452
490
  },
453
491
  }
454
- })
492
+ },
493
+ )
455
494
 
456
495
  @staticmethod
457
496
  def update(model):
497
+ return asyncio.run(Model.updateAsync(model))
498
+
499
+ @staticmethod
500
+ async def updateAsync(model):
458
501
  """
459
- 更新项目
502
+ 更新项目
460
503
 
461
- :params: model 项目
504
+ :params: model 项目
462
505
 
463
- :return: 保存成功/保存失败
506
+ :return: 保存成功/保存失败
464
507
 
465
- >>> Model.update(model)
508
+ >>> Model.update(model)
466
509
  """
467
510
 
468
- t = '(?<=/)\\S+(?=/)'
511
+ t = "(?<=/)\\S+(?=/)"
469
512
  username = userName()
470
513
  owner = re.search(t, model.rid)
471
514
 
472
515
  if owner is None:
473
- raise Exception('rid 错误,无法保存')
516
+ raise Exception("rid 错误,无法保存")
474
517
  elif owner[0] != username:
475
- raise Exception('rid 错误,无法保存')
518
+ raise Exception("rid 错误,无法保存")
476
519
 
477
520
  modelQuery = """
478
521
  mutation($a:UpdateModelInput!){updateModel(input:$a){
479
522
  rid
480
523
  }}
481
524
  """
482
- isPublic = model.context.get('auth', '') != 'private'
483
- isComponent = model.context.get('category', '') == 'component'
484
- publicRead = model.context.get('publicRead', '') != False
525
+ isPublic = model.context.get("auth", "") != "private"
526
+ isComponent = model.context.get("category", "") == "component"
527
+ publicRead = model.context.get("publicRead", "") != False
485
528
  auth = (65539 if publicRead else 65537) if isPublic else 0
486
- revision = ModelRevision.create(model.revision, model.revision.hash)
529
+ revision = await ModelRevision.create(model.revision, model.revision.hash)
487
530
 
488
- xVersion = int(float(os.environ.get('X_CLOUDPSS_VERSION', 4)))
489
- tags= {
490
- "replace":model.tags
491
- }
492
- if xVersion==3:
493
- tags=model.tags
494
-
495
- return graphql_request(
496
- modelQuery, {
497
- 'a': {
498
- 'rid': model.rid,
499
- 'revision': revision['hash'],
500
- 'context': model.context,
501
- 'configs': model.configs,
502
- 'jobs': model.jobs,
503
- 'name': model.name,
504
- 'description': model.description,
505
- 'tags': tags,
531
+ xVersion = int(float(os.environ.get("X_CLOUDPSS_VERSION", 4)))
532
+ tags = {"replace": model.tags}
533
+ if xVersion == 3:
534
+ tags = model.tags
535
+
536
+ return await graphql_fetch(
537
+ modelQuery,
538
+ {
539
+ "a": {
540
+ "rid": model.rid,
541
+ "revision": revision["hash"],
542
+ "context": model.context,
543
+ "configs": model.configs,
544
+ "jobs": model.jobs,
545
+ "name": model.name,
546
+ "description": model.description,
547
+ "tags": tags,
506
548
  "permissions": {
507
549
  "moderator": 1,
508
550
  "member": 1,
509
551
  "everyone": auth,
510
552
  },
511
553
  }
512
- })
554
+ },
555
+ )
513
556
 
514
557
  def fetchTopology(
515
558
  self,
@@ -518,201 +561,199 @@ class Model(object):
518
561
  maximumDepth=None,
519
562
  ):
520
563
  """
521
- 通过项目信息,获取当前项目对应的拓扑数据
564
+ 通过项目信息,获取当前项目对应的拓扑数据
522
565
 
523
- :params implementType: 实现类型
524
- :params config: config 项目参数, 不指定将使用算例保存时选中的参数方案
525
- :params maximumDepth: 最大递归深度,用于自定义项目中使用 diagram 实现元件展开情况
566
+ :params implementType: 实现类型
567
+ :params config: config 项目参数, 不指定将使用算例保存时选中的参数方案
568
+ :params maximumDepth: 最大递归深度,用于自定义项目中使用 diagram 实现元件展开情况
526
569
 
527
- :return: 一个拓扑实例
570
+ :return: 一个拓扑实例
528
571
 
529
- >>> topology=model.fetchTopology()
530
- topology=model.fetchTopology(implementType='powerFlow',config=config) # 获取潮流实现的拓扑数据
531
- topology=model.fetchTopology(maximumDepth=2) # 获取仅展开 2 层的拓扑数据
572
+ >>> topology=model.fetchTopology()
573
+ topology=model.fetchTopology(implementType='powerFlow',config=config) # 获取潮流实现的拓扑数据
574
+ topology=model.fetchTopology(maximumDepth=2) # 获取仅展开 2 层的拓扑数据
532
575
  """
533
576
 
534
577
  if self.revision is not None:
535
578
  if implementType is None:
536
- implementType = 'emtp'
579
+ implementType = "emtp"
537
580
  if config is None:
538
- currentConfig = self.context['currentConfig']
581
+ currentConfig = self.context["currentConfig"]
539
582
  config = self.configs[currentConfig]
540
- return self.revision.fetchTopology(implementType, config,
541
- maximumDepth)
583
+ return self.revision.fetchTopology(implementType, config, maximumDepth)
542
584
  return None
543
585
 
544
- def runEMT(self,job=None,config=None)->Runner[EMTResult]:
545
- '''
546
- 运行 emtp 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
586
+ def runEMT(self, job=None, config=None) -> Job:
587
+ """
588
+ 运行 emtp 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
589
+
590
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
591
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
547
592
 
548
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
549
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
550
-
551
- :return: runner Runner[EMTResult]
552
- '''
593
+ :return: job 运行结果
594
+ """
553
595
  if job is None:
554
- currentJob = self.context['currentJob']
596
+ currentJob = self.context["currentJob"]
555
597
  job = self.jobs[currentJob]
556
- if job['rid'] != 'job-definition/cloudpss/emtp':
598
+ if job["rid"] != "job-definition/cloudpss/emtp":
557
599
  for j in self.jobs:
558
- if j['rid'] == 'job-definition/cloudpss/emtp':
600
+ if j["rid"] == "job-definition/cloudpss/emtp":
559
601
  job = j
560
602
  if job is None:
561
603
  raise Exception("找不到电磁暂态运行的计算方案")
562
- if job['rid'] != 'job-definition/cloudpss/emtp':
604
+ if job["rid"] != "job-definition/cloudpss/emtp":
563
605
  raise Exception("不是电磁暂态运行生成算法的计算方案")
564
606
  if config is None:
565
- currentConfig = self.context['currentConfig']
607
+ currentConfig = self.context["currentConfig"]
566
608
  config = self.configs[currentConfig]
567
609
  return self.run(job=job, config=config)
568
610
 
569
- def runSFEMT(self,job=None,config=None)->Runner[EMTResult]:
570
- '''
571
- 运行 移频电磁暂态 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
611
+ def runSFEMT(self, job=None, config=None) -> Job:
612
+ """
613
+ 运行 移频电磁暂态 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
572
614
 
573
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
574
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
615
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
616
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
575
617
 
576
- :return: runner Runner[EMTResult]
577
- '''
618
+ :return: runner Runner[EMTResult]
619
+ """
578
620
  if job is None:
579
- currentJob = self.context['currentJob']
621
+ currentJob = self.context["currentJob"]
580
622
  job = self.jobs[currentJob]
581
- if job['rid'] != 'job-definition/cloudpss/sfemt':
623
+ if job["rid"] != "job-definition/cloudpss/sfemt":
582
624
  for j in self.jobs:
583
- if j['rid'] == 'job-definition/cloudpss/sfemt':
625
+ if j["rid"] == "job-definition/cloudpss/sfemt":
584
626
  job = j
585
627
  if job is None:
586
628
  raise Exception("找不到移频电磁暂态运行的计算方案")
587
- if job['rid'] != 'job-definition/cloudpss/sfemt':
629
+ if job["rid"] != "job-definition/cloudpss/sfemt":
588
630
  raise Exception("不是移频电磁暂态运行生成算法的计算方案")
589
631
  if config is None:
590
- currentConfig = self.context['currentConfig']
632
+ currentConfig = self.context["currentConfig"]
591
633
  config = self.configs[currentConfig]
592
634
  return self.run(job=job, config=config)
593
635
 
594
- def runPowerFlow(self,job=None,config=None)->Runner[PowerFlowResult]:
595
- '''
596
- 运行 潮流 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
636
+ def runPowerFlow(self, job=None, config=None) -> Job:
637
+ """
638
+ 运行 潮流 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
597
639
 
598
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
599
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
640
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
641
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
600
642
 
601
- :return: runner Runner[PowerFlowResult]
602
- '''
643
+ :return: runner Runner[PowerFlowResult]
644
+ """
603
645
  if job is None:
604
- currentJob = self.context['currentJob']
646
+ currentJob = self.context["currentJob"]
605
647
  job = self.jobs[currentJob]
606
- if job['rid'] != 'job-definition/cloudpss/power-flow':
648
+ if job["rid"] != "job-definition/cloudpss/power-flow":
607
649
  for j in self.jobs:
608
- if j['rid'] == 'job-definition/cloudpss/power-flow':
650
+ if j["rid"] == "job-definition/cloudpss/power-flow":
609
651
  job = j
610
652
  if job is None:
611
653
  raise Exception("找不到潮流内核运行的计算方案")
612
- if job['rid'] != 'job-definition/cloudpss/power-flow':
654
+ if job["rid"] != "job-definition/cloudpss/power-flow":
613
655
  raise Exception("不是潮流内核运行生成算法的计算方案")
614
656
  if config is None:
615
- currentConfig = self.context['currentConfig']
657
+ currentConfig = self.context["currentConfig"]
616
658
  config = self.configs[currentConfig]
617
659
  return self.run(job=job, config=config)
618
660
 
619
- def runThreePhasePowerFlow(self,job=None,config=None)->Runner[PowerFlowResult]:
620
- '''
621
- 运行 三相不平衡潮流 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
622
-
623
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
624
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
661
+ def runThreePhasePowerFlow(self, job=None, config=None) -> Job:
662
+ """
663
+ 运行 三相不平衡潮流 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
664
+
665
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
666
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
625
667
 
626
- :return: runner Runner[PowerFlowResult]
627
- '''
668
+ :return: runner Runner[PowerFlowResult]
669
+ """
628
670
  if job is None:
629
- currentJob = self.context['currentJob']
671
+ currentJob = self.context["currentJob"]
630
672
  job = self.jobs[currentJob]
631
- if job['rid'] != 'job-definition/cloudpss/three-phase-powerFlow':
673
+ if job["rid"] != "job-definition/cloudpss/three-phase-powerFlow":
632
674
  for j in self.jobs:
633
- if j['rid'] == 'job-definition/cloudpss/three-phase-powerFlow':
675
+ if j["rid"] == "job-definition/cloudpss/three-phase-powerFlow":
634
676
  job = j
635
677
  if job is None:
636
678
  raise Exception("找不到三相不平衡潮流内核运行的计算方案")
637
- if job['rid'] != 'job-definition/cloudpss/three-phase-powerFlow':
679
+ if job["rid"] != "job-definition/cloudpss/three-phase-powerFlow":
638
680
  raise Exception("不是三相不平衡潮流内核运行生成算法的计算方案")
639
681
  if config is None:
640
- currentConfig = self.context['currentConfig']
682
+ currentConfig = self.context["currentConfig"]
641
683
  config = self.configs[currentConfig]
642
684
  return self.run(job=job, config=config)
643
-
644
- def runIESLoadPrediction(self,job=None,config=None)->Runner[IESResult]:
645
- '''
646
- 运行 负荷预测方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
647
-
648
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
649
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
650
-
651
- :return: runner Runner[IESResult]
652
- '''
685
+
686
+ def runIESLoadPrediction(self, job=None, config=None) -> Runner[IESResult]:
687
+ """
688
+ 运行 负荷预测方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
689
+
690
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
691
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
692
+
693
+ :return: runner Runner[IESResult]
694
+ """
653
695
  if job is None:
654
- currentJob = self.context['currentJob']
696
+ currentJob = self.context["currentJob"]
655
697
  job = self.jobs[currentJob]
656
- if job['rid'] != 'job-definition/ies/ies-load-prediction':
698
+ if job["rid"] != "job-definition/ies/ies-load-prediction":
657
699
  for j in self.jobs:
658
- if j['rid'] == 'job-definition/ies/ies-load-prediction':
700
+ if j["rid"] == "job-definition/ies/ies-load-prediction":
659
701
  job = j
660
702
  if job is None:
661
703
  raise Exception("找不到负荷预测方案内核运行的计算方案")
662
- if job['rid'] != 'job-definition/ies/ies-load-prediction':
704
+ if job["rid"] != "job-definition/ies/ies-load-prediction":
663
705
  raise Exception("不是负荷预测方案内核运行生成算法的计算方案")
664
706
  if config is None:
665
- currentConfig = self.context['currentConfig']
707
+ currentConfig = self.context["currentConfig"]
666
708
  config = self.configs[currentConfig]
667
709
  return self.run(job=job, config=config)
668
-
669
- def runIESPowerFlow(self,job=None,config=None)->Runner[IESResult]:
670
- '''
671
- 运行 时序潮流方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
672
-
673
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
674
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
675
-
676
- :return: runner Runner[IESResult]
677
- '''
710
+
711
+ def runIESPowerFlow(self, job=None, config=None) -> Runner[IESResult]:
712
+ """
713
+ 运行 时序潮流方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
714
+
715
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
716
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
717
+
718
+ :return: runner Runner[IESResult]
719
+ """
678
720
  if job is None:
679
- currentJob = self.context['currentJob']
721
+ currentJob = self.context["currentJob"]
680
722
  job = self.jobs[currentJob]
681
- if job['rid'] != 'job-definition/ies/ies-power-flow':
723
+ if job["rid"] != "job-definition/ies/ies-power-flow":
682
724
  for j in self.jobs:
683
- if j['rid'] == 'job-definition/ies/ies-power-flow':
725
+ if j["rid"] == "job-definition/ies/ies-power-flow":
684
726
  job = j
685
727
  if job is None:
686
728
  raise Exception("找不到时序潮流方案内核运行的计算方案")
687
- if job['rid'] != 'job-definition/ies/ies-power-flow':
729
+ if job["rid"] != "job-definition/ies/ies-power-flow":
688
730
  raise Exception("不是时序潮流方案内核运行生成算法的计算方案")
689
731
  if config is None:
690
- currentConfig = self.context['currentConfig']
732
+ currentConfig = self.context["currentConfig"]
691
733
  config = self.configs[currentConfig]
692
734
  return self.run(job=job, config=config)
693
735
 
694
- def runIESEnergyStoragePlan(self,job=None,config=None)->Runner[IESResult]:
695
- '''
696
- 运行 储能规划方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
697
-
698
- :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
699
- :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
736
+ def runIESEnergyStoragePlan(self, job=None, config=None) -> Runner[IESResult]:
737
+ """
738
+ 运行 储能规划方案 内核,如果当前 model 没有创建 Job 时报错,默认使用第一个计算方案,进行仿真。
700
739
 
701
- :return: runner Runner[IESResult]
702
- '''
740
+ :param: job 计算方案名称,可选,字符串类型或者字典类型,默认使用第一个计算方案,如果同名使用最靠前一个
741
+ :param: config 参数方案,可选,字符串类型或者字典类型,默认使用保存时选中的参数方案
742
+
743
+ :return: runner Runner[IESResult]
744
+ """
703
745
  if job is None:
704
- currentJob = self.context['currentJob']
746
+ currentJob = self.context["currentJob"]
705
747
  job = self.jobs[currentJob]
706
- if job['rid'] != 'job-definition/ies/ies-energy-storage-plan':
748
+ if job["rid"] != "job-definition/ies/ies-energy-storage-plan":
707
749
  for j in self.jobs:
708
- if j['rid'] == 'job-definition/ies/ies-energy-storage-plan':
750
+ if j["rid"] == "job-definition/ies/ies-energy-storage-plan":
709
751
  job = j
710
752
  if job is None:
711
753
  raise Exception("找不到储能规划方案内核运行的计算方案")
712
- if job['rid'] != 'job-definition/ies/ies-energy-storage-plan':
754
+ if job["rid"] != "job-definition/ies/ies-energy-storage-plan":
713
755
  raise Exception("不是储能规划方案内核运行生成算法的计算方案")
714
756
  if config is None:
715
- currentConfig = self.context['currentConfig']
757
+ currentConfig = self.context["currentConfig"]
716
758
  config = self.configs[currentConfig]
717
759
  return self.run(job=job, config=config)
718
-