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/__init__.py CHANGED
@@ -6,17 +6,16 @@ from .model import Model, ModelRevision, ModelTopology
6
6
  from .project import Project
7
7
  from .utils import MatlabDataEncoder, DateTimeEncode
8
8
  from . import function
9
-
9
+ from .job import Job
10
10
  from .function import FunctionExecution
11
11
  from .version import __version__
12
12
  __all__ = [
13
13
  'setToken', 'Model', 'ModelRevision', 'ModelTopology', 'Runner', 'Result',
14
14
  'PowerFlowResult', 'EMTResult', 'MatlabDataEncoder', 'DateTimeEncode',
15
- 'function', 'Project', 'currentJob', 'IESLabSimulation', 'IESLabPlan','__version__'
15
+ 'function', 'Project', 'currentJob', 'IESLabSimulation', 'IESLabPlan','__version__','Job'
16
16
  ]
17
17
 
18
18
 
19
-
20
19
  def currentJob():
21
20
  """
22
21
  获取当前的 currentExecution 实例
@@ -163,7 +163,7 @@ class FunctionExecution(object):
163
163
  sys.exit(code)
164
164
 
165
165
  def print(self, data):
166
- print(json.dumps(data, cls=MatlabDataEncoder), flush=True)
166
+ print(json.dumps(data, cls=MatlabDataEncoder)+'\n', flush=True)
167
167
 
168
168
  def log(self, content, level='info', html=False, key=None):
169
169
  '''
cloudpss/job/job.py CHANGED
@@ -1,6 +1,10 @@
1
+ import asyncio
1
2
  import random
2
3
  import re
3
4
  import time
5
+ from cloudpss.utils.AsyncIterable import CustomAsyncIterable
6
+
7
+ from cloudpss.utils.httpAsyncRequest import graphql_fetch
4
8
  from .view import getViewClass
5
9
 
6
10
  from cloudpss.utils.IO import IO
@@ -12,20 +16,33 @@ from .jobMachine import JobMachine
12
16
  from .messageStreamSender import MessageStreamSender
13
17
 
14
18
 
15
-
16
19
  class Job(object):
17
20
  """docstring for Job"""
18
21
 
19
- def __init__(self, id, args, createTime, startTime, endTime, status,
20
- context, user, priority, policy, machine, input, output,
21
- position):
22
+ def __init__(
23
+ self,
24
+ id,
25
+ args,
26
+ createTime,
27
+ startTime,
28
+ endTime,
29
+ status,
30
+ context,
31
+ user,
32
+ priority,
33
+ policy,
34
+ machine,
35
+ input,
36
+ output,
37
+ position,
38
+ ):
22
39
  super(Job, self).__init__()
23
40
  self.id = id
24
41
  self.args = args
25
42
  self.createTime = createTime
26
43
  self.startTime = startTime
27
44
  self.endTime = endTime
28
- self.status = status
45
+ self.job_status = status #这里的status字段与原本的status()冲突
29
46
  self.context = context
30
47
  self.user = user
31
48
  self.priority = priority
@@ -36,15 +53,16 @@ class Job(object):
36
53
  self.position = position
37
54
  self.__receiver = None
38
55
  self.__sender = None
56
+ self._result = None
39
57
 
40
58
  @staticmethod
41
- def fetch(id):
59
+ async def fetch(id):
42
60
  """
43
61
  获取job信息
44
62
  """
45
63
  if id is None:
46
- raise Exception('id is None')
47
- query = '''query($_a:JobInput!){
64
+ raise Exception("id is None")
65
+ query = """query($_a:JobInput!){
48
66
  job(input:$_a){
49
67
  id
50
68
  args
@@ -79,165 +97,103 @@ class Job(object):
79
97
  output
80
98
  position
81
99
  }
82
- }'''
100
+ }"""
83
101
  variables = {"_a": {"id": id}}
84
- r = graphql_request(query, variables)
85
- if 'errors' in r:
86
- raise Exception(r['errors'])
87
- return Job(**r['data']['job'])
102
+
103
+ r = await graphql_fetch(query, variables)
104
+ if "errors" in r:
105
+ raise Exception(r["errors"])
106
+ return Job(**r["data"]["job"])
88
107
 
89
108
  @staticmethod
90
- def fetchMany(input):
109
+ def fetchMany(*args):
91
110
  """
92
111
  批量获取任务信息
93
112
  """
94
- if input is None:
95
- raise Exception('input is None')
96
- query = '''query($_a:JobsInput!){
97
- jobs(input:$_a){
98
- item {
99
- id
100
- args
101
- createTime
102
- startTime
103
- endTime
104
- status
105
- context
106
- user
107
- priority
108
- policy {
109
- id
110
- name
111
- users
112
- functions
113
- tres {
114
- cpu
115
- ecpu
116
- mem
117
- }
118
- minPriority
119
- maxPriority
120
- maxDuration
121
- createTime
122
- updateTime
123
- visibility
124
- queue
125
- }
126
- machine {
127
- id
128
- name
129
- tres {
130
- cpu
131
- ecpu
132
- mem
133
- }
134
- valid
135
- }
136
- input
137
- output
138
- position
139
- }
140
- cursor
141
- count
142
- total
143
- }
144
- }'''
145
- variables = {"_a": input}
146
- r = graphql_request(query, variables)
147
- if 'errors' in r:
148
- raise Exception(r['errors'])
149
- jobs = []
150
- for job in r['data']['jobs']['item']:
151
- jobs.append(Job(**job))
113
+ jobs = CustomAsyncIterable(Job.fetch,*args)
152
114
  return jobs
115
+
153
116
 
154
117
  @staticmethod
155
- def create(revisionHash,
156
- job,
157
- config,
158
- name=None,
159
- rid='',
160
- policy=None,
161
- **kwargs):
162
- '''
163
- 创建一个运行任务
118
+ async def create(revisionHash, job, config, name=None, rid="", policy=None, **kwargs):
119
+ """
120
+ 创建一个运行任务
164
121
 
165
- :params: revision 项目版本号
166
- :params: job 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
167
- :params: config 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
168
- :params: name 任务名称,为空时使用项目的参数方案名称和计算方案名称
169
- :params: rid 项目rid,可为空
122
+ :params: revision 项目版本号
123
+ :params: job 调用仿真时使用的计算方案,为空时使用项目的第一个计算方案
124
+ :params: config 调用仿真时使用的参数方案,为空时使用项目的第一个参数方案
125
+ :params: name 任务名称,为空时使用项目的参数方案名称和计算方案名称
126
+ :params: rid 项目rid,可为空
170
127
 
171
- :return: 返回一个运行实例
128
+ :return: 返回一个运行实例
172
129
 
173
- >>> runner = Runner.runRevision(revision,job,config,'')
174
- '''
130
+ >>> runner = Runner.runRevision(revision,job,config,'')
131
+ """
175
132
 
176
- #处理policy字段
133
+ # 处理policy字段
177
134
  if policy is None:
178
135
  policy = {}
179
- if policy.get('tres', None) is None:
180
- policy['tres'] = {}
181
- policy['queue'] = job['args'].get('@queue', 1)
182
- policy['priority'] = job['args'].get('@priority', 0)
183
- tres = {'cpu': 1, 'ecpu': 0, 'mem': 0}
184
- tresStr = job['args'].get('@tres', '')
185
- for t in re.split('\s+', tresStr):
186
- if t == '':
136
+ if policy.get("tres", None) is None:
137
+ policy["tres"] = {}
138
+ policy["queue"] = job["args"].get("@queue", 1)
139
+ policy["priority"] = job["args"].get("@priority", 0)
140
+ tres = {"cpu": 1, "ecpu": 0, "mem": 0}
141
+ tresStr = job["args"].get("@tres", "")
142
+ for t in re.split("\s+", tresStr):
143
+ if t == "":
187
144
  continue
188
- k, v = t.split('=')
189
- tres[k] = float(v) #type: ignore
190
- policy['tres'] = tres
145
+ k, v = t.split("=")
146
+ tres[k] = float(v) # type: ignore
147
+ policy["tres"] = tres
191
148
 
192
- query = '''mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}'''
193
- function = job['rid'].replace('job-definition/cloudpss/',
194
- 'function/CloudPSS/')
149
+ query = """mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}"""
150
+ function = job["rid"].replace("job-definition/cloudpss/", "function/CloudPSS/")
195
151
  variables = {
196
- 'input': {
152
+ "input": {
197
153
  "args": {
198
- **job['args'], '_ModelRevision': revisionHash,
199
- '_ModelArgs': config['args']
154
+ **job["args"],
155
+ "_ModelRevision": revisionHash,
156
+ "_ModelArgs": config["args"],
200
157
  },
201
158
  "context": [
202
159
  function,
203
160
  rid,
204
- f"model/@sdk/{str(int(time.time() * random.random()))}"
161
+ f"model/@sdk/{str(int(time.time() * random.random()))}",
205
162
  ],
206
- "policy":
207
- policy,
163
+ "policy": policy,
208
164
  }
209
165
  }
210
- r = graphql_request(query, variables)
211
- if 'errors' in r:
212
- raise Exception(r['errors'])
213
- id = r['data']['job']['id']
214
- return Job.fetch(id)
166
+ r = await graphql_fetch(query, variables)
167
+ if "errors" in r:
168
+ raise Exception(r["errors"])
169
+ id = r["data"]["job"]["id"]
170
+ return await Job.fetch(id)
215
171
 
216
172
  @staticmethod
217
- def abort(id, timeout):
173
+ async def abort(id, timeout):
218
174
  """
219
175
  结束当前运行的算例
220
176
 
221
177
  """
222
- query = '''mutation ($input: AbortJobInput!) {
178
+ query = """mutation ($input: AbortJobInput!) {
223
179
  job: abortJob(input: $input) {
224
180
  id
225
181
  status
226
182
  }
227
183
  }
228
- '''
229
- variables = {'input': {'id': id, 'timeout': timeout}}
230
- graphql_request(query, variables)
184
+ """
185
+ variables = {"input": {"id": id, "timeout": timeout}}
186
+ await graphql_fetch(query, variables)
231
187
 
232
188
  @staticmethod
233
- def load(file, format='yaml'):
189
+ def load(file, format="yaml"):
234
190
  return IO.load(file, format)
235
191
 
236
192
  @staticmethod
237
- def dump(job, file, format='yaml', compress='gzip'):
193
+ def dump(job, file, format="yaml", compress="gzip"):
238
194
  return IO.dump(job, file, format, compress)
239
195
 
240
- def read(self, receiver=None, dev=False, **kwargs):
196
+ async def read(self, receiver=None, dev=False, **kwargs):
241
197
  """
242
198
  使用接收器获取当前运行实例的输出
243
199
  """
@@ -245,33 +201,40 @@ class Job(object):
245
201
  self.__sender = receiver
246
202
  if self.__receiver is None:
247
203
  self.__receiver = MessageStreamReceiver(self, dev)
248
- self.__receiver.connect(**kwargs)
204
+ await self.__receiver.connect(**kwargs)
249
205
  return self.__receiver
250
206
 
251
- def write(self,sender=None, dev=False, **kwargs)->MessageStreamSender:
207
+ async def write(self, sender=None, dev=False, **kwargs) -> MessageStreamSender:
252
208
  """
253
- 使用发送器为当前运行实例输入
209
+ 使用发送器为当前运行实例输入
254
210
  """
255
-
211
+
256
212
  if sender is not None:
257
213
  self.__sender = sender
258
214
  if self.__sender is None:
259
- self.__sender =MessageStreamSender(self,dev)
260
- self.__sender.connect(**kwargs)
215
+ self.__sender = MessageStreamSender(self, dev)
216
+ await self.__sender.connect(**kwargs)
261
217
  return self.__sender
262
218
 
219
+ def status(self):
220
+ if self.__receiver is not None:
221
+ return self.__receiver.status
222
+ return 0
223
+
263
224
  @property
264
225
  def result(self):
265
226
  """
266
227
  获取当前运行实例的输出
267
228
  """
268
- viewType = getViewClass(self.context[0])
269
- return self.view(viewType)
229
+ if self._result is None:
230
+ viewType = getViewClass(self.context[0])
231
+ self._result = asyncio.run(self.view(viewType))
232
+ return self._result
270
233
 
271
- def view(self, viewType):
234
+ async def view(self, viewType):
272
235
  """
273
236
  获取当前运行实例的输出
274
237
  """
275
- receiver = self.read()
276
- sender=self.write()
277
- return viewType(receiver,sender)
238
+ receiver = await self.read()
239
+ sender = await self.write()
240
+ return viewType(receiver, sender)
@@ -1,35 +1,30 @@
1
1
  import logging
2
+
3
+ from cloudpss.utils.httpAsyncRequest import websocket_connect
2
4
  from .jobReceiver import JobReceiver
3
5
  import os
4
6
  from urllib.parse import urlparse
5
- import websocket
6
7
  import pytz
7
- import threading
8
- import time
9
- utc_tz = pytz.timezone('UTC')
8
+
9
+ utc_tz = pytz.timezone("UTC")
10
10
 
11
11
  from ..utils.IO import IO
12
12
 
13
13
 
14
14
  class Message(object):
15
-
16
15
  def __init__(self, id, token):
17
16
  self.id = id
18
17
  self.token = token
19
-
20
18
 
21
19
 
22
20
  class MessageStreamReceiver(JobReceiver):
23
-
24
21
  def __init__(self, job, dev=False):
25
22
  super().__init__()
26
23
  self.job = job
27
24
  self.dev = dev
28
- self.origin = os.environ.get('CLOUDPSS_API_URL',
29
- 'https://cloudpss.net/')
30
- self.__hasOpen=False
25
+ self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
31
26
 
32
- def receive(self, id, fr0m, on_open, on_message, on_error, on_close):
27
+ async def receive(self, id, fr0m, on_open, on_message, on_error, on_close):
33
28
  """
34
29
  读取消息流中的数据
35
30
  id: 消息流id
@@ -40,28 +35,31 @@ class MessageStreamReceiver(JobReceiver):
40
35
  on_close: 连接关闭时的回调函数
41
36
  """
42
37
  if id is None:
43
- raise Exception('id is None')
38
+ raise Exception("id is None")
44
39
  u = list(urlparse(self.origin))
45
- head = 'wss' if u[0] == 'https' else 'ws'
40
+ head = "wss" if u[0] == "https" else "ws"
46
41
 
47
- path = head + '://' + str(u[1]) + '/api/streams/id/' + id
42
+ path = head + "://" + str(u[1]) + "/api/streams/id/" + id
48
43
  if fr0m is not None:
49
- path = path + '&from=' + str(fr0m)
44
+ path = path + "&from=" + str(fr0m)
50
45
  logging.info(f"receive data from websocket: {path}")
51
- ws = websocket.WebSocketApp(path,
52
- on_open=on_open,
53
- on_message=on_message,
54
- on_error=on_error,
55
- on_close=on_close)
56
-
46
+ ws = await websocket_connect(
47
+ path,
48
+ open_func=on_open,
49
+ receive_func=on_message,
50
+ error_func=on_error,
51
+ closed_func=on_close,
52
+ )
53
+
57
54
  return ws
58
-
55
+
59
56
  ###下面是兼容Receiver部分功能实现
60
57
 
61
- def on_message(self, ws, message):
62
- data = IO.deserialize(message, 'ubjson')
63
- msg = IO.deserialize(data['data'], 'ubjson')
64
- if msg.get('type', None) == 'log' and self.dev:
58
+ def on_message(self, message):
59
+ data = IO.deserialize(message, "ubjson")
60
+ msg = IO.deserialize(data["data"], "ubjson")
61
+ logging.debug(f"receive message: {msg}")
62
+ if msg.get("type", None) == "log" and self.dev:
65
63
  print(msg)
66
64
  self.messages.append(msg)
67
65
  # if msg and type(msg) is dict and msg.get('type', None) == 'terminate':
@@ -70,12 +68,12 @@ class MessageStreamReceiver(JobReceiver):
70
68
  def on_error(self, ws, error):
71
69
  logging.info("MessageStreamReceiver error")
72
70
  msg = {
73
- 'type': 'log',
74
- 'verb': 'create',
75
- 'version': 1,
76
- 'data': {
77
- 'level': 'error',
78
- 'content': "websocket error",
71
+ "type": "log",
72
+ "verb": "create",
73
+ "version": 1,
74
+ "data": {
75
+ "level": "error",
76
+ "content": "websocket error",
79
77
  },
80
78
  }
81
79
  self.messages.append(msg)
@@ -84,37 +82,46 @@ class MessageStreamReceiver(JobReceiver):
84
82
  logging.info("MessageStreamReceiver close")
85
83
  self._status = 0
86
84
  msg = {
87
- 'type': 'log',
88
- 'verb': 'create',
89
- 'version': 1,
90
- 'data': {
91
- 'level': 'error',
92
- 'content': "websocket closed",
85
+ "type": "log",
86
+ "verb": "create",
87
+ "version": 1,
88
+ "data": {
89
+ "level": "error",
90
+ "content": "websocket closed",
93
91
  },
94
92
  }
95
93
  self.messages.append(msg)
96
94
 
97
- def on_open(self, ws):
95
+ def on_open(self):
98
96
  self._status = 1
99
- self.__hasOpen=True
97
+ self.__hasOpen = True
100
98
  pass
101
99
 
102
100
  def close(self, ws):
103
101
  self._status = 0
104
102
  ws.close()
105
103
 
104
+ @property
105
+ def status(self):
106
+ return self._status
107
+
106
108
  @property
107
109
  def end(self):
108
- return not self._status
110
+ return not self._status
109
111
 
110
- def connect(self):
112
+ async def connect(self):
111
113
  self._status = 0
112
- self.ws = self.receive(self.job.output, None, self.on_open,
113
- self.on_message, self.on_error, self.on_close)
114
-
115
-
116
- thread = threading.Thread(target=self.ws.run_forever, args=(None , None , 6, 3))
117
- thread.setDaemon(True)
118
- thread.start()
119
- while not self.__hasOpen:
120
- time.sleep(0.2)
114
+ self.ws = await self.receive(
115
+ self.job.output,
116
+ None,
117
+ self.on_open,
118
+ self.on_message,
119
+ self.on_error,
120
+ self.on_close,
121
+ )
122
+
123
+ # thread = threading.Thread(target=self.ws.run_forever, args=(None, None, 6, 3))
124
+ # thread.setDaemon(True)
125
+ # thread.start()
126
+ # while not self.__hasOpen:
127
+ # time.sleep(0.2)
@@ -1,7 +1,10 @@
1
- import sys,os
1
+ import sys, os
2
2
  import threading
3
3
  from urllib.parse import urlparse
4
- sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
4
+
5
+ from cloudpss.utils.httpAsyncRequest import websocket_connect
6
+
7
+ sys.path.append(os.path.join(os.path.dirname(__file__), "../"))
5
8
 
6
9
  import websocket
7
10
 
@@ -9,36 +12,34 @@ from cloudpss.utils.IO import IO
9
12
  import time
10
13
  import logging
11
14
 
12
- class MessageStreamSender():
13
15
 
16
+ class MessageStreamSender:
14
17
  def __init__(self, job, dev=False):
15
18
  super().__init__()
16
19
  self.job = job
17
20
  self.dev = dev
18
- self.origin = os.environ.get('CLOUDPSS_API_URL',
19
- 'https://cloudpss.net/')
21
+ self.origin = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
20
22
 
21
23
  ###下面是兼容Receiver部分功能实现
22
24
 
23
25
  def on_message(self, ws, message):
24
- logging.info('on_message',message)
26
+ logging.info("on_message", message)
25
27
 
26
28
  def on_error(self, ws, error):
27
- logging.info('on_error')
29
+ logging.info("on_error")
28
30
 
29
31
  def on_close(self, *args, **kwargs):
30
32
  time.sleep(0.5)
31
33
  self._status = 0
32
-
33
- logging.info('on_close')
34
34
 
35
- def on_open(self, ws):
35
+ logging.info("on_close")
36
+
37
+ def on_open(self):
36
38
  self._status = 1
37
- logging.info('on_open')
39
+ logging.info("on_open")
38
40
  pass
39
41
 
40
42
  def close(self):
41
-
42
43
  self._status = 0
43
44
  self.ws.close()
44
45
 
@@ -47,28 +48,30 @@ class MessageStreamSender():
47
48
  return self._status
48
49
 
49
50
  def write(self, message):
50
- data = IO.serialize(message, 'ubjson',None)
51
- self.ws.send(data, websocket.ABNF.OPCODE_BINARY)
52
-
53
- def connect(self):
54
- logging.info('connect')
51
+ data = IO.serialize(message, "ubjson", None)
52
+ self.ws.send_bytes(data)
53
+
54
+ async def connect(self):
55
+ logging.info("connect")
55
56
  self._status = 0
56
57
  if self.job.input is None:
57
- raise Exception('id is None')
58
+ raise Exception("id is None")
58
59
  u = list(urlparse(self.origin))
59
- head = 'wss' if u[0] == 'https' else 'ws'
60
+ head = "wss" if u[0] == "https" else "ws"
60
61
 
61
- path = head + '://' + str(u[1]) + '/api/streams/token/' + self.job.input
62
+ path = head + "://" + str(u[1]) + "/api/streams/token/" + self.job.input
62
63
  logging.info(f"receive data from websocket: {path}")
63
-
64
- self.ws = websocket.WebSocketApp(path,
65
- on_open=self.on_open,
66
- on_message=self.on_message,
67
- on_error=self.on_error,
68
- on_close=self.on_close)
69
-
70
- thread = threading.Thread(target=self.ws.run_forever, args=(None , None , 6, 3))
71
- thread.setDaemon(True)
72
- thread.start()
73
- while self.status != 1:
74
- time.sleep(0.2)
64
+
65
+ self.ws = await websocket_connect(
66
+ path,
67
+ open_func=self.on_open,
68
+ receive_func=self.on_message,
69
+ error_func=self.on_error,
70
+ closed_func=self.on_close,
71
+ )
72
+
73
+ # thread = threading.Thread(target=self.ws.run_forever, args=(None, None, 6, 3))
74
+ # thread.setDaemon(True)
75
+ # thread.start()
76
+ # while self.status != 1:
77
+ # time.sleep(0.2)