cloudpss 4.0.3__py3-none-any.whl → 4.0.5__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.
@@ -0,0 +1,99 @@
1
+ import os
2
+ from urllib.parse import urlparse
3
+ import requests
4
+ import websocket
5
+ import datetime
6
+ import pytz
7
+ utc_tz = pytz.timezone('UTC')
8
+
9
+ from ..utils.IO import IO
10
+
11
+
12
+ class Message(object):
13
+
14
+ def __init__(self, id, token):
15
+ self.id = id
16
+ self.token = token
17
+
18
+
19
+ class MessageStreamReceiver(object):
20
+ """消息流读取函数结果"""
21
+
22
+ def __init__(self, id, db):
23
+ self.origin = os.environ.get('CLOUDPSS_API_URL',
24
+ 'https://cloudpss.net/')
25
+ self.id = id
26
+ self.db = db
27
+ self._status = 0
28
+ self.error = None
29
+ self.isOpen = False
30
+
31
+ def receive(self, id, fr0m, on_open, on_message, on_error, on_close):
32
+ """
33
+ 读取消息流中的数据
34
+ id: 消息流id
35
+ fr0m: 从哪个位置开始读取,如果为0则从头开始读取
36
+ on_open: 连接建立时的回调函数
37
+ on_message: 收到消息时的回调函数
38
+ on_error: 发生错误时的回调函数
39
+ on_close: 连接关闭时的回调函数
40
+ """
41
+ if id is None:
42
+ raise Exception('id is None')
43
+ u = list(urlparse(self.origin))
44
+ head = 'wss' if u[0] == 'https' else 'ws'
45
+
46
+ path = head + '://' + str(u[1]) + '/api/streams/id/' + id
47
+ if fr0m is not None:
48
+ path = path + '&from=' + str(fr0m)
49
+ ws = websocket.WebSocketApp(path,
50
+ on_open=on_open,
51
+ on_message=on_message,
52
+ on_error=on_error,
53
+ on_close=on_close)
54
+ ws.run_forever()
55
+ return ws
56
+
57
+ ###下面是兼容Receiver部分功能实现
58
+ def on_message(self, ws, message):
59
+ data = IO.deserialize(message, 'ubjson')
60
+ msg = IO.deserialize(data['data'], 'ubjson')
61
+ if "when" not in msg:
62
+ msg['when']= datetime.datetime.now()
63
+ self.db.storeMessage(msg)
64
+ if(msg['type']=='terminate'):
65
+ self.close(self.ws)
66
+
67
+ def on_error(self, ws, error):
68
+ msg = {
69
+ 'type': 'log',
70
+ 'verb': 'create',
71
+ 'version': 1,
72
+ 'data': {
73
+ 'level': 'error',
74
+ 'content': "websocket error",
75
+ },
76
+ }
77
+ self.db.storeMessage(msg)
78
+ self.error = error
79
+ self._status = -1
80
+
81
+
82
+ def on_close(self, ws,*args,**kwargs):
83
+ self.db.finished = datetime.datetime.now(tz=utc_tz).isoformat()
84
+ self._status = 1
85
+
86
+ def on_open(self, ws):
87
+ self.isOpen = True
88
+
89
+ def close(self, ws):
90
+ ws.close()
91
+
92
+ def status(self):
93
+ return self._status
94
+
95
+ def connect(self):
96
+ self._status = 0
97
+ self.ws = self.receive(self.id, None, self.on_open, self.on_message, self.on_error, self.on_close)
98
+
99
+
cloudpss/runner/runner.py CHANGED
@@ -3,20 +3,27 @@ import threading
3
3
  import json
4
4
  import time
5
5
  import random
6
+
7
+ from deprecated import deprecated
8
+
9
+ from cloudpss.utils.graphqlUtil import graphql_request
6
10
  from .receiver import Receiver
11
+ from .MessageStreamReceiver import MessageStreamReceiver
7
12
  from .result import IESLabSimulationResult, PowerFlowResult, EMTResult, Result, IESResult
8
13
  from .IESLabPlanResult import IESLabPlanResult
9
14
  from .IESLabEvaluationResult import IESLabEvaluationResult
10
15
  from .IESLabTypicalDayResult import IESLabTypicalDayResult
11
16
  from .storage import Storage
12
17
  from ..utils import request
13
- from typing import TypeVar, Generic
18
+ from typing import TypeVar, Generic
19
+ import re
14
20
 
15
21
  RECEIVER = {
16
- 'default': Receiver,
22
+ 'default': MessageStreamReceiver,
17
23
  }
18
24
  T = TypeVar('T', Result, EMTResult, PowerFlowResult, IESResult,
19
- IESLabSimulationResult, IESLabPlanResult, IESLabEvaluationResult,IESLabTypicalDayResult)
25
+ IESLabSimulationResult, IESLabPlanResult, IESLabEvaluationResult,
26
+ IESLabTypicalDayResult)
20
27
 
21
28
  IES_LAB_RESULT = {
22
29
  'function/ieslab/plan': IESLabPlanResult,
@@ -40,8 +47,9 @@ RESULT_DB = {
40
47
  }
41
48
 
42
49
  class Runner(Generic[T]):
43
- def __init__(self, taskId, name, job, config, revision, modelRid,
50
+ def __init__(self, id,taskId, name, job, config, revision, modelRid, policy,
44
51
  **kwargs):
52
+ self.id = id
45
53
  self.taskId = taskId
46
54
  self.db = Storage(taskId, name, job, config, revision, modelRid)
47
55
  rid =job['rid'].replace('job-definition/','function/').replace('/cloudpss/','/CloudPSS/')
@@ -87,10 +95,36 @@ class Runner(Generic[T]):
87
95
  结束当前运行的算例
88
96
 
89
97
  """
90
- r = request("DELETE", 'api/simulation/runner/' + str(self.taskId))
98
+ self.abort(0)
99
+ def abort(self,timeout=3):
100
+ """
101
+ 结束当前运行的算例
102
+
103
+ """
104
+ query = '''mutation ($input: AbortJobInput!) {
105
+ job: abortJob(input: $input) {
106
+ id
107
+ status
108
+ }
109
+ }
110
+ '''
111
+ variables = {
112
+ 'input': {
113
+ 'id': self.taskId,
114
+ 'timeout': timeout
115
+ }
116
+ }
117
+ graphql_request(query, variables)
118
+
91
119
 
92
120
  @staticmethod
93
- def create(revisionHash, job, config, name=None, rid='', **kwargs):
121
+ def create(revisionHash,
122
+ job,
123
+ config,
124
+ name=None,
125
+ rid='',
126
+ policy=None,
127
+ **kwargs):
94
128
  '''
95
129
  创建一个运行任务
96
130
 
@@ -104,35 +138,72 @@ class Runner(Generic[T]):
104
138
 
105
139
  >>> runner = Runner.runRevision(revision,job,config,'')
106
140
  '''
107
- taskId = str(int(time.time() * random.random()))
108
141
 
109
- runner = Runner(taskId, name, job, config, revisionHash, rid, **kwargs)
142
+ #处理policy字段
143
+ if policy is None:
144
+ policy = {}
145
+ if policy.get('tres', None) is None:
146
+ policy['tres'] = {}
147
+ policy['queue'] = job['args'].get('@queue', 1)
148
+ policy['priority'] = job['args'].get('@priority', 0)
149
+ tres = {'cpu': 1, 'ecpu': 0, 'mem': 0}
150
+ tresStr = job['args'].get('@tres', '')
151
+ for t in re.split('\s+', tresStr):
152
+ if t == '':
153
+ continue
154
+ k, v = t.split('=')
155
+ tres[k] = float(v) #type: ignore
156
+ policy['tres'] = tres
157
+
158
+ query = '''mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}'''
159
+ function = job['rid'].replace('job-definition/cloudpss/',
160
+ 'function/CloudPSS/')
161
+ variables = {
162
+ 'input': {
163
+ "args":
164
+ {
165
+ **job['args'],
166
+ '_ModelRevision' : revisionHash,
167
+ '_ModelArgs' : config['args']
168
+ },
169
+ "context": [
170
+ function,
171
+ f"model/@sdk/{str(int(time.time() * random.random()))}",
172
+ rid
173
+ ],
174
+ "policy":
175
+ policy,
176
+ }
177
+ }
178
+ r = graphql_request(query, variables)
179
+ if 'errors' in r:
180
+ raise Exception(r['errors'])
181
+ messageId = r['data']['job']['output']
182
+ id = r['data']['job']['id']
183
+ runner = Runner(id,messageId, name, job, config, revisionHash, rid,
184
+ policy, **kwargs)
185
+
110
186
  event = threading.Event()
111
187
  thread = threading.Thread(target=runner.__listen, kwargs=kwargs)
112
188
  thread.setDaemon(True)
113
189
  thread.start()
114
- payload = {
115
- 'args': config['args'],
116
- 'job': job,
117
- 'implement': kwargs.get('topology', None)
118
- }
190
+
119
191
  while not runner.__listenStatus():
120
192
  time.sleep(0.1)
121
- r = request('POST',
122
- 'api/simulation/runner/' + revisionHash + '/' +
123
- str(taskId),
124
- data=json.dumps(payload))
125
193
 
126
194
  return runner
127
195
 
196
+
128
197
 
129
198
  class HttpRunner(Runner[T]):
199
+
130
200
  def __init__(self, job, simulationId, **kwargs):
131
201
  self.simulationId = simulationId
132
202
  self.job = job
133
203
  self.__taskId = self.__getLastTask()
134
204
  result = IES_LAB_RESULT.get(job.get('rid', ''), IESLabPlanResult)
135
- self.result: T = result(self.simulationId, self.__taskId, **kwargs)
205
+ self.result: T = result(self.simulationId, self.__taskId,
206
+ **kwargs) # type: ignore
136
207
 
137
208
  def __getLastTask(self):
138
209
  r = request('GET',
cloudpss/utils/IO.py ADDED
@@ -0,0 +1,164 @@
1
+ import io
2
+ import json
3
+ import ubjson
4
+ import yaml
5
+ import gzip
6
+ import base64
7
+ import struct
8
+ import zstandard as zstd
9
+
10
+
11
+ def float32Array(_loader, node):
12
+ data = base64.b64decode(node.value)
13
+ return list(struct.unpack('f' * (len(data) // 4), data))
14
+
15
+
16
+ def float64Array(_loader, node):
17
+ data = base64.b64decode(node.value)
18
+ return list(struct.unpack('d' * (len(data) // 8), data))
19
+
20
+
21
+ def uint8Array(_loader, node):
22
+ data = base64.b64decode(node.value)
23
+ return list(struct.unpack('B' * (len(data) // 1), data))
24
+
25
+
26
+ def uint8ClampedArray(_loader, node):
27
+ data = base64.b64decode(node.value)
28
+ return list(struct.unpack('B' * (len(data) // 1), data))
29
+
30
+
31
+ def uint16Array(_loader, node):
32
+ data = base64.b64decode(node.value)
33
+ return list(struct.unpack('H' * (len(data) // 2), data))
34
+
35
+
36
+ def uint32Array(_loader, node):
37
+ data = base64.b64decode(node.value)
38
+ return list(struct.unpack('I' * (len(data) // 4), data))
39
+
40
+
41
+ def int8Array(_loader, node):
42
+ data = base64.b64decode(node.value)
43
+ return list(struct.unpack('b' * (len(data) // 1), data))
44
+
45
+
46
+ def int16Array(_loader, node):
47
+ data = base64.b64decode(node.value)
48
+ return list(struct.unpack('h' * (len(data) // 2), data))
49
+
50
+
51
+ def int32Array(_loader, node):
52
+ data = base64.b64decode(node.value)
53
+ return list(struct.unpack('i' * (len(data) // 4), data))
54
+
55
+
56
+ #type:ignore
57
+ yaml.add_constructor('tag:yaml.org,2002:js/Float32Array', float32Array)
58
+ yaml.add_constructor('tag:yaml.org,2002:js/Float64Array', float64Array)
59
+ yaml.add_constructor('tag:yaml.org,2002:js/Uint8Array', uint8Array)
60
+ yaml.add_constructor('tag:yaml.org,2002:js/Uint8ClampedArray',
61
+ uint8ClampedArray)
62
+ yaml.add_constructor('tag:yaml.org,2002:js/Uint16Array', uint16Array)
63
+ yaml.add_constructor('tag:yaml.org,2002:js/Uint32Array', uint32Array)
64
+ yaml.add_constructor('tag:yaml.org,2002:js/Int8Array', int8Array)
65
+ yaml.add_constructor('tag:yaml.org,2002:js/Int16Array', int16Array)
66
+ yaml.add_constructor('tag:yaml.org,2002:js/Int32Array', int32Array)
67
+
68
+
69
+ class IO(object):
70
+ """
71
+ IO 模块,抽象 bytes/file <-> object 的 load/dump 操作,支持 gzip 压缩和 yaml、ubjson 序列化 读取时依据 magic number 自动识别压缩格式,写入时默认使用 gzip
72
+ """
73
+
74
+ @staticmethod
75
+ def serialize(obj, format, compress='gzip') -> bytes:
76
+ """
77
+ 根据format序列化模型
78
+ format 支持 json, ubjson, yaml, zstd
79
+ compress 支持 gzip
80
+ """
81
+ result = None
82
+ if format == 'json':
83
+ result = json.dumps(obj).encode(encoding="utf-8")
84
+ if format == 'ubjson':
85
+ result = ubjson.dumpb(obj)
86
+ if format == 'yaml':
87
+ result = yaml.dump(obj).encode(encoding="utf-8")
88
+ if result is None:
89
+ assert False, 'format not support'
90
+ if compress == 'gzip':
91
+ return gzip.compress(result)
92
+ if compress == 'zstd':
93
+ return zstd.ZstdCompressor().compress(result)
94
+ return result
95
+
96
+ @staticmethod
97
+ def deserialize(byt, format):
98
+ """
99
+ 根据format反序列化模型
100
+ format 支持 json, ubjson, yaml, zstd
101
+ """
102
+ if format == 'json':
103
+ return json.loads(byt)
104
+ if format == 'ubjson':
105
+ return ubjson.loadb(byt)
106
+ if format == 'yaml':
107
+ return yaml.load(io.BytesIO(byt), yaml.FullLoader)
108
+ assert False, 'format not support'
109
+
110
+ @staticmethod
111
+ def load(file, format):
112
+ """
113
+ 根据format从文件中加载模型
114
+ format 支持 json, ubjson, yaml
115
+ """
116
+ ### 读取文件
117
+ f = open(file, 'r+', encoding='utf-8')
118
+ t = f.buffer.read(4)
119
+ f.close()
120
+ ### 判断文件格式是否是gzip或其他格式
121
+ if t[0:2] == b'\x1f\x8b':
122
+ with gzip.open(file, 'rb') as input_file:
123
+ return IO.deserialize(input_file.read(), format) # type:ignore
124
+ if t == b'\x28\xb5\x2f\xfd':
125
+ with open(file, 'rb') as input_file:
126
+ return IO.deserialize(
127
+ zstd.ZstdDecompressor().decompress(input_file.read()),
128
+ format)
129
+ else:
130
+ with open(file, 'rb') as f:
131
+ data = f.read()
132
+ f.close()
133
+ return IO.deserialize(data, format)
134
+
135
+ @staticmethod
136
+ def dump(obj, file, format, compress='gzip'):
137
+ """
138
+ 根据format将模型保存到文件中
139
+ format 支持 json, ubjson, yaml, zstd
140
+ compress 支持 gzip
141
+ """
142
+ ### 序列化
143
+ data = IO.serialize(obj, format, compress)
144
+ ### 写入文件
145
+ with open(file, 'wb') as f:
146
+ f.write(data)
147
+ f.close()
148
+
149
+
150
+ if __name__ == '__main__':
151
+ obj = [
152
+ 123, 1.25, 43121609.5543, 12345.44e40, 'a', 'here is a string', None,
153
+ True, False, [[1, 2], 3, [4, 5, 6], 7], {
154
+ 'a dict': 456
155
+ }
156
+ ]
157
+ IO.dump(obj, 'output.json.gz', 'json')
158
+ IO.dump(obj, 'output.ubjson.gz', 'ubjson')
159
+ IO.dump(obj, 'output.yaml.gz', 'yaml') # type: ignore
160
+ IO.dump(obj, 'output.yaml.zstd', 'yaml', 'zstd') # type: ignore
161
+ print(IO.load('output.json.gz', 'json'))
162
+ print(IO.load('output.ubjson.gz', 'ubjson'))
163
+ print(IO.load('output.yaml.gz', 'yaml'))
164
+ print(IO.load('output.yaml.zstd', 'yaml'))
cloudpss/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '4.0.3'
1
+ __version__ = '4.0.5'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudpss
3
- Version: 4.0.3
3
+ Version: 4.0.5
4
4
  Summary: cloudpss sdk
5
5
  Home-page: https://www.cloudpss.net
6
6
  Author: cloudpss
@@ -21,6 +21,8 @@ Requires-Dist: requests
21
21
  Requires-Dist: websocket-client
22
22
  Requires-Dist: pytz
23
23
  Requires-Dist: deprecated
24
+ Requires-Dist: zstandard
25
+ Requires-Dist: py-ubjson
24
26
 
25
27
 
26
28
  CloudPSS SDK
@@ -1,6 +1,6 @@
1
1
  cloudpss/__init__.py,sha256=Ov8K45KxSsPalPErvTRUb2GvPdJ3myucFqx7s37_YZo,777
2
2
  cloudpss/verify.py,sha256=KF4Gd59DGvCyIEkRD7rNnekWw22XxJpi3DW6keb6j4c,1498
3
- cloudpss/version.py,sha256=WVDh-CWReADU6VLpUNeW8EQnxCJUNqQrdVIoGVLRXxQ,21
3
+ cloudpss/version.py,sha256=F9_5WzXCbDxelG0Xz9hBfGhy0BP1_F8FDyJ64EnDdCM,21
4
4
  cloudpss/function/__init__.py,sha256=TNzChB-gQF6oB62F423evpUlgcp6s03D4pKKs89Lz4Q,1629
5
5
  cloudpss/function/function.py,sha256=llomkfnTmKMiFJYJ2mKnmAEoIjTNVCnjCUUyiJMOV1s,29
6
6
  cloudpss/function/functionExecution.py,sha256=GcyhRlgYjRnJrreKOtERExbCp6XDedUlT0L7k-uqyZM,14640
@@ -25,19 +25,21 @@ cloudpss/project/project.py,sha256=sGvJEd9yEB5NARRa64gwF96hK69gQSmwX8lQANLhBos,1
25
25
  cloudpss/runner/IESLabEvaluationResult.py,sha256=uFNLiN5kzlzSGlLIq3ybuRwB-ufYytflVrXV5g7voOU,5841
26
26
  cloudpss/runner/IESLabPlanResult.py,sha256=dCyTbMtITy9XDjE42knrpJrvaH7dvFgfQMZbx9hybRs,6862
27
27
  cloudpss/runner/IESLabTypicalDayResult.py,sha256=3egAzmv32sr4wKaVgLxsM75ScSb08F4-iLEbuPkoi_c,8001
28
+ cloudpss/runner/MessageStreamReceiver.py,sha256=_G_7LIFdm7EtOf046nT-V3HNmygAm2oo5WYl4m27jKY,2832
28
29
  cloudpss/runner/__init__.py,sha256=aZ00V2AzQNBbER0xi6pqFFyiLFM-6r1fxvzdxxUJA_4,241
29
30
  cloudpss/runner/receiver.py,sha256=d8vOtBJ_Iqo3syJXgFFxwii1MXF7CyHRoXy6eT81Zq4,4096
30
31
  cloudpss/runner/result.py,sha256=MkoTQly7FjKj9mde3bnv4vBDfGJ2U4eK-HhxxdwmemE,13125
31
- cloudpss/runner/runner.py,sha256=NbBJfCVFk9n3eYsQSjTaK12zohwqKYak-lEEOo8vWDo,5316
32
+ cloudpss/runner/runner.py,sha256=207PVoD3mjPiqWy6Qt3L5EU0woO7jmv_xj_bRuE9tDU,7299
32
33
  cloudpss/runner/storage.py,sha256=zFET_zwPIOF2Cnh9sgFiS0HFxV1OmVsU34bGUQ6PpkA,4162
33
34
  cloudpss/runner/transform.py,sha256=krOgTZiJSJAb5QSwerAqlbC4Ma0PKi__0WOZlAxw4O8,11613
35
+ cloudpss/utils/IO.py,sha256=Uh1NOlBn15Jl5_aWS2QRO2-QsKlFT9o8DPtP8-8Z2PA,5314
34
36
  cloudpss/utils/__init__.py,sha256=NU5ZAeXH733nJKooH_1cdT9ntPEYRG4Kk3PA7P6bK_s,291
35
37
  cloudpss/utils/dataEncoder.py,sha256=5PUPb844eOGgFnYrMM8bdjdKH_MZz0lk-67uo8TvwEo,885
36
38
  cloudpss/utils/graphqlUtil.py,sha256=swl6XT1UmUQHdHjMWw3M0i8meEmVKNQvX0SHsbgg8TU,255
37
39
  cloudpss/utils/httprequests.py,sha256=-RYi1Dc4QDqqupuw0x-lq74dFvCqPrZfCJKgrdolEpk,1643
38
40
  cloudpss/utils/matlab.py,sha256=SLwVt790BjklJK2XNELt9R2n_1ej9Y8QsTIdFkKXLWE,795
39
41
  cloudpss/utils/yamlLoader.py,sha256=KRlRkHFltOjqxa_sesdBLf1W5J7XTgvubszsSw-XR0U,2885
40
- cloudpss-4.0.3.dist-info/METADATA,sha256=uXlgX7FBN1vtept_TPaoufb-pEoAGMZskcgbHObajwM,2318
41
- cloudpss-4.0.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
42
- cloudpss-4.0.3.dist-info/top_level.txt,sha256=wS9qPU4-aWM9ouzMOx34Nlq-GkdQKpr9vBskwut1BD8,9
43
- cloudpss-4.0.3.dist-info/RECORD,,
42
+ cloudpss-4.0.5.dist-info/METADATA,sha256=iDbbOA3p31OHB5tsRdsAMTDpX03a_nQVwW8Fin3-07E,2368
43
+ cloudpss-4.0.5.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
44
+ cloudpss-4.0.5.dist-info/top_level.txt,sha256=wS9qPU4-aWM9ouzMOx34Nlq-GkdQKpr9vBskwut1BD8,9
45
+ cloudpss-4.0.5.dist-info/RECORD,,