oocana 0.16.9__tar.gz → 0.16.11__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.
- {oocana-0.16.9 → oocana-0.16.11}/PKG-INFO +1 -1
- {oocana-0.16.9 → oocana-0.16.11}/oocana/context.py +169 -73
- {oocana-0.16.9 → oocana-0.16.11}/oocana/handle_data.py +7 -1
- {oocana-0.16.9 → oocana-0.16.11}/pyproject.toml +1 -1
- {oocana-0.16.9 → oocana-0.16.11}/oocana/__init__.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/data.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/extra.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/mainframe.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/preview.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/schema.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/service.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/oocana/throtter.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/__init__.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_data.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_handle_data.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_json.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_mainframe.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_performance.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_schema.py +0 -0
- {oocana-0.16.9 → oocana-0.16.11}/tests/test_throtter.py +0 -0
@@ -11,8 +11,33 @@ from .preview import PreviewPayload, TablePreviewData, DataFrame, ShapeDataFrame
|
|
11
11
|
from .data import EXECUTOR_NAME
|
12
12
|
import os.path
|
13
13
|
import logging
|
14
|
+
import copy
|
14
15
|
|
15
|
-
__all__ = ["Context"]
|
16
|
+
__all__ = ["Context", "HandleDefDict"]
|
17
|
+
|
18
|
+
class HandleDefDict(TypedDict):
|
19
|
+
"""a dict that represents the handle definition, used in the block schema output and input defs.
|
20
|
+
"""
|
21
|
+
|
22
|
+
handle: str
|
23
|
+
"""the handle of the output, should be defined in the block schema output defs, the field name is handle
|
24
|
+
"""
|
25
|
+
|
26
|
+
description: str | None
|
27
|
+
"""the description of the output, should be defined in the block schema output defs, the field name is description
|
28
|
+
"""
|
29
|
+
|
30
|
+
json_schema: Dict[str, Any] | None
|
31
|
+
"""the schema of the output, should be defined in the block schema output defs, the field name is json_schema
|
32
|
+
"""
|
33
|
+
|
34
|
+
kind: str | None
|
35
|
+
"""the kind of the output, should be defined in the block schema output defs, the field name is kind
|
36
|
+
"""
|
37
|
+
|
38
|
+
nullable: bool
|
39
|
+
"""if the output can be None, should be defined in the block schema output defs, the field name is nullable
|
40
|
+
"""
|
16
41
|
|
17
42
|
class OnlyEqualSelf:
|
18
43
|
def __eq__(self, value: object) -> bool:
|
@@ -35,8 +60,8 @@ class Context:
|
|
35
60
|
|
36
61
|
__block_info: BlockInfo
|
37
62
|
__outputs_def: Dict[str, HandleDef]
|
63
|
+
__inputs_def: Dict[str, Any]
|
38
64
|
__store: Any
|
39
|
-
__is_done: bool = False
|
40
65
|
__keep_alive: OnlyEqualSelf = OnlyEqualSelf()
|
41
66
|
__session_dir: str
|
42
67
|
__tmp_dir: str
|
@@ -45,7 +70,7 @@ class Context:
|
|
45
70
|
__pkg_dir: str
|
46
71
|
|
47
72
|
def __init__(
|
48
|
-
self, inputs: Dict[str, Any], blockInfo: BlockInfo, mainframe: Mainframe, store,
|
73
|
+
self, *, inputs: Dict[str, Any], blockInfo: BlockInfo, mainframe: Mainframe, store, inputs_def, outputs_def, session_dir: str, tmp_dir: str, package_name: str, pkg_dir: str
|
49
74
|
) -> None:
|
50
75
|
|
51
76
|
self.__block_info = blockInfo
|
@@ -55,10 +80,11 @@ class Context:
|
|
55
80
|
self.__inputs = inputs
|
56
81
|
|
57
82
|
outputs_defs = {}
|
58
|
-
if
|
59
|
-
for k, v in
|
83
|
+
if outputs_def is not None:
|
84
|
+
for k, v in outputs_def.items():
|
60
85
|
outputs_defs[k] = HandleDef(**v)
|
61
86
|
self.__outputs_def = outputs_defs
|
87
|
+
self.__inputs_def = inputs_def
|
62
88
|
self.__session_dir = session_dir
|
63
89
|
self.__tmp_dir = tmp_dir
|
64
90
|
self.__package_name = package_name
|
@@ -105,6 +131,17 @@ class Context:
|
|
105
131
|
@property
|
106
132
|
def inputs(self):
|
107
133
|
return self.__inputs
|
134
|
+
|
135
|
+
@property
|
136
|
+
def inputs_def(self) -> Dict[str, HandleDefDict]:
|
137
|
+
return copy.deepcopy(self.__inputs_def) if self.__inputs_def is not None else {}
|
138
|
+
|
139
|
+
@property
|
140
|
+
def outputs_def(self) -> Dict[str, HandleDefDict]:
|
141
|
+
outputs = {}
|
142
|
+
for k, v in self.__outputs_def.items():
|
143
|
+
outputs[k] = asdict(v)
|
144
|
+
return outputs
|
108
145
|
|
109
146
|
@property
|
110
147
|
def session_id(self):
|
@@ -156,10 +193,6 @@ class Context:
|
|
156
193
|
"""
|
157
194
|
return os.getenv("OO_HOST_ENDPOINT", None)
|
158
195
|
|
159
|
-
@property
|
160
|
-
def is_done(self) -> bool:
|
161
|
-
return self.__is_done
|
162
|
-
|
163
196
|
def __store_ref(self, handle: str):
|
164
197
|
return StoreKey(
|
165
198
|
executor=EXECUTOR_NAME,
|
@@ -170,8 +203,67 @@ class Context:
|
|
170
203
|
|
171
204
|
def __is_basic_type(self, value: Any) -> bool:
|
172
205
|
return isinstance(value, (int, float, str, bool))
|
206
|
+
|
207
|
+
def __wrap_output_value(self, handle: str, value: Any):
|
208
|
+
"""
|
209
|
+
wrap the output value:
|
210
|
+
if the value is a var handle, store it in the store and return the reference.
|
211
|
+
if the value is a bin handle, store it in the store and return the reference.
|
212
|
+
if the handle is not defined in the block outputs schema, raise an ValueError.
|
213
|
+
otherwise, return the value.
|
214
|
+
:param handle: the handle of the output
|
215
|
+
:param value: the value of the output
|
216
|
+
:return: the wrapped value
|
217
|
+
"""
|
218
|
+
# __outputs_def should never be None
|
219
|
+
if self.__outputs_def is None:
|
220
|
+
return value
|
221
|
+
|
222
|
+
output_def = self.__outputs_def.get(handle)
|
223
|
+
if output_def is None:
|
224
|
+
raise ValueError(
|
225
|
+
f"Output handle key: [{handle}] is not defined in Block outputs schema."
|
226
|
+
)
|
227
|
+
|
228
|
+
if output_def.is_var_handle() and not self.__is_basic_type(value):
|
229
|
+
ref = self.__store_ref(handle)
|
230
|
+
self.__store[ref] = value
|
231
|
+
var: VarValueDict = {
|
232
|
+
"__OOMOL_TYPE__": "oomol/var",
|
233
|
+
"value": asdict(ref)
|
234
|
+
}
|
235
|
+
return var
|
236
|
+
|
237
|
+
if output_def.is_bin_handle():
|
238
|
+
if not isinstance(value, bytes):
|
239
|
+
self.send_warning(
|
240
|
+
f"Output handle key: [{handle}] is defined as binary, but the value is not bytes."
|
241
|
+
)
|
242
|
+
return value
|
243
|
+
|
244
|
+
bin_file = f"{self.session_dir}/binary/{self.session_id}/{self.job_id}/{handle}"
|
245
|
+
os.makedirs(os.path.dirname(bin_file), exist_ok=True)
|
246
|
+
try:
|
247
|
+
with open(bin_file, "wb") as f:
|
248
|
+
f.write(value)
|
249
|
+
except IOError as e:
|
250
|
+
raise IOError(
|
251
|
+
f"Output handle key: [{handle}] is defined as binary, but an error occurred while writing the file: {e}"
|
252
|
+
)
|
253
|
+
|
254
|
+
if os.path.exists(bin_file):
|
255
|
+
bin_value: BinValueDict = {
|
256
|
+
"__OOMOL_TYPE__": "oomol/bin",
|
257
|
+
"value": bin_file,
|
258
|
+
}
|
259
|
+
return bin_value
|
260
|
+
else:
|
261
|
+
raise IOError(
|
262
|
+
f"Output handle key: [{handle}] is defined as binary, but the file is not written."
|
263
|
+
)
|
264
|
+
return value
|
173
265
|
|
174
|
-
def output(self, key: str, value: Any
|
266
|
+
def output(self, key: str, value: Any):
|
175
267
|
"""
|
176
268
|
output the value to the next block
|
177
269
|
|
@@ -179,81 +271,85 @@ class Context:
|
|
179
271
|
value: Any, the value of the output
|
180
272
|
"""
|
181
273
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
output_def = self.__outputs_def.get(key)
|
186
|
-
if (
|
187
|
-
output_def is not None and output_def.is_var_handle() and not self.__is_basic_type(value) # 基础类型即使是变量也不放进 store,直接作为 json 内容传递
|
188
|
-
):
|
189
|
-
ref = self.__store_ref(key)
|
190
|
-
self.__store[ref] = value
|
191
|
-
d: VarValueDict = {
|
192
|
-
"__OOMOL_TYPE__": "oomol/var",
|
193
|
-
"value": asdict(ref)
|
194
|
-
}
|
195
|
-
v = d
|
196
|
-
elif output_def is not None and output_def.is_bin_handle():
|
197
|
-
if not isinstance(value, bytes):
|
198
|
-
self.send_warning(
|
199
|
-
f"Output handle key: [{key}] is defined as binary, but the value is not bytes."
|
200
|
-
)
|
201
|
-
return
|
202
|
-
|
203
|
-
bin_file = f"{self.session_dir}/binary/{self.session_id}/{self.job_id}/{key}"
|
204
|
-
os.makedirs(os.path.dirname(bin_file), exist_ok=True)
|
205
|
-
try:
|
206
|
-
with open(bin_file, "wb") as f:
|
207
|
-
f.write(value)
|
208
|
-
except IOError as e:
|
209
|
-
self.send_warning(
|
210
|
-
f"Output handle key: [{key}] is defined as binary, but an error occurred while writing the file: {e}"
|
211
|
-
)
|
212
|
-
return
|
213
|
-
|
214
|
-
if os.path.exists(bin_file):
|
215
|
-
bin_value: BinValueDict = {
|
216
|
-
"__OOMOL_TYPE__": "oomol/bin",
|
217
|
-
"value": bin_file,
|
218
|
-
}
|
219
|
-
v = bin_value
|
220
|
-
else:
|
221
|
-
self.send_warning(
|
222
|
-
f"Output handle key: [{key}] is defined as binary, but the file is not written."
|
223
|
-
)
|
224
|
-
return
|
225
|
-
|
226
|
-
# 如果传入 key 在输出定义中不存在,直接忽略,不发送数据。但是 done 仍然生效。
|
227
|
-
if self.__outputs_def is not None and self.__outputs_def.get(key) is None:
|
274
|
+
try:
|
275
|
+
wrap_value = self.__wrap_output_value(key, value)
|
276
|
+
except ValueError as e:
|
228
277
|
self.send_warning(
|
229
|
-
f"
|
278
|
+
f"{e}"
|
279
|
+
)
|
280
|
+
return
|
281
|
+
except IOError as e:
|
282
|
+
self.send_warning(
|
283
|
+
f"{e}"
|
230
284
|
)
|
231
|
-
if done:
|
232
|
-
self.done()
|
233
285
|
return
|
234
286
|
|
235
287
|
node_result = {
|
236
288
|
"type": "BlockOutput",
|
237
289
|
"handle": key,
|
238
|
-
"output":
|
239
|
-
"done": done,
|
290
|
+
"output": wrap_value,
|
240
291
|
}
|
241
292
|
self.__mainframe.send(self.job_info, node_result)
|
293
|
+
|
294
|
+
def outputs(self, outputs: Dict[str, Any]):
|
295
|
+
"""
|
296
|
+
output the value to the next block
|
242
297
|
|
243
|
-
|
244
|
-
|
298
|
+
map: Dict[str, Any], the key of the output, should be defined in the block schema output defs, the field name is handle
|
299
|
+
"""
|
245
300
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
301
|
+
values = {}
|
302
|
+
for key, value in outputs.items():
|
303
|
+
try:
|
304
|
+
wrap_value = self.__wrap_output_value(key, value)
|
305
|
+
values[key] = wrap_value
|
306
|
+
except ValueError as e:
|
307
|
+
self.send_warning(
|
308
|
+
f"{e}"
|
309
|
+
)
|
310
|
+
except IOError as e:
|
311
|
+
self.send_warning(
|
312
|
+
f"{e}"
|
313
|
+
)
|
314
|
+
self.__mainframe.send(self.job_info, {
|
315
|
+
"type": "BlockOutputs",
|
316
|
+
"outputs": values,
|
317
|
+
})
|
318
|
+
|
319
|
+
|
320
|
+
|
321
|
+
def finish(self, *, result: Dict[str, Any] | None = None, error: str | None = None):
|
322
|
+
"""
|
323
|
+
finish the block, and send the result to oocana.
|
324
|
+
if error is not None, the block will be finished with error.
|
325
|
+
then if result is not None, the block will be finished with result.
|
326
|
+
lastly, if both error and result are None, the block will be finished without any result.
|
327
|
+
"""
|
328
|
+
|
329
|
+
if error is not None:
|
330
|
+
self.__mainframe.send(self.job_info, {"type": "BlockFinished", "error": error})
|
331
|
+
elif result is not None:
|
332
|
+
wrap_result = {}
|
333
|
+
if isinstance(result, dict):
|
334
|
+
for key, value in result.items():
|
335
|
+
try:
|
336
|
+
wrap_result[key] = self.__wrap_output_value(key, value)
|
337
|
+
except ValueError as e:
|
338
|
+
self.send_warning(
|
339
|
+
f"Output handle key: [{key}] is not defined in Block outputs schema. {e}"
|
340
|
+
)
|
341
|
+
except IOError as e:
|
342
|
+
self.send_warning(
|
343
|
+
f"Output handle key: [{key}] is not defined in Block outputs schema. {e}"
|
344
|
+
)
|
345
|
+
|
346
|
+
self.__mainframe.send(self.job_info, {"type": "BlockFinished", "result": wrap_result})
|
347
|
+
else:
|
348
|
+
raise ValueError(
|
349
|
+
f"result should be a dict, but got {type(result)}"
|
350
|
+
)
|
253
351
|
else:
|
254
|
-
self.__mainframe.send(
|
255
|
-
self.job_info, {"type": "BlockFinished", "error": error}
|
256
|
-
)
|
352
|
+
self.__mainframe.send(self.job_info, {"type": "BlockFinished"})
|
257
353
|
|
258
354
|
def send_message(self, payload):
|
259
355
|
self.__mainframe.report(
|
@@ -11,12 +11,18 @@ class HandleDef:
|
|
11
11
|
handle: str
|
12
12
|
"""The name of the handle. it should be unique in handle list."""
|
13
13
|
|
14
|
+
"""The description of the handle. It is used to display in the UI."""
|
15
|
+
description: Optional[str] = None
|
16
|
+
|
14
17
|
json_schema: Optional[FieldSchema] = None
|
15
18
|
"""The schema of the handle. It is used to validate the handle's content."""
|
16
19
|
|
17
|
-
|
20
|
+
kind: Optional[str] = None
|
18
21
|
"""A alias of the handle's type name. It is used to display in the UI and connect to the other handle match"""
|
19
22
|
|
23
|
+
nullable: bool = False
|
24
|
+
"""If the handle value can be None. If True, the handle can be None, otherwise it must have a value."""
|
25
|
+
|
20
26
|
def __init__(self, **kwargs):
|
21
27
|
for key, value in kwargs.items():
|
22
28
|
object.__setattr__(self, key, value)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|