cloudpss 4.0.2a1__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.
@@ -1,3 +1,4 @@
1
+ from cloudpss.utils.httpAsyncRequest import graphql_fetch
1
2
  from .topology import ModelTopology
2
3
  from .implements import ModelImplement
3
4
  from ..utils import request, graphql_request
@@ -21,6 +22,7 @@ class ModelRevision(object):
21
22
 
22
23
 
23
24
  """
25
+
24
26
  def __init__(self, revision: dict = {}):
25
27
  """
26
28
  初始化
@@ -54,7 +56,7 @@ class ModelRevision(object):
54
56
 
55
57
  return self.implements
56
58
 
57
- def run(self, job, config, name=None, rid='', **kwargs):
59
+ async def run(self, job, config, name=None, rid='', policy=None, **kwargs):
58
60
  """
59
61
  运行某个指定版本的项目
60
62
 
@@ -63,16 +65,14 @@ class ModelRevision(object):
63
65
  :params name: 任务名称,为空时使用项目的参数方案名称和计算方案名称
64
66
  :params rid: 项目rid,可为空
65
67
 
66
- :return: 返回一个运行实例
68
+ :return: 返回一个ModelRevision
67
69
 
68
70
  >>> revision.run(revision,job,config,'')
69
71
  """
70
- revision = ModelRevision.create(self)
71
- return Runner.create(revision['hash'], job, config, name, rid,
72
- **kwargs)
72
+ return await ModelRevision.create(self)
73
73
 
74
74
  @staticmethod
75
- def create(revision, parentHash=None):
75
+ async def create(revision, parentHash=None):
76
76
  """
77
77
  创建一个新版本
78
78
 
@@ -93,12 +93,12 @@ class ModelRevision(object):
93
93
  del r['hash']
94
94
  variables = {'a': {**r, 'parent': parentHash}}
95
95
 
96
- r = graphql_request(query, variables)
96
+ r = await graphql_fetch(query, variables)
97
97
  if 'errors' in r:
98
98
  raise Exception(r['errors'])
99
99
  return r['data']['createModelRevision']
100
100
 
101
- def fetchTopology(self, implementType, config, maximumDepth):
101
+ async def fetchTopology(self, implementType, config, maximumDepth):
102
102
  """
103
103
  获取当前项目版本的拓扑数据
104
104
 
@@ -115,6 +115,6 @@ class ModelRevision(object):
115
115
  """
116
116
 
117
117
  if self.hash is not None:
118
- return ModelTopology.fetch(self.hash, implementType, config,
118
+ return await ModelTopology.fetch(self.hash, implementType, config,
119
119
  maximumDepth)
120
120
  return None
@@ -1,4 +1,6 @@
1
1
  import json
2
+
3
+ from cloudpss.utils.httpAsyncRequest import graphql_fetch
2
4
  from ..utils import request, graphql_request
3
5
 
4
6
 
@@ -44,7 +46,7 @@ class ModelTopology():
44
46
  f.close()
45
47
 
46
48
  @staticmethod
47
- def fetch(hash, implementType, config, maximumDepth=None):
49
+ async def fetch(hash, implementType, config, maximumDepth=None):
48
50
  """
49
51
  获取拓扑
50
52
 
@@ -75,7 +77,7 @@ class ModelTopology():
75
77
  'maximumDepth': maximumDepth
76
78
  }
77
79
  }
78
- data = graphql_request(query, variables)
80
+ data = await graphql_fetch(query, variables)
79
81
  if 'errors' in data:
80
82
  raise Exception(data['errors'][0]['message'])
81
83
 
@@ -1,8 +1,10 @@
1
-
2
1
  from .receiver import Receiver
3
2
  from .result import PowerFlowResult, EMTResult, Result
4
3
  from .storage import Storage
5
4
  from .runner import Runner
5
+ from .MessageStreamReceiver import MessageStreamReceiver, Message
6
6
 
7
- __all__ = ['Runner', 'Result', 'PowerFlowResult',
8
- 'EMTResult', 'Receiver', 'Storage']
7
+ __all__ = [
8
+ 'Runner', 'Result', 'PowerFlowResult', 'EMTResult', 'Receiver', 'Storage',
9
+ 'MessageStreamReceiver', 'Message'
10
+ ]
@@ -8,6 +8,7 @@ from .transform import Transformer
8
8
  import datetime
9
9
  import pytz
10
10
  import ssl
11
+ import time
11
12
 
12
13
  utc_tz = pytz.timezone('UTC')
13
14
 
@@ -62,6 +63,7 @@ class Receiver(object):
62
63
  return
63
64
  try:
64
65
  payload = json.loads(message)
66
+ payload['when'] = datetime.datetime.now()
65
67
  msg = payload
66
68
  try:
67
69
  if ('version' in payload and payload['version'] == 1):
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,
@@ -39,9 +46,12 @@ RESULT_DB = {
39
46
  'function/CloudPSS/ieslab-optimization': IESResult,
40
47
  }
41
48
 
49
+ @deprecated(version='4.0', reason="该类将在 6.0 版本移除,请使用 Job 类代替")
42
50
  class Runner(Generic[T]):
43
- def __init__(self, taskId, name, job, config, revision, modelRid,
51
+
52
+ def __init__(self, id,taskId, name, job, config, revision, modelRid, policy,
44
53
  **kwargs):
54
+ self.id = id
45
55
  self.taskId = taskId
46
56
  self.db = Storage(taskId, name, job, config, revision, modelRid)
47
57
  rid =job['rid'].replace('job-definition/','function/').replace('/cloudpss/','/CloudPSS/')
@@ -87,10 +97,37 @@ class Runner(Generic[T]):
87
97
  结束当前运行的算例
88
98
 
89
99
  """
90
- r = request("DELETE", 'api/simulation/runner/' + str(self.taskId))
100
+ self.abort(0)
101
+
102
+ def abort(self,timeout=3):
103
+ """
104
+ 结束当前运行的算例
105
+
106
+ """
107
+ query = '''mutation ($input: AbortJobInput!) {
108
+ job: abortJob(input: $input) {
109
+ id
110
+ status
111
+ }
112
+ }
113
+ '''
114
+ variables = {
115
+ 'input': {
116
+ 'id': self.taskId,
117
+ 'timeout': timeout
118
+ }
119
+ }
120
+ graphql_request(query, variables)
121
+
91
122
 
92
123
  @staticmethod
93
- def create(revisionHash, job, config, name=None, rid='', **kwargs):
124
+ def create(revisionHash,
125
+ job,
126
+ config,
127
+ name=None,
128
+ rid='',
129
+ policy=None,
130
+ **kwargs):
94
131
  '''
95
132
  创建一个运行任务
96
133
 
@@ -104,35 +141,71 @@ class Runner(Generic[T]):
104
141
 
105
142
  >>> runner = Runner.runRevision(revision,job,config,'')
106
143
  '''
107
- taskId = str(int(time.time() * random.random()))
108
144
 
109
- runner = Runner(taskId, name, job, config, revisionHash, rid, **kwargs)
145
+ #处理policy字段
146
+ if policy is None:
147
+ policy = {}
148
+ if policy.get('tres', None) is None:
149
+ policy['tres'] = {}
150
+ policy['queue'] = job['args'].get('@queue', 1)
151
+ policy['priority'] = job['args'].get('@priority', 0)
152
+ tres = {'cpu': 1, 'ecpu': 0, 'mem': 0}
153
+ tresStr = job['args'].get('@tres', '')
154
+ for t in re.split('\s+', tresStr):
155
+ if t == '':
156
+ continue
157
+ k, v = t.split('=')
158
+ tres[k] = float(v) #type: ignore
159
+ policy['tres'] = tres
160
+
161
+ query = '''mutation($input:CreateJobInput!){job:createJob(input:$input){id input output status position}}'''
162
+ function = job['rid'].replace('job-definition/cloudpss/',
163
+ 'function/CloudPSS/')
164
+ variables = {
165
+ 'input': {
166
+ "args":
167
+ {
168
+ **job['args'],
169
+ '_ModelRevision' : revisionHash,
170
+ '_ModelArgs' : config['args']
171
+ },
172
+ "context": [
173
+ function,
174
+ f"model/@sdk/{str(int(time.time() * random.random()))}"
175
+ ],
176
+ "policy":
177
+ policy,
178
+ }
179
+ }
180
+ r = graphql_request(query, variables)
181
+ if 'errors' in r:
182
+ raise Exception(r['errors'])
183
+ messageId = r['data']['job']['output']
184
+ id = r['data']['job']['id']
185
+ runner = Runner(id,messageId, name, job, config, revisionHash, rid,
186
+ policy, **kwargs)
187
+
110
188
  event = threading.Event()
111
189
  thread = threading.Thread(target=runner.__listen, kwargs=kwargs)
112
190
  thread.setDaemon(True)
113
191
  thread.start()
114
- payload = {
115
- 'args': config['args'],
116
- 'job': job,
117
- 'implement': kwargs.get('topology', None)
118
- }
192
+
119
193
  while not runner.__listenStatus():
120
194
  time.sleep(0.1)
121
- r = request('POST',
122
- 'api/simulation/runner/' + revisionHash + '/' +
123
- str(taskId),
124
- data=json.dumps(payload))
125
195
 
126
196
  return runner
127
197
 
198
+
128
199
 
129
200
  class HttpRunner(Runner[T]):
201
+
130
202
  def __init__(self, job, simulationId, **kwargs):
131
203
  self.simulationId = simulationId
132
204
  self.job = job
133
205
  self.__taskId = self.__getLastTask()
134
206
  result = IES_LAB_RESULT.get(job.get('rid', ''), IESLabPlanResult)
135
- self.result: T = result(self.simulationId, self.__taskId, **kwargs)
207
+ self.result: T = result(self.simulationId, self.__taskId,
208
+ **kwargs) # type: ignore
136
209
 
137
210
  def __getLastTask(self):
138
211
  r = request('GET',
@@ -0,0 +1,27 @@
1
+ import asyncio
2
+
3
+
4
+ class CustomAsyncIterable:
5
+ async def __init__(self, async_func, *args):
6
+ self.async_func = async_func
7
+ self.queue = asyncio.Queue()
8
+ self.index = 0
9
+ self.args = args
10
+
11
+ async def __aiter__(self):
12
+ return self
13
+
14
+ async def __anext__(self):
15
+ try:
16
+ result = await self.queue.get()
17
+ if result is None:
18
+ raise StopAsyncIteration
19
+ return result
20
+ except asyncio.QueueEmpty:
21
+ tasks = []
22
+ for arg in self.args:
23
+ tasks.append(asyncio.create_task(self.async_func(arg)))
24
+ await asyncio.gather(*tasks)
25
+ for task in tasks:
26
+ await self.queue.put(await task)
27
+ return await self.__anext__()
@@ -3,5 +3,9 @@ from .httprequests import request
3
3
  from .yamlLoader import fileLoad
4
4
  from .dataEncoder import MatlabDataEncoder, DateTimeEncode
5
5
  from .graphqlUtil import graphql_request
6
+ from .IO import IO
6
7
 
7
- __all__ = ['request', 'fileLoad', 'MatlabDataEncoder', 'DateTimeEncode', 'graphql_request']
8
+ __all__ = [
9
+ 'request', 'fileLoad', 'MatlabDataEncoder', 'DateTimeEncode',
10
+ 'graphql_request', 'IO'
11
+ ]
@@ -0,0 +1,88 @@
1
+ import json
2
+ import os
3
+ from aiohttp import ClientSession, WSMsgType
4
+ from urllib.parse import urljoin
5
+ import logging
6
+ from ..version import __version__
7
+
8
+
9
+ def graphql_version_check(uri, response):
10
+ if uri.startswith("graphql"):
11
+ if "X-Cloudpss-Version" not in response.headers:
12
+ raise Exception("当前SDK版本(ver 3.X.X)与服务器版本(3.0.0 以下)不兼容,请更换服务器地址或更换SDK版本。")
13
+ os.environ["X_CLOUDPSS_VERSION"] = response.headers["X-Cloudpss-Version"]
14
+ if float(response.headers["X-Cloudpss-Version"]) >= 5:
15
+ raise Exception(
16
+ "当前SDK版本(ver "
17
+ + __version__
18
+ + ")与服务器版本(ver "
19
+ + response.headers["X-Cloudpss-Version"]
20
+ + ".X.X)不兼容,请更换服务器地址或更换SDK版本(pip 使用 pip install -U cloudpss 命令更新, conda 使用 conda update cloudpss 命令更新)。"
21
+ )
22
+
23
+
24
+ ### 通过aiohttp实现请求
25
+ async def fetch_data(method: str, uri, data, baseUrl=None, params={}, **kwargs):
26
+ if baseUrl == None:
27
+ baseUrl = os.environ.get("CLOUDPSS_API_URL", "https://cloudpss.net/")
28
+ url = urljoin(baseUrl, uri)
29
+ token = os.environ.get("CLOUDPSS_TOKEN", None)
30
+ if token:
31
+ headers = {
32
+ "Authorization": "Bearer " + token,
33
+ "Content-Type": "application/json; charset=utf-8",
34
+ }
35
+ else:
36
+ raise Exception("token undefined")
37
+ logging.debug("fetch start:")
38
+ async with ClientSession() as session:
39
+ async with session.request(
40
+ method, url, data=data, params=params, headers=headers
41
+ ) as response:
42
+ if response.status == 200:
43
+ data = await response.json()
44
+ logging.debug("data:")
45
+ logging.debug(data)
46
+ logging.debug("params:")
47
+ logging.debug(params)
48
+ graphql_version_check(uri, response)
49
+ # if "statusCode" in r.text:
50
+ # t = json.loads(r.text)
51
+ # raise Exception(str(t['statusCode']) + " "+t['message'])
52
+ return data
53
+ elif 400 <= response.status < 500:
54
+ raise Exception(f"请求失败,状态码:{response.status}")
55
+ elif 500 <= response.status < 600:
56
+ raise Exception(f"请求失败,状态码:{response.status}")
57
+ else:
58
+ return
59
+
60
+
61
+ # graphql实现方法
62
+ async def graphql_fetch(query, variables=None):
63
+ payload = {"query": query, "variables": variables}
64
+ return await fetch_data("POST", "graphql", data=json.dumps(payload))
65
+
66
+
67
+ # websocket
68
+ async def websocket_connect(url, open_func, receive_func, closed_func, error_func):
69
+ async with ClientSession() as session:
70
+ async with session.ws_connect(url) as ws:
71
+ # ws.register_callback("connecting", lambda: logging.debug("连接正在建立..."))
72
+ # ws.register_callback("connected", lambda: open_func())
73
+ # ws.register_callback("closed", lambda: closed_func())
74
+ # ws.register_callback("error", lambda: error_func())
75
+ open_func()
76
+ async for msg in ws:
77
+ if msg.type == WSMsgType.BINARY:
78
+ receive_func(msg.data)
79
+ if msg.type == WSMsgType.TEXT:
80
+ receive_func(msg.data)
81
+ elif msg.type == WSMsgType.CLOSED:
82
+ logging.debug("WebSocket连接已关闭")
83
+ closed_func()
84
+ break
85
+ elif msg.type == WSMsgType.ERROR:
86
+ logging.debug(f"WebSocket连接发生错误:{msg.data}")
87
+ error_func(msg.data)
88
+ break
@@ -5,6 +5,9 @@ import requests
5
5
  import os
6
6
  from collections import OrderedDict
7
7
  from ..version import __version__
8
+ import logging
9
+
10
+
8
11
  def request(method, uri, baseUrl=None, params={}, token=None, **kwargs):
9
12
  if baseUrl == None:
10
13
  baseUrl = os.environ.get('CLOUDPSS_API_URL', 'https://cloudpss.net/')
@@ -17,6 +20,7 @@ def request(method, uri, baseUrl=None, params={}, token=None, **kwargs):
17
20
  }
18
21
  else:
19
22
  raise Exception('token undefined')
23
+ logging.debug(kwargs['data'])
20
24
  r = requests.request(method, url, params=params, headers=headers, **kwargs)
21
25
 
22
26
  if (uri.startswith('graphql')):
@@ -31,9 +35,10 @@ def request(method, uri, baseUrl=None, params={}, token=None, **kwargs):
31
35
 
32
36
  if r.ok:
33
37
  return r
38
+ logging.debug(r.text)
34
39
  if r.text =="":
35
40
  r.raise_for_status()
36
41
  if "statusCode" in r.text:
37
42
  t = json.loads(r.text)
38
- raise Exception( str(t['statusCode']) + " "+t['message'])
43
+ raise Exception(str(t['statusCode']) + " "+t['message'])
39
44
 
@@ -5,63 +5,62 @@ import struct
5
5
  import base64
6
6
 
7
7
 
8
- class JavascriptSchema():
9
- def float32Array(self, node):
10
- data = base64.b64decode(node.value)
11
- return list(struct.unpack('f' * (len(data) // 4), data))
12
8
 
13
- def float64Array(self, node):
14
- data = base64.b64decode(node.value)
15
- return list(struct.unpack('d' * (len(data) // 8), data))
9
+ def float32Array(_loader, node):
10
+ data = base64.b64decode(node.value)
11
+ return list(struct.unpack('f' * (len(data) // 4), data))
16
12
 
17
- def uint8Array(self, node):
18
- data = base64.b64decode(node.value)
19
- return list(struct.unpack('B' * (len(data) // 1), data))
13
+ def float64Array(_loader, node):
14
+ data = base64.b64decode(node.value)
15
+ return list(struct.unpack('d' * (len(data) // 8), data))
20
16
 
21
- def uint8ClampedArray(self, node):
22
- data = base64.b64decode(node.value)
23
- return list(struct.unpack('B' * (len(data) // 1), data))
17
+ def uint8Array(_loader, node):
18
+ data = base64.b64decode(node.value)
19
+ return list(struct.unpack('B' * (len(data) // 1), data))
24
20
 
25
- def uint16Array(self, node):
26
- data = base64.b64decode(node.value)
27
- return list(struct.unpack('H' * (len(data) // 2), data))
21
+ def uint8ClampedArray(_loader, node):
22
+ data = base64.b64decode(node.value)
23
+ return list(struct.unpack('B' * (len(data) // 1), data))
28
24
 
29
- def uint32Array(self, node):
30
- data = base64.b64decode(node.value)
31
- return list(struct.unpack('I' * (len(data) // 4), data))
25
+ def uint16Array(_loader, node):
26
+ data = base64.b64decode(node.value)
27
+ return list(struct.unpack('H' * (len(data) // 2), data))
32
28
 
33
- def int8Array(self, node):
34
- data = base64.b64decode(node.value)
35
- return list(struct.unpack('b' * (len(data) // 1), data))
29
+ def uint32Array(_loader, node):
30
+ data = base64.b64decode(node.value)
31
+ return list(struct.unpack('I' * (len(data) // 4), data))
36
32
 
37
- def int16Array(self, node):
38
- data = base64.b64decode(node.value)
39
- return list(struct.unpack('h' * (len(data) // 2), data))
33
+ def int8Array(_loader, node):
34
+ data = base64.b64decode(node.value)
35
+ return list(struct.unpack('b' * (len(data) // 1), data))
40
36
 
41
- def int32Array(self, node):
42
-
43
- data = base64.b64decode(node.value)
44
- return list(struct.unpack('i' * (len(data) // 4), data)).toList()
37
+ def int16Array(_loader, node):
38
+ data = base64.b64decode(node.value)
39
+ return list(struct.unpack('h' * (len(data) // 2), data))
45
40
 
41
+ def int32Array(_loader, node):
42
+ data = base64.b64decode(node.value)
43
+ return list(struct.unpack('i' * (len(data) // 4), data))
46
44
 
45
+ #type:ignore
47
46
  yaml.add_constructor('tag:yaml.org,2002:js/Float32Array',
48
- JavascriptSchema.float32Array)
47
+ float32Array)
49
48
  yaml.add_constructor('tag:yaml.org,2002:js/Float64Array',
50
- JavascriptSchema.float64Array)
49
+ float64Array)
51
50
  yaml.add_constructor('tag:yaml.org,2002:js/Uint8Array',
52
- JavascriptSchema.uint8Array)
51
+ uint8Array)
53
52
  yaml.add_constructor('tag:yaml.org,2002:js/Uint8ClampedArray',
54
- JavascriptSchema.uint8ClampedArray)
53
+ uint8ClampedArray)
55
54
  yaml.add_constructor('tag:yaml.org,2002:js/Uint16Array',
56
- JavascriptSchema.uint16Array)
55
+ uint16Array)
57
56
  yaml.add_constructor('tag:yaml.org,2002:js/Uint32Array',
58
- JavascriptSchema.uint32Array)
57
+ uint32Array)
59
58
  yaml.add_constructor('tag:yaml.org,2002:js/Int8Array',
60
- JavascriptSchema.int8Array)
59
+ int8Array)
61
60
  yaml.add_constructor('tag:yaml.org,2002:js/Int16Array',
62
- JavascriptSchema.int16Array)
61
+ int16Array)
63
62
  yaml.add_constructor('tag:yaml.org,2002:js/Int32Array',
64
- JavascriptSchema.int32Array)
63
+ int32Array)
65
64
 
66
65
 
67
66
  def fileLoad(fileName):
@@ -71,11 +70,11 @@ def fileLoad(fileName):
71
70
  data = None
72
71
  if t == b'\x1f\x8b':
73
72
  with gzip.open(fileName, 'rb') as input_file:
74
- with io.TextIOWrapper(input_file, encoding='utf-8') as dec:
73
+ with io.TextIOWrapper(input_file, encoding='utf-8') as dec: # type: ignore
75
74
  r = dec.read()
76
- data = yaml.load(r, Loader=yaml.FullLoader)
75
+ data = yaml.load(r, _loader=yaml.Full_loader) # type: ignore
77
76
  else:
78
77
  f = open(fileName, 'r+', encoding='utf-8')
79
- data = yaml.load(f, Loader=yaml.FullLoader)
78
+ data = yaml.load(f, _loader=yaml.Full_loader) # type: ignore
80
79
  f.close()
81
80
  return data
cloudpss/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '4.0.2-alpha.1'
1
+ __version__ = '4.1.1-alpha.1'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudpss
3
- Version: 4.0.2a1
3
+ Version: 4.1.1a1
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: py-ubjson
25
+ Requires-Dist: aiohttp
24
26
 
25
27
 
26
28
  CloudPSS SDK