cloudpss 4.1.1b8__tar.gz → 4.5.13__tar.gz
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-4.1.1b8 → cloudpss-4.5.13}/PKG-INFO +1 -1
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/__init__.py +2 -3
- cloudpss-4.5.13/cloudpss/asyncio/__init__.py +8 -0
- cloudpss-4.5.13/cloudpss/asyncio/job/job.py +116 -0
- cloudpss-4.5.13/cloudpss/asyncio/job/messageStreamReceiver.py +121 -0
- cloudpss-4.5.13/cloudpss/asyncio/job/messageStreamSender.py +45 -0
- cloudpss-4.5.13/cloudpss/asyncio/model/model.py +257 -0
- cloudpss-4.5.13/cloudpss/asyncio/model/revision.py +41 -0
- cloudpss-4.5.13/cloudpss/asyncio/model/topology.py +34 -0
- cloudpss-4.5.13/cloudpss/asyncio/utils/__init__.py +6 -0
- {cloudpss-4.1.1b8/cloudpss → cloudpss-4.5.13/cloudpss/asyncio}/utils/httpAsyncRequest.py +2 -2
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/function/functionExecution.py +74 -5
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/ieslab/DataManageModel.py +144 -9
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/ieslab/EvaluationModel.py +80 -9
- cloudpss-4.5.13/cloudpss/ieslab/IESLabOpt.py +235 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/ieslab/IESLabPlan.py +82 -4
- cloudpss-4.5.13/cloudpss/ieslab/IESLabSimulation.py +116 -0
- cloudpss-4.5.13/cloudpss/ieslab/PlanModel.py +347 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/ieslab/__init__.py +2 -1
- cloudpss-4.5.13/cloudpss/job/__init__.py +5 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/job/job.py +136 -141
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/job/jobReceiver.py +8 -2
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/job/messageStreamReceiver.py +42 -99
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/job/messageStreamSender.py +5 -42
- cloudpss-4.1.1b8/cloudpss/job/view/EMTView.py → cloudpss-4.5.13/cloudpss/job/result/EMTResult.py +57 -14
- cloudpss-4.5.13/cloudpss/job/result/IESLabSimulationResult.py +5 -0
- cloudpss-4.5.13/cloudpss/job/result/IESLabTypicalDayResult.py +134 -0
- cloudpss-4.1.1b8/cloudpss/job/view/IESView.py → cloudpss-4.5.13/cloudpss/job/result/IESResult.py +7 -5
- cloudpss-4.1.1b8/cloudpss/job/view/PowerFlowView.py → cloudpss-4.5.13/cloudpss/job/result/PowerFlowResult.py +2 -2
- cloudpss-4.5.13/cloudpss/job/result/__init__.py +40 -0
- cloudpss-4.1.1b8/cloudpss/job/view/view.py → cloudpss-4.5.13/cloudpss/job/result/result.py +38 -8
- cloudpss-4.5.13/cloudpss/model/__init__.py +5 -0
- cloudpss-4.5.13/cloudpss/model/implements/diagram.py +186 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/jobDefinitions.py +6 -6
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/model.py +245 -226
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/revision.py +30 -35
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/topology.py +26 -15
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/IESLabEvaluationResult.py +14 -6
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/IESLabPlanResult.py +91 -35
- cloudpss-4.5.13/cloudpss/runner/IESLabTypicalDayResult.py +154 -0
- cloudpss-4.5.13/cloudpss/runner/MessageStreamReceiver.py +98 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/result.py +6 -1
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/runner.py +97 -53
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/IO.py +3 -1
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/graphqlUtil.py +3 -2
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/httprequests.py +19 -10
- cloudpss-4.5.13/cloudpss/version.py +1 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss.egg-info/PKG-INFO +1 -1
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss.egg-info/SOURCES.txt +31 -22
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss.egg-info/requires.txt +1 -1
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/setup.py +1 -1
- cloudpss-4.5.13/test/test-plot.py +42 -0
- cloudpss-4.5.13/test/test-plot1.py +0 -0
- cloudpss-4.5.13/test/test-topology.py +41 -0
- cloudpss-4.1.1b8/test/test.py → cloudpss-4.5.13/test/test-topology1.py +8 -6
- cloudpss-4.5.13/test/test-yield.py +16 -0
- cloudpss-4.5.13/test/test.py +35 -0
- cloudpss-4.5.13/test/test11.py +69 -0
- cloudpss-4.5.13/test/test12.py +21 -0
- cloudpss-4.5.13/test/testRt-test.py +148 -0
- cloudpss-4.5.13/test/testRt.py +193 -0
- cloudpss-4.1.1b8/test/testRt.py → cloudpss-4.5.13/test/testRt2.py +39 -23
- cloudpss-4.5.13/test/testSend.py +47 -0
- cloudpss-4.5.13/test/test_modepower_ampratio(3).py +244 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test_ws.py +14 -16
- cloudpss-4.5.13/test/test_ws2.py +114 -0
- cloudpss-4.5.13/test/test_ws3.py +49 -0
- cloudpss-4.1.1b8/cloudpss/dslab/__init__.py +0 -2
- cloudpss-4.1.1b8/cloudpss/dslab/dataManageModel.py +0 -275
- cloudpss-4.1.1b8/cloudpss/dslab/dslab.py +0 -210
- cloudpss-4.1.1b8/cloudpss/dslab/files/__init__.py +0 -2
- cloudpss-4.1.1b8/cloudpss/dslab/files/curveData.py +0 -140229
- cloudpss-4.1.1b8/cloudpss/dslab/files/files.py +0 -27
- cloudpss-4.1.1b8/cloudpss/dslab/financialAnalysisModel.py +0 -137
- cloudpss-4.1.1b8/cloudpss/ieslab/IESLabSimulation.py +0 -89
- cloudpss-4.1.1b8/cloudpss/ieslab/PlanModel.py +0 -143
- cloudpss-4.1.1b8/cloudpss/job/jobMachine.py +0 -11
- cloudpss-4.1.1b8/cloudpss/job/jobPolicy.py +0 -129
- cloudpss-4.1.1b8/cloudpss/job/jobQueue.py +0 -14
- cloudpss-4.1.1b8/cloudpss/job/jobTres.py +0 -6
- cloudpss-4.1.1b8/cloudpss/job/view/IESLabSimulationView.py +0 -5
- cloudpss-4.1.1b8/cloudpss/job/view/IESLabTypicalDayView.py +0 -27
- cloudpss-4.1.1b8/cloudpss/job/view/__init__.py +0 -42
- cloudpss-4.1.1b8/cloudpss/model/implements/diagram.py +0 -46
- cloudpss-4.1.1b8/cloudpss/runner/DSLabResult.py +0 -92
- cloudpss-4.1.1b8/cloudpss/runner/IESLabTypicalDayResult.py +0 -142
- cloudpss-4.1.1b8/cloudpss/runner/MessageStreamReceiver.py +0 -193
- cloudpss-4.1.1b8/cloudpss/version.py +0 -1
- cloudpss-4.1.1b8/test/test-topology.py +0 -26
- cloudpss-4.1.1b8/test/testRt copy.py +0 -107
- cloudpss-4.1.1b8/test/testSend.py +0 -39
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/README.md +0 -0
- {cloudpss-4.1.1b8/cloudpss → cloudpss-4.5.13/cloudpss/asyncio}/job/__init__.py +0 -0
- {cloudpss-4.1.1b8/cloudpss → cloudpss-4.5.13/cloudpss/asyncio}/model/__init__.py +0 -0
- {cloudpss-4.1.1b8/cloudpss → cloudpss-4.5.13/cloudpss/asyncio}/utils/AsyncIterable.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/function/__init__.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/function/function.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/function/job.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/implements/__init__.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/implements/component.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/model/implements/implement.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/project/__init__.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/project/project.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/__init__.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/receiver.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/storage.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/runner/transform.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/__init__.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/dataEncoder.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/matlab.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/utils/yamlLoader.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss/verify.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss.egg-info/dependency_links.txt +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/cloudpss.egg-info/top_level.txt +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/setup.cfg +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-async.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-async2.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-async3.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-sdk.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-sdk1.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test-snapshot.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test7950.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/testAsync.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/testEvent.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/test_in_new_web_1.py +0 -0
- {cloudpss-4.1.1b8 → cloudpss-4.5.13}/test/testb.py +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding=UTF-8
|
2
|
-
from cloudpss.ieslab import IESLabSimulation, IESLabPlan
|
2
|
+
from cloudpss.ieslab import IESLabSimulation, IESLabPlan, IESLabOpt
|
3
3
|
from .verify import setToken
|
4
4
|
from .runner import Runner, Result, EMTResult, PowerFlowResult
|
5
5
|
from .model import Model, ModelRevision, ModelTopology
|
@@ -9,11 +9,10 @@ from . import function
|
|
9
9
|
from .job import Job
|
10
10
|
from .function import FunctionExecution
|
11
11
|
from .version import __version__
|
12
|
-
from .dslab import DSLab
|
13
12
|
__all__ = [
|
14
13
|
'setToken', 'Model', 'ModelRevision', 'ModelTopology', 'Runner', 'Result',
|
15
14
|
'PowerFlowResult', 'EMTResult', 'MatlabDataEncoder', 'DateTimeEncode',
|
16
|
-
'function', 'Project', 'currentJob', 'IESLabSimulation', 'IESLabPlan','
|
15
|
+
'function', 'Project', 'currentJob', 'IESLabSimulation', 'IESLabPlan','IESLabOpt','__version__','Job'
|
17
16
|
]
|
18
17
|
|
19
18
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
from cloudpss.asyncio.job.messageStreamReceiver import MessageStreamReceiver
|
2
|
+
from cloudpss.asyncio.job.messageStreamSender import MessageStreamSender
|
3
|
+
from cloudpss.asyncio.utils.AsyncIterable import CustomAsyncIterable
|
4
|
+
from cloudpss.asyncio.utils.httpAsyncRequest import graphql_request
|
5
|
+
from cloudpss.job import Job as JobBase
|
6
|
+
from typing import Any, Callable, TypeVar
|
7
|
+
F = TypeVar('F', bound=Callable[..., Any])
|
8
|
+
|
9
|
+
class Job(JobBase):
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
async def fetch(id):
|
13
|
+
"""
|
14
|
+
获取job信息
|
15
|
+
"""
|
16
|
+
if id is None:
|
17
|
+
raise Exception("id is None")
|
18
|
+
|
19
|
+
variables = {"_a": {"id": id}}
|
20
|
+
|
21
|
+
r = await graphql_request(Job.__jobQuery, variables)
|
22
|
+
if "errors" in r:
|
23
|
+
raise Exception(r["errors"])
|
24
|
+
return Job(**r["data"]["job"])
|
25
|
+
|
26
|
+
@staticmethod
|
27
|
+
def fetchMany(*args):
|
28
|
+
"""
|
29
|
+
批量获取任务信息
|
30
|
+
"""
|
31
|
+
jobs = CustomAsyncIterable(Job.fetch,*args)
|
32
|
+
return jobs
|
33
|
+
|
34
|
+
|
35
|
+
@staticmethod
|
36
|
+
async def create(revisionHash, job, config, name=None, rid="", policy=None, **kwargs):
|
37
|
+
"""
|
38
|
+
创建一个运行任务
|
39
|
+
|
40
|
+
:params: revision 项目版本号
|
41
|
+
:params: job 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
|
42
|
+
:params: config 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
|
43
|
+
:params: name 任务名称,为空时使用项目的参数方案名称和计算方案名称
|
44
|
+
:params: rid 项目rid,可为空
|
45
|
+
|
46
|
+
:return: 返回一个运行实例
|
47
|
+
|
48
|
+
>>> runner = Runner.runRevision(revision,job,config,'')
|
49
|
+
"""
|
50
|
+
|
51
|
+
variables=Job.__createJobVariables(job, config, revisionHash, rid, policy)
|
52
|
+
r = await graphql_request(Job.__createJobQuery, variables)
|
53
|
+
if "errors" in r:
|
54
|
+
raise Exception(r["errors"])
|
55
|
+
id = r["data"]["job"]["id"]
|
56
|
+
return await Job.fetch(id)
|
57
|
+
|
58
|
+
|
59
|
+
@staticmethod
|
60
|
+
async def abort(id, timeout):
|
61
|
+
"""
|
62
|
+
结束当前运行的算例
|
63
|
+
|
64
|
+
"""
|
65
|
+
query = """mutation ($input: AbortJobInput!) {
|
66
|
+
job: abortJob(input: $input) {
|
67
|
+
id
|
68
|
+
status
|
69
|
+
}
|
70
|
+
}
|
71
|
+
"""
|
72
|
+
variables = {"input": {"id": id, "timeout": timeout}}
|
73
|
+
await graphql_request(query, variables)
|
74
|
+
|
75
|
+
async def result(self, resultType:F)->F:
|
76
|
+
"""
|
77
|
+
获取当前运行实例的输出
|
78
|
+
"""
|
79
|
+
receiver = await self.read()
|
80
|
+
sender = await self.write()
|
81
|
+
self._result= resultType(receiver, sender)
|
82
|
+
return self._result
|
83
|
+
|
84
|
+
async def write(self, sender=None, dev=False, **kwargs) -> MessageStreamSender:
|
85
|
+
"""
|
86
|
+
使用发送器为当前运行实例输入
|
87
|
+
"""
|
88
|
+
|
89
|
+
if sender is not None:
|
90
|
+
self.__sender = sender
|
91
|
+
if self.__sender is None:
|
92
|
+
self.__sender = MessageStreamSender(self, dev)
|
93
|
+
await self.__sender.connect(**kwargs)
|
94
|
+
return self.__sender
|
95
|
+
|
96
|
+
async def read(self, receiver=None, dev=False, **kwargs)-> MessageStreamReceiver:
|
97
|
+
"""
|
98
|
+
使用接收器获取当前运行实例的输出
|
99
|
+
"""
|
100
|
+
if receiver is not None:
|
101
|
+
self.__receiver = receiver
|
102
|
+
if self.__receiver is None:
|
103
|
+
self.__receiver = MessageStreamReceiver(self, dev)
|
104
|
+
await self.__receiver.connect(**kwargs)
|
105
|
+
return self.__receiver
|
106
|
+
|
107
|
+
async def status(self):
|
108
|
+
"""
|
109
|
+
return: 0: 运行中 1: 运行完成 2: 运行失败
|
110
|
+
"""
|
111
|
+
if self.__receiver is not None:
|
112
|
+
return await self.__receiver.status
|
113
|
+
# if self.__receiver is None:
|
114
|
+
# self.__connect()
|
115
|
+
# return 0
|
116
|
+
return 0
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
from urllib.parse import urlparse
|
4
|
+
|
5
|
+
from aiohttp import ClientSession, WSMsgType
|
6
|
+
from cloudpss.asyncio.utils.httpAsyncRequest import websocket_connect
|
7
|
+
from cloudpss.job.jobReceiver import JobReceiver
|
8
|
+
from cloudpss.utils.IO import IO
|
9
|
+
|
10
|
+
|
11
|
+
class MessageStreamReceiver(JobReceiver):
|
12
|
+
def __init__(self, job, dev=False):
|
13
|
+
super().__init__()
|
14
|
+
self.job = job
|
15
|
+
self.dev = dev
|
16
|
+
self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
|
17
|
+
|
18
|
+
async def __receive(self):
|
19
|
+
"""
|
20
|
+
读取消息流中的数据
|
21
|
+
"""
|
22
|
+
msg = await self.ws.receive()
|
23
|
+
result=None
|
24
|
+
if msg.type == WSMsgType.BINARY:
|
25
|
+
result=await self.__on_message(msg.data)
|
26
|
+
if msg.type == WSMsgType.TEXT:
|
27
|
+
result=await self.__on_message(msg.data)
|
28
|
+
elif msg.type == WSMsgType.CLOSE:
|
29
|
+
self.__on_close(msg)
|
30
|
+
elif msg.type == WSMsgType.CLOSED:
|
31
|
+
await self.__on_closed()
|
32
|
+
elif msg.type == WSMsgType.ERROR:
|
33
|
+
self.__on_error(msg.data)
|
34
|
+
return result
|
35
|
+
|
36
|
+
def __aiter__(self):
|
37
|
+
return self
|
38
|
+
|
39
|
+
async def __anext__(self):
|
40
|
+
result = await self.__receive()
|
41
|
+
if result is None:
|
42
|
+
raise StopAsyncIteration
|
43
|
+
return result
|
44
|
+
|
45
|
+
def __on_close(self, msg,*args, **kwargs):
|
46
|
+
if msg is not None and msg.startswith("CMS_NO_STREAM_ID:"):
|
47
|
+
self._status = 1
|
48
|
+
msg = {
|
49
|
+
"type": "log",
|
50
|
+
"version": 1,
|
51
|
+
"data": {
|
52
|
+
"level": "critical",
|
53
|
+
"content": "未找到任务的输出流,运行结果可能已被清理。",
|
54
|
+
},
|
55
|
+
}
|
56
|
+
self.messages.append(msg)
|
57
|
+
return
|
58
|
+
|
59
|
+
async def __on_closed(self, *args, **kwargs):
|
60
|
+
logging.debug("MessageStreamReceiver close")
|
61
|
+
self._status = 1
|
62
|
+
msg = {
|
63
|
+
"type": "log",
|
64
|
+
"verb": "create",
|
65
|
+
"version": 1,
|
66
|
+
"data": {
|
67
|
+
"level": "info",
|
68
|
+
"content": "websocket closed",
|
69
|
+
},
|
70
|
+
}
|
71
|
+
self.messages.append(msg)
|
72
|
+
await self.session.close()
|
73
|
+
|
74
|
+
async def __on_message(self, message):
|
75
|
+
|
76
|
+
data = IO.deserialize(message, "ubjson")
|
77
|
+
msg = IO.deserialize(data["data"], "ubjson")
|
78
|
+
self.messages.append(msg)
|
79
|
+
# print(msg['type'])
|
80
|
+
if(msg['type']=='terminate'):
|
81
|
+
await self.close(self.ws)
|
82
|
+
return msg
|
83
|
+
|
84
|
+
def __on_error(self, msg,*args, **kwargs):
|
85
|
+
logging.debug("MessageStreamReceiver error")
|
86
|
+
msg = {
|
87
|
+
"type": "log",
|
88
|
+
"verb": "create",
|
89
|
+
"version": 1,
|
90
|
+
"data": {
|
91
|
+
"level": "error",
|
92
|
+
"content": "websocket error",
|
93
|
+
},
|
94
|
+
}
|
95
|
+
self.messages.append(msg)
|
96
|
+
|
97
|
+
@property
|
98
|
+
async def status(self):
|
99
|
+
await self.__receive()
|
100
|
+
return self._status
|
101
|
+
|
102
|
+
async def close(self, ws):
|
103
|
+
self._status = 1
|
104
|
+
await ws.close()
|
105
|
+
|
106
|
+
async def connect(self,**kwargs):
|
107
|
+
self._status = 0
|
108
|
+
|
109
|
+
if self.job.output is None:
|
110
|
+
raise Exception("id is None")
|
111
|
+
u = list(urlparse(self.origin))
|
112
|
+
head = "wss" if u[0] == "https" else "ws"
|
113
|
+
|
114
|
+
path = head + "://" + str(u[1]) + "/api/streams/id/" + self.job.output
|
115
|
+
from_=kwargs.get("from",None)
|
116
|
+
if from_ is not None:
|
117
|
+
path = path + "&from=" + str(from_)
|
118
|
+
logging.info(f"MessageStreamReceiver data from websocket: {path}")
|
119
|
+
|
120
|
+
self.session= ClientSession()
|
121
|
+
self.ws= await self.session.ws_connect(path)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
import logging
|
3
|
+
from typing import IO
|
4
|
+
from urllib.parse import urlparse
|
5
|
+
import aiohttp
|
6
|
+
from cloudpss.job.messageStreamSender import MessageStreamSender as MessageStreamSenderBase
|
7
|
+
|
8
|
+
|
9
|
+
class MessageStreamSender(MessageStreamSenderBase):
|
10
|
+
|
11
|
+
|
12
|
+
async def receive_data(self):
|
13
|
+
if self.websocket:
|
14
|
+
data = await self.websocket.receive()
|
15
|
+
if data.type == aiohttp.WSMsgType.TEXT:
|
16
|
+
self.__on_message(data.data)
|
17
|
+
elif data.type == aiohttp.WSMsgType.CLOSED:
|
18
|
+
self.__on_close()
|
19
|
+
elif data.type == aiohttp.WSMsgType.ERROR:
|
20
|
+
self.__on_error(data.data)
|
21
|
+
else:
|
22
|
+
logging.info("WebSocket connection not established")
|
23
|
+
|
24
|
+
async def connect(self):
|
25
|
+
self._status = 0
|
26
|
+
if self.job.input is None:
|
27
|
+
raise Exception("id is None")
|
28
|
+
if self.job.input == "00000000-0000-0000-0000-000000000000":
|
29
|
+
return
|
30
|
+
u = list(urlparse(self.origin))
|
31
|
+
head = "wss" if u[0] == "https" else "ws"
|
32
|
+
|
33
|
+
path = head + "://" + str(u[1]) + "/api/streams/token/" + self.job.input
|
34
|
+
logging.info(f"MessageStreamSender data from websocket: {path}")
|
35
|
+
async with aiohttp.ClientSession() as session:
|
36
|
+
self.websocket = await session.ws_connect(path)
|
37
|
+
|
38
|
+
async def write(self, message):
|
39
|
+
if self.websocket:
|
40
|
+
data = IO.serialize(message, "ubjson", None)
|
41
|
+
await self.websocket.send_bytes(data)
|
42
|
+
else:
|
43
|
+
logging.info("websocket is None")
|
44
|
+
|
45
|
+
|
@@ -0,0 +1,257 @@
|
|
1
|
+
import os
|
2
|
+
import re
|
3
|
+
from cloudpss.asyncio.job.job import Job
|
4
|
+
from cloudpss.asyncio.model.revision import ModelRevision
|
5
|
+
from cloudpss.asyncio.utils.httpAsyncRequest import graphql_request
|
6
|
+
from cloudpss.model.model import Model as ModelBase
|
7
|
+
from cloudpss.verify import userName
|
8
|
+
|
9
|
+
|
10
|
+
class Model(ModelBase):
|
11
|
+
|
12
|
+
def __init__(self, model: dict = {}):
|
13
|
+
"""
|
14
|
+
项目初始化
|
15
|
+
"""
|
16
|
+
for k, v in model.items():
|
17
|
+
if k == "revision":
|
18
|
+
if "version" in v and v["version"] < 5:
|
19
|
+
self.revision = ModelRevision(v)
|
20
|
+
else:
|
21
|
+
raise Exception(
|
22
|
+
"当前SDK版本(ver 3.X.X)不兼容该项目文件,请先升级项目文件。具体方法:将该项目文件导入至XStudio 3.X.X平台后重新保存至本地后即可。"
|
23
|
+
)
|
24
|
+
|
25
|
+
else:
|
26
|
+
self.__dict__[k] = v
|
27
|
+
@staticmethod
|
28
|
+
async def fetch(rid):
|
29
|
+
"""
|
30
|
+
获取项目
|
31
|
+
|
32
|
+
:params rid: 项目 rid
|
33
|
+
|
34
|
+
:return: 返回一个项目实例
|
35
|
+
|
36
|
+
>>> model=Model.fetch('model/Demo/test')
|
37
|
+
|
38
|
+
"""
|
39
|
+
data = await graphql_request(Model.__model_query, {"rid": rid})
|
40
|
+
if "errors" in data:
|
41
|
+
raise Exception(data["errors"][0]["message"])
|
42
|
+
return Model(data["data"]["model"])
|
43
|
+
|
44
|
+
async def save(self, key=None):
|
45
|
+
"""
|
46
|
+
保存/创建项目
|
47
|
+
|
48
|
+
key 不为空时如果远程存在相同的资源名称时将覆盖远程项目。
|
49
|
+
key 为空时如果项目 rid 不存在则抛异常,需要重新设置 key。
|
50
|
+
如果保存时,当前用户不是该项目的拥有者时,将重新创建项目,重建项目时如果参数的 key 为空将使用当前当前项目的 key 作为资源的 key ,当资源的 key 和远程冲突时保存失败
|
51
|
+
|
52
|
+
:params: model 项目
|
53
|
+
:params: key 资源 id 的唯一标识符,
|
54
|
+
|
55
|
+
:return: 保存成功/保存失败
|
56
|
+
|
57
|
+
>>> model.save(model)
|
58
|
+
model.save(model,'newKey') # 另存为新的项目
|
59
|
+
|
60
|
+
"""
|
61
|
+
username = userName()
|
62
|
+
|
63
|
+
if key is not None:
|
64
|
+
matchObj = re.match(r"^[-_A-Za-z0-9]+$", key, re.I | re.S)
|
65
|
+
if matchObj:
|
66
|
+
self.rid = "model/" + username + "/" + key
|
67
|
+
try:
|
68
|
+
return await Model.update(self)
|
69
|
+
except:
|
70
|
+
return await Model.create(self)
|
71
|
+
else:
|
72
|
+
raise Exception("key 能包含字母数子和下划线")
|
73
|
+
else:
|
74
|
+
t = "(?<=/)\\S+(?=/)"
|
75
|
+
owner = re.search(t, self.rid)
|
76
|
+
if owner is None:
|
77
|
+
raise Exception("rid 错误,请传入 key")
|
78
|
+
elif owner[0] != username:
|
79
|
+
rid = re.sub(t, username, self.rid)
|
80
|
+
try:
|
81
|
+
return await Model.create(self)
|
82
|
+
except:
|
83
|
+
raise Exception(rid + " 该资源已存在,无法重复创建,请修改 key")
|
84
|
+
|
85
|
+
return await Model.update(self)
|
86
|
+
|
87
|
+
@staticmethod
|
88
|
+
async def fetchMany(name=None, cursor=[]):
|
89
|
+
"""
|
90
|
+
获取用户可以运行的项目列表
|
91
|
+
|
92
|
+
:params name: 查询名称,模糊查询
|
93
|
+
:params cursor: 游标
|
94
|
+
|
95
|
+
:return: 按分页信息返回项目列表
|
96
|
+
|
97
|
+
>>> data= await Model.fetchMany()
|
98
|
+
{
|
99
|
+
items: [
|
100
|
+
{'rid': 'model/admin/share-test', 'name': '1234', 'description': '1234'}
|
101
|
+
...
|
102
|
+
],
|
103
|
+
cursor: ["1699353593000"],
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
"""
|
109
|
+
variables = {
|
110
|
+
"cursor": cursor,
|
111
|
+
"limit": 10,
|
112
|
+
"orderBy": ["updatedAt<"],
|
113
|
+
"permissionEveryone": ["b_any", 2**16],
|
114
|
+
}
|
115
|
+
if name is not None:
|
116
|
+
variables["_search"] = name
|
117
|
+
|
118
|
+
data = await graphql_request(Model.__models_query, {"input": variables})
|
119
|
+
|
120
|
+
if "errors" in data:
|
121
|
+
raise Exception(data["errors"][0]["message"])
|
122
|
+
|
123
|
+
return data["data"]["models"]
|
124
|
+
|
125
|
+
|
126
|
+
@staticmethod
|
127
|
+
async def create(model):
|
128
|
+
"""
|
129
|
+
新建项目
|
130
|
+
|
131
|
+
:params: model 项目
|
132
|
+
|
133
|
+
:return: 保存成功/保存失败
|
134
|
+
|
135
|
+
>>> Model.create(model)
|
136
|
+
保存成功
|
137
|
+
"""
|
138
|
+
# Model.update(model)
|
139
|
+
t = "(?<=/)\\S+(?=/)"
|
140
|
+
username = userName()
|
141
|
+
owner = re.search(t, model.rid)
|
142
|
+
|
143
|
+
if owner is None:
|
144
|
+
raise Exception("rid 错误,无法保存")
|
145
|
+
elif owner[0] != username:
|
146
|
+
raise Exception("rid 错误,无法保存")
|
147
|
+
|
148
|
+
isPublic = model.context.get("auth", "") != "private"
|
149
|
+
publicRead = model.context.get("publicRead", "") != False
|
150
|
+
auth = (65539 if publicRead else 65537) if isPublic else 0
|
151
|
+
revision = await ModelRevision.create(model.revision, model.revision.hash)
|
152
|
+
|
153
|
+
return await graphql_request(
|
154
|
+
Model.__models_query,
|
155
|
+
{
|
156
|
+
"a": {
|
157
|
+
"rid": model.rid,
|
158
|
+
"revision": revision["hash"],
|
159
|
+
"context": model.context,
|
160
|
+
"configs": model.configs,
|
161
|
+
"jobs": model.jobs,
|
162
|
+
"name": model.name,
|
163
|
+
"description": model.description,
|
164
|
+
"tags": model.tags,
|
165
|
+
"permissions": {
|
166
|
+
"moderator": 1,
|
167
|
+
"member": 1,
|
168
|
+
"everyone": auth,
|
169
|
+
},
|
170
|
+
}
|
171
|
+
},
|
172
|
+
)
|
173
|
+
|
174
|
+
|
175
|
+
@staticmethod
|
176
|
+
async def update(model):
|
177
|
+
"""
|
178
|
+
更新项目
|
179
|
+
|
180
|
+
:params: model 项目
|
181
|
+
|
182
|
+
:return: 保存成功/保存失败
|
183
|
+
|
184
|
+
>>> Model.update(model)
|
185
|
+
"""
|
186
|
+
|
187
|
+
t = "(?<=/)\\S+(?=/)"
|
188
|
+
username = userName()
|
189
|
+
owner = re.search(t, model.rid)
|
190
|
+
|
191
|
+
if owner is None:
|
192
|
+
raise Exception("rid 错误,无法保存")
|
193
|
+
elif owner[0] != username:
|
194
|
+
raise Exception("rid 错误,无法保存")
|
195
|
+
|
196
|
+
|
197
|
+
isPublic = model.context.get("auth", "") != "private"
|
198
|
+
isComponent = model.context.get("category", "") == "component"
|
199
|
+
publicRead = model.context.get("publicRead", "") != False
|
200
|
+
auth = (65539 if publicRead else 65537) if isPublic else 0
|
201
|
+
revision = await ModelRevision.create(model.revision, model.revision.hash)
|
202
|
+
|
203
|
+
xVersion = int(float(os.environ.get("X_CLOUDPSS_VERSION", 4)))
|
204
|
+
tags = {"replace": model.tags}
|
205
|
+
if xVersion == 3:
|
206
|
+
tags = model.tags
|
207
|
+
|
208
|
+
return await graphql_request(
|
209
|
+
Model.__update_model,
|
210
|
+
{
|
211
|
+
"a": {
|
212
|
+
"rid": model.rid,
|
213
|
+
"revision": revision["hash"],
|
214
|
+
"context": model.context,
|
215
|
+
"configs": model.configs,
|
216
|
+
"jobs": model.jobs,
|
217
|
+
"name": model.name,
|
218
|
+
"description": model.description,
|
219
|
+
"tags": tags,
|
220
|
+
"permissions": {
|
221
|
+
"moderator": 1,
|
222
|
+
"member": 1,
|
223
|
+
"everyone": auth,
|
224
|
+
},
|
225
|
+
}
|
226
|
+
},
|
227
|
+
)
|
228
|
+
|
229
|
+
async def run(self, job=None, config=None, name=None, policy=None,stop_on_entry=None, **kwargs):
|
230
|
+
"""
|
231
|
+
|
232
|
+
调用仿真
|
233
|
+
|
234
|
+
:params job: 调用仿真时使用的计算方案,不指定将使用算例保存时选中的计算方案
|
235
|
+
:params config: 调用仿真时使用的参数方案,不指定将使用算例保存时选中的参数方案
|
236
|
+
:params name: 任务名称,为空时使用项目的参数方案名称和计算方案名称
|
237
|
+
|
238
|
+
:return: 返回一个Job实例
|
239
|
+
|
240
|
+
>>> job=model.run(job,config,'')
|
241
|
+
job
|
242
|
+
|
243
|
+
"""
|
244
|
+
if job is None:
|
245
|
+
currentJob = self.context["currentJob"]
|
246
|
+
job = self.jobs[currentJob]
|
247
|
+
if config is None:
|
248
|
+
currentConfig = self.context["currentConfig"]
|
249
|
+
config = self.configs[currentConfig]
|
250
|
+
revision = await self.revision.run(
|
251
|
+
job, config, name, self.rid, policy, **kwargs
|
252
|
+
)
|
253
|
+
if stop_on_entry is not None:
|
254
|
+
job['args']['stop_on_entry'] = stop_on_entry
|
255
|
+
return await Job.create(
|
256
|
+
revision["hash"], job, config, name, self.rid, policy, **kwargs
|
257
|
+
)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from cloudpss.asyncio.utils.httpAsyncRequest import graphql_request
|
2
|
+
from cloudpss.model.revision import ModelRevision as ModelRevisionBase
|
3
|
+
|
4
|
+
|
5
|
+
class ModelRevision(ModelRevisionBase):
|
6
|
+
|
7
|
+
@staticmethod
|
8
|
+
async def create(revision, parentHash=None):
|
9
|
+
"""
|
10
|
+
创建一个新版本
|
11
|
+
|
12
|
+
:params: revision 版本数据
|
13
|
+
|
14
|
+
:return: 项目版本hash
|
15
|
+
|
16
|
+
>>> ModelRevision.create(model.revision)
|
17
|
+
{hash:'4043acbddb9ce0c6174be65573c0380415bc48186c74a459f88865313743230c'}
|
18
|
+
"""
|
19
|
+
|
20
|
+
r = revision.toJSON()
|
21
|
+
del r['hash']
|
22
|
+
variables = {'a': {**r, 'parent': parentHash}}
|
23
|
+
r = await graphql_request(ModelRevision.__createModelRevisionQuery, variables)
|
24
|
+
if 'errors' in r:
|
25
|
+
raise Exception(r['errors'])
|
26
|
+
return r['data']['createModelRevision']
|
27
|
+
|
28
|
+
async def run(self, job, config, name=None, rid='', policy=None, **kwargs):
|
29
|
+
"""
|
30
|
+
运行某个指定版本的项目
|
31
|
+
|
32
|
+
:params job: 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
|
33
|
+
:params config: 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
|
34
|
+
:params name: 任务名称,为空时使用项目的参数方案名称和计算方案名称
|
35
|
+
:params rid: 项目rid,可为空
|
36
|
+
|
37
|
+
:return: 返回一个ModelRevision
|
38
|
+
|
39
|
+
>>> revision.run(revision,job,config,'')
|
40
|
+
"""
|
41
|
+
return await ModelRevision.create(self)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from cloudpss.asyncio.utils.httpAsyncRequest import graphql_request
|
2
|
+
from cloudpss.model.topology import ModelTopology as ModelTopologyBase
|
3
|
+
|
4
|
+
|
5
|
+
class ModelTopology(ModelTopologyBase):
|
6
|
+
@staticmethod
|
7
|
+
async def fetch(hash, implementType, config, maximumDepth=None):
|
8
|
+
"""
|
9
|
+
获取拓扑
|
10
|
+
|
11
|
+
:params: hash
|
12
|
+
:params: implementType 实现类型
|
13
|
+
:params: config 参数方案
|
14
|
+
:params: maximumDepth 最大递归深度,用于自定义项目中使用 diagram 实现元件展开情况
|
15
|
+
|
16
|
+
: return: 拓扑实例
|
17
|
+
|
18
|
+
>>> data = ModelTopology.fetch('','emtp',{})
|
19
|
+
|
20
|
+
"""
|
21
|
+
args = {} if config is None else config['args']
|
22
|
+
variables = {
|
23
|
+
"a": {
|
24
|
+
'hash': hash,
|
25
|
+
'args': args,
|
26
|
+
'acceptImplementType': implementType,
|
27
|
+
'maximumDepth': maximumDepth
|
28
|
+
}
|
29
|
+
}
|
30
|
+
data = await graphql_request(ModelTopology.__modelTopologyQuery, variables)
|
31
|
+
if 'errors' in data:
|
32
|
+
raise Exception(data['errors'][0]['message'])
|
33
|
+
|
34
|
+
return ModelTopology(data['data']['modelTopology'])
|
@@ -3,7 +3,7 @@ import os
|
|
3
3
|
from aiohttp import ClientSession, WSMsgType
|
4
4
|
from urllib.parse import urljoin
|
5
5
|
import logging
|
6
|
-
from
|
6
|
+
from ...version import __version__
|
7
7
|
|
8
8
|
|
9
9
|
def graphql_version_check(uri, response):
|
@@ -54,7 +54,7 @@ async def fetch_data(method: str, uri, data, baseUrl=None, params={}, **kwargs):
|
|
54
54
|
|
55
55
|
|
56
56
|
# graphql实现方法
|
57
|
-
async def
|
57
|
+
async def graphql_request(query, variables=None):
|
58
58
|
payload = {"query": query, "variables": variables}
|
59
59
|
return await fetch_data("POST", "graphql", data=json.dumps(payload))
|
60
60
|
|