benchling-sdk 1.9.0a4__py3-none-any.whl → 1.10.0__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.
- benchling_sdk/apps/canvas/__init__.py +0 -0
- benchling_sdk/apps/canvas/errors.py +14 -0
- benchling_sdk/apps/{helpers/canvas_helpers.py → canvas/framework.py} +129 -188
- benchling_sdk/apps/canvas/types.py +125 -0
- benchling_sdk/apps/config/__init__.py +0 -3
- benchling_sdk/apps/config/decryption_provider.py +1 -1
- benchling_sdk/apps/config/errors.py +38 -0
- benchling_sdk/apps/config/framework.py +343 -0
- benchling_sdk/apps/config/helpers.py +157 -0
- benchling_sdk/apps/config/{mock_dependencies.py → mock_config.py} +78 -99
- benchling_sdk/apps/config/types.py +36 -0
- benchling_sdk/apps/framework.py +49 -338
- benchling_sdk/apps/helpers/webhook_helpers.py +2 -2
- benchling_sdk/apps/status/__init__.py +0 -0
- benchling_sdk/apps/status/errors.py +85 -0
- benchling_sdk/apps/{helpers/session_helpers.py → status/framework.py} +58 -167
- benchling_sdk/apps/status/helpers.py +20 -0
- benchling_sdk/apps/status/types.py +45 -0
- benchling_sdk/apps/types.py +3 -0
- benchling_sdk/errors.py +4 -4
- benchling_sdk/helpers/retry_helpers.py +3 -1
- benchling_sdk/models/__init__.py +44 -0
- benchling_sdk/services/v2/beta/{v2_beta_dataset_service.py → v2_beta_data_frame_service.py} +126 -116
- benchling_sdk/services/v2/stable/assay_result_service.py +18 -0
- benchling_sdk/services/v2/v2_beta_service.py +11 -11
- {benchling_sdk-1.9.0a4.dist-info → benchling_sdk-1.10.0.dist-info}/METADATA +4 -4
- {benchling_sdk-1.9.0a4.dist-info → benchling_sdk-1.10.0.dist-info}/RECORD +30 -21
- benchling_sdk/apps/config/dependencies.py +0 -1085
- benchling_sdk/apps/config/scalars.py +0 -226
- benchling_sdk/apps/helpers/config_helpers.py +0 -409
- /benchling_sdk/apps/{helpers → config}/cryptography_helpers.py +0 -0
- {benchling_sdk-1.9.0a4.dist-info → benchling_sdk-1.10.0.dist-info}/LICENSE +0 -0
- {benchling_sdk-1.9.0a4.dist-info → benchling_sdk-1.10.0.dist-info}/WHEEL +0 -0
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class DuplicateBlockIdError(Exception):
|
2
|
+
"""Error indicating that duplicate ids were present on blocks within a Canvas."""
|
3
|
+
|
4
|
+
pass
|
5
|
+
|
6
|
+
|
7
|
+
class NoMatchingBlocksError(Exception):
|
8
|
+
"""
|
9
|
+
Error indicating that blocks were expected, but none matched.
|
10
|
+
|
11
|
+
Used to prevent requiring developers to handle Optional[_UiBlock] for type safety.
|
12
|
+
"""
|
13
|
+
|
14
|
+
pass
|
@@ -1,142 +1,40 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import json
|
3
4
|
from typing import cast, Dict, Generic, List, Optional, Protocol, Set, Type, TypeVar, Union
|
4
5
|
|
5
6
|
from benchling_api_client.v2.extensions import UnknownType
|
6
7
|
|
7
|
-
from benchling_sdk.
|
8
|
+
from benchling_sdk.apps.canvas.errors import DuplicateBlockIdError, NoMatchingBlocksError
|
9
|
+
from benchling_sdk.apps.canvas.types import (
|
10
|
+
_UI_BLOCK_MAPPINGS_CREATE,
|
11
|
+
_UI_BLOCK_MAPPINGS_UPDATE,
|
12
|
+
_UiBlockCreate,
|
13
|
+
_UiBlockUpdate,
|
14
|
+
UiBlock,
|
15
|
+
UiBlockType,
|
16
|
+
)
|
17
|
+
from benchling_sdk.apps.types import JsonType
|
8
18
|
from benchling_sdk.models import (
|
9
19
|
AppCanvas,
|
10
20
|
AppCanvasApp,
|
11
21
|
AppCanvasCreate,
|
12
22
|
AppCanvasUpdate,
|
13
|
-
ButtonUiBlock,
|
14
|
-
ButtonUiBlockCreate,
|
15
|
-
ButtonUiBlockUpdate,
|
16
|
-
ChipUiBlock,
|
17
|
-
ChipUiBlockCreate,
|
18
|
-
ChipUiBlockUpdate,
|
19
23
|
DropdownMultiValueUiBlock,
|
20
|
-
DropdownMultiValueUiBlockCreate,
|
21
|
-
DropdownMultiValueUiBlockUpdate,
|
22
24
|
DropdownUiBlock,
|
23
|
-
DropdownUiBlockCreate,
|
24
|
-
DropdownUiBlockUpdate,
|
25
|
-
MarkdownUiBlock,
|
26
|
-
MarkdownUiBlockCreate,
|
27
|
-
MarkdownUiBlockUpdate,
|
28
25
|
SearchInputMultiValueUiBlock,
|
29
|
-
SearchInputMultiValueUiBlockCreate,
|
30
|
-
SearchInputMultiValueUiBlockUpdate,
|
31
26
|
SearchInputUiBlock,
|
32
|
-
SearchInputUiBlockCreate,
|
33
|
-
SearchInputUiBlockUpdate,
|
34
27
|
SectionUiBlock,
|
35
|
-
SectionUiBlockCreate,
|
36
|
-
SectionUiBlockUpdate,
|
37
28
|
SelectorInputMultiValueUiBlock,
|
38
|
-
SelectorInputMultiValueUiBlockCreate,
|
39
|
-
SelectorInputMultiValueUiBlockUpdate,
|
40
29
|
SelectorInputUiBlock,
|
41
|
-
SelectorInputUiBlockCreate,
|
42
|
-
SelectorInputUiBlockUpdate,
|
43
30
|
TableUiBlock,
|
44
|
-
TableUiBlockCreate,
|
45
|
-
TableUiBlockUpdate,
|
46
31
|
TextInputUiBlock,
|
47
|
-
TextInputUiBlockCreate,
|
48
|
-
TextInputUiBlockUpdate,
|
49
32
|
)
|
50
33
|
|
51
|
-
|
52
|
-
|
53
|
-
S = TypeVar("S", bound="_FilteredCanvasBuilderBlockStream")
|
54
|
-
|
55
|
-
_UiBlock = Union[
|
56
|
-
ButtonUiBlock,
|
57
|
-
ChipUiBlock,
|
58
|
-
DropdownMultiValueUiBlock,
|
59
|
-
DropdownUiBlock,
|
60
|
-
MarkdownUiBlock,
|
61
|
-
SearchInputMultiValueUiBlock,
|
62
|
-
SearchInputUiBlock,
|
63
|
-
SectionUiBlock,
|
64
|
-
SelectorInputMultiValueUiBlock,
|
65
|
-
SelectorInputUiBlock,
|
66
|
-
TableUiBlock,
|
67
|
-
TextInputUiBlock,
|
68
|
-
UnknownType,
|
69
|
-
]
|
34
|
+
S = TypeVar("S", bound="FilteredCanvasBuilderBlockStream")
|
70
35
|
|
71
|
-
_UiBlockType = TypeVar(
|
72
|
-
"_UiBlockType",
|
73
|
-
bound=_UiBlock,
|
74
|
-
)
|
75
36
|
|
76
|
-
|
77
|
-
ButtonUiBlockCreate,
|
78
|
-
ChipUiBlockCreate,
|
79
|
-
DropdownMultiValueUiBlockCreate,
|
80
|
-
DropdownUiBlockCreate,
|
81
|
-
MarkdownUiBlockCreate,
|
82
|
-
SearchInputMultiValueUiBlockCreate,
|
83
|
-
SearchInputUiBlockCreate,
|
84
|
-
SectionUiBlockCreate,
|
85
|
-
SelectorInputMultiValueUiBlockCreate,
|
86
|
-
SelectorInputUiBlockCreate,
|
87
|
-
TableUiBlockCreate,
|
88
|
-
TextInputUiBlockCreate,
|
89
|
-
UnknownType,
|
90
|
-
]
|
91
|
-
|
92
|
-
_UiBlockUpdate = Union[
|
93
|
-
ButtonUiBlockUpdate,
|
94
|
-
ChipUiBlockUpdate,
|
95
|
-
DropdownMultiValueUiBlockUpdate,
|
96
|
-
DropdownUiBlockUpdate,
|
97
|
-
MarkdownUiBlockUpdate,
|
98
|
-
SearchInputMultiValueUiBlockUpdate,
|
99
|
-
SearchInputUiBlockUpdate,
|
100
|
-
SectionUiBlockUpdate,
|
101
|
-
SelectorInputMultiValueUiBlockUpdate,
|
102
|
-
SelectorInputUiBlockUpdate,
|
103
|
-
TableUiBlockUpdate,
|
104
|
-
TextInputUiBlockUpdate,
|
105
|
-
UnknownType,
|
106
|
-
]
|
107
|
-
|
108
|
-
_UI_BLOCK_MAPPINGS_CREATE = {
|
109
|
-
ButtonUiBlock: ButtonUiBlockCreate,
|
110
|
-
ChipUiBlock: ChipUiBlockCreate,
|
111
|
-
DropdownMultiValueUiBlock: DropdownMultiValueUiBlockCreate,
|
112
|
-
DropdownUiBlock: DropdownUiBlockCreate,
|
113
|
-
MarkdownUiBlock: MarkdownUiBlockCreate,
|
114
|
-
SearchInputMultiValueUiBlock: SearchInputMultiValueUiBlockCreate,
|
115
|
-
SearchInputUiBlock: SearchInputUiBlockCreate,
|
116
|
-
SectionUiBlock: SectionUiBlockCreate,
|
117
|
-
SelectorInputMultiValueUiBlock: SelectorInputMultiValueUiBlockCreate,
|
118
|
-
SelectorInputUiBlock: SelectorInputUiBlockCreate,
|
119
|
-
TableUiBlock: TableUiBlockCreate,
|
120
|
-
TextInputUiBlock: TextInputUiBlockCreate,
|
121
|
-
}
|
122
|
-
|
123
|
-
_UI_BLOCK_MAPPINGS_UPDATE = {
|
124
|
-
ButtonUiBlock: ButtonUiBlockUpdate,
|
125
|
-
ChipUiBlock: ChipUiBlockUpdate,
|
126
|
-
DropdownMultiValueUiBlock: DropdownMultiValueUiBlockUpdate,
|
127
|
-
DropdownUiBlock: DropdownUiBlockUpdate,
|
128
|
-
MarkdownUiBlock: MarkdownUiBlockUpdate,
|
129
|
-
SearchInputMultiValueUiBlock: SearchInputMultiValueUiBlockUpdate,
|
130
|
-
SearchInputUiBlock: SearchInputUiBlockUpdate,
|
131
|
-
SectionUiBlock: SectionUiBlockUpdate,
|
132
|
-
SelectorInputMultiValueUiBlock: SelectorInputMultiValueUiBlockUpdate,
|
133
|
-
SelectorInputUiBlock: SelectorInputUiBlockUpdate,
|
134
|
-
TableUiBlock: TableUiBlockUpdate,
|
135
|
-
TextInputUiBlock: TextInputUiBlockUpdate,
|
136
|
-
}
|
137
|
-
|
138
|
-
|
139
|
-
def _ui_block_to_create(block: _UiBlock) -> _UiBlockCreate:
|
37
|
+
def _ui_block_to_create(block: UiBlock) -> _UiBlockCreate:
|
140
38
|
# Rely on the fact that the read/write shapes are compatible, for now
|
141
39
|
if isinstance(block, UnknownType):
|
142
40
|
return block
|
@@ -150,7 +48,7 @@ def _ui_block_to_create(block: _UiBlock) -> _UiBlockCreate:
|
|
150
48
|
return block # type: ignore
|
151
49
|
|
152
50
|
|
153
|
-
def _ui_block_to_update(block:
|
51
|
+
def _ui_block_to_update(block: UiBlock) -> _UiBlockUpdate:
|
154
52
|
# Rely on the fact that the read/write shapes are compatible, for now
|
155
53
|
# Update is functionally the same as create at the moment but different for type safety
|
156
54
|
# and reserved in case the shapes do diverge later
|
@@ -166,44 +64,27 @@ def _ui_block_to_update(block: _UiBlock) -> _UiBlockUpdate:
|
|
166
64
|
return block # type: ignore
|
167
65
|
|
168
66
|
|
169
|
-
class
|
170
|
-
"""Error indicating that duplicate ids were present on blocks within a Canvas."""
|
171
|
-
|
172
|
-
pass
|
173
|
-
|
174
|
-
|
175
|
-
class NoMatchingBlocksError(Exception):
|
176
|
-
"""
|
177
|
-
Error indicating that blocks were expected, but none matched.
|
178
|
-
|
179
|
-
Used to prevent requiring developers to handle Optional[_UiBlock] for type safety.
|
180
|
-
"""
|
181
|
-
|
182
|
-
pass
|
183
|
-
|
184
|
-
|
185
|
-
class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
67
|
+
class CanvasBuilderUiBlock(Generic[UiBlockType]):
|
186
68
|
"""Internal UI block wrapper for CanvasBuilder."""
|
187
69
|
|
188
|
-
_block:
|
70
|
+
_block: UiBlockType
|
189
71
|
_builder: CanvasBuilder
|
190
72
|
|
191
|
-
def __init__(self, block:
|
73
|
+
def __init__(self, block: UiBlockType, builder: CanvasBuilder):
|
74
|
+
"""Init CanvasBuilderUiBlock."""
|
192
75
|
self._block = block
|
193
76
|
self._builder = builder
|
194
77
|
|
195
78
|
@classmethod
|
196
|
-
def from_api_model(
|
197
|
-
cls, block: _UiBlockType, builder: CanvasBuilder
|
198
|
-
) -> _CanvasBuilderUiBlock[_UiBlockType]:
|
79
|
+
def from_api_model(cls, block: UiBlockType, builder: CanvasBuilder) -> CanvasBuilderUiBlock[UiBlockType]:
|
199
80
|
"""Create a _CanvasBuilderUiBlock from an underlying API model."""
|
200
81
|
return cls(block, builder)
|
201
82
|
|
202
|
-
def to_api_model(self) ->
|
83
|
+
def to_api_model(self) -> UiBlockType:
|
203
84
|
"""Convert to the underlying API model."""
|
204
85
|
return self._block
|
205
86
|
|
206
|
-
def children(self) ->
|
87
|
+
def children(self) -> CanvasBuilderBlockStream:
|
207
88
|
"""
|
208
89
|
Return children for blocks when applicable, such as for section blocks.
|
209
90
|
|
@@ -214,16 +95,16 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
214
95
|
# MyPy can't recognize the type narrowing when we check .children below
|
215
96
|
section_block = cast(SectionUiBlock, model)
|
216
97
|
child_blocks = [
|
217
|
-
|
98
|
+
CanvasBuilderUiBlock.from_api_model(block, self._builder) for block in section_block.children
|
218
99
|
]
|
219
100
|
# Pass reference to parent block (self)
|
220
|
-
return
|
221
|
-
return
|
101
|
+
return CanvasBuilderBlockStream(self._builder, child_blocks, child_blocks, self)
|
102
|
+
return CanvasBuilderBlockStream(self._builder, [], [])
|
222
103
|
|
223
|
-
def replace(self, new_blocks: List[
|
104
|
+
def replace(self, new_blocks: List[UiBlock]) -> None:
|
224
105
|
"""Replace block with provided new_blocks."""
|
225
106
|
parent = self._parent_block()
|
226
|
-
model = cast(
|
107
|
+
model = cast(UiBlock, self.to_api_model())
|
227
108
|
if parent:
|
228
109
|
self.insert_after(new_blocks)
|
229
110
|
# Keeps MyPy happy; SectionUiBlock is not valid for .children of SectionUiBlock
|
@@ -237,7 +118,7 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
237
118
|
def remove(self) -> None:
|
238
119
|
"""Remove block."""
|
239
120
|
parent = self._parent_block()
|
240
|
-
model = cast(
|
121
|
+
model = cast(UiBlock, self.to_api_model())
|
241
122
|
if parent:
|
242
123
|
# Keeps MyPy happy; SectionUiBlock is not valid for .children of SectionUiBlock
|
243
124
|
assert not (isinstance(model, SectionUiBlock) or isinstance(model, TableUiBlock))
|
@@ -246,15 +127,15 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
246
127
|
# noinspection PyProtectedMember
|
247
128
|
self._builder._source_canvas.blocks.remove(model)
|
248
129
|
|
249
|
-
def insert_after(self, new_blocks: List[
|
130
|
+
def insert_after(self, new_blocks: List[UiBlock]) -> None:
|
250
131
|
"""Insert new_blocks after block."""
|
251
132
|
self._nested_insert(new_blocks, 1)
|
252
133
|
|
253
|
-
def insert_before(self, new_blocks: List[
|
134
|
+
def insert_before(self, new_blocks: List[UiBlock]) -> None:
|
254
135
|
"""Insert new_blocks before block."""
|
255
136
|
self._nested_insert(new_blocks, 0)
|
256
137
|
|
257
|
-
def _nested_insert(self, new_blocks: List[
|
138
|
+
def _nested_insert(self, new_blocks: List[UiBlock], offset: int) -> None:
|
258
139
|
"""
|
259
140
|
Nested insert.
|
260
141
|
|
@@ -269,7 +150,7 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
269
150
|
# Using list() to solve "List" is invariant creates a copy which means this stops working
|
270
151
|
self._insert(new_blocks, offset, child_blocks, self.to_api_model()) # type: ignore
|
271
152
|
parent_block.children = child_blocks
|
272
|
-
parent_builder_block =
|
153
|
+
parent_builder_block = CanvasBuilderUiBlock.from_api_model(parent_block, self._builder)
|
273
154
|
parent_builder_block.insert_after([parent_block])
|
274
155
|
# noinspection PyProtectedMember
|
275
156
|
self._builder._source_canvas.blocks.remove(parent_builder_block.to_api_model())
|
@@ -278,9 +159,7 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
278
159
|
self._insert(new_blocks, offset, self._builder._source_canvas.blocks, self.to_api_model())
|
279
160
|
|
280
161
|
@staticmethod
|
281
|
-
def _insert(
|
282
|
-
new_blocks: List[_UiBlock], offset: int, blocks: List[_UiBlock], target_block: _UiBlock
|
283
|
-
) -> None:
|
162
|
+
def _insert(new_blocks: List[UiBlock], offset: int, blocks: List[UiBlock], target_block: UiBlock) -> None:
|
284
163
|
"""Insert new_blocks before block as a side effect."""
|
285
164
|
index = blocks.index(target_block)
|
286
165
|
for count, new_block in enumerate(new_blocks):
|
@@ -295,26 +174,29 @@ class _CanvasBuilderUiBlock(Generic[_UiBlockType]):
|
|
295
174
|
return None
|
296
175
|
|
297
176
|
|
298
|
-
class
|
299
|
-
|
177
|
+
class CanvasBuilderFilter(Protocol):
|
178
|
+
"""Callable protocol for specifying a predicate for filtering UiBlocks."""
|
179
|
+
|
180
|
+
def __call__(self, block: UiBlockType) -> bool:
|
300
181
|
"""Return True if the UiBlock matches specified conditions."""
|
301
182
|
pass
|
302
183
|
|
303
184
|
|
304
|
-
class
|
305
|
-
"""
|
185
|
+
class FilteredCanvasBuilderBlockStream:
|
186
|
+
"""Filtered UI block list wrapper for CanvasBuilder."""
|
306
187
|
|
307
188
|
_builder: CanvasBuilder
|
308
|
-
_blocks: List[
|
309
|
-
_selected_blocks: List[
|
189
|
+
_blocks: List[CanvasBuilderUiBlock]
|
190
|
+
_selected_blocks: List[CanvasBuilderUiBlock]
|
310
191
|
_cursor: int
|
311
192
|
|
312
193
|
def __init__(
|
313
194
|
self,
|
314
195
|
builder: CanvasBuilder,
|
315
|
-
blocks: List[
|
316
|
-
selected_blocks: List[
|
196
|
+
blocks: List[CanvasBuilderUiBlock],
|
197
|
+
selected_blocks: List[CanvasBuilderUiBlock],
|
317
198
|
):
|
199
|
+
"""Init FilteredCanvasBuilderBlockStream."""
|
318
200
|
self._builder = builder
|
319
201
|
self._blocks = blocks
|
320
202
|
self._selected_blocks = selected_blocks
|
@@ -339,26 +221,26 @@ class _FilteredCanvasBuilderBlockStream:
|
|
339
221
|
"""
|
340
222
|
# noinspection PyProtectedMember
|
341
223
|
blocks = [
|
342
|
-
|
224
|
+
CanvasBuilderUiBlock.from_api_model(block, builder)
|
343
225
|
for block in builder._source_canvas.blocks
|
344
226
|
if not isinstance(block, UnknownType)
|
345
227
|
]
|
346
228
|
return cls(builder, blocks, blocks)
|
347
229
|
|
348
|
-
def filter(self, filter_function:
|
230
|
+
def filter(self, filter_function: CanvasBuilderFilter) -> FilteredCanvasBuilderBlockStream:
|
349
231
|
"""
|
350
232
|
Filter.
|
351
233
|
|
352
234
|
Accept a predicate that evaluates if a UiBlock should be included in the result or not.
|
353
235
|
Returns a new stream of blocks filtered to the predicate, which is further operable.
|
354
236
|
"""
|
355
|
-
return
|
237
|
+
return CanvasBuilderBlockStream(
|
356
238
|
self._builder,
|
357
239
|
self._blocks,
|
358
240
|
[block for block in self._selected_blocks if filter_function(block.to_api_model())],
|
359
241
|
)
|
360
242
|
|
361
|
-
def get_by_id(self, block_id: str) ->
|
243
|
+
def get_by_id(self, block_id: str) -> CanvasBuilderUiBlock:
|
362
244
|
"""
|
363
245
|
Get a block by its id.
|
364
246
|
|
@@ -370,8 +252,8 @@ class _FilteredCanvasBuilderBlockStream:
|
|
370
252
|
return matched_block
|
371
253
|
|
372
254
|
def _block_by_id(
|
373
|
-
self, block_id: str, blocks: List[
|
374
|
-
) -> Optional[
|
255
|
+
self, block_id: str, blocks: List[CanvasBuilderUiBlock]
|
256
|
+
) -> Optional[CanvasBuilderUiBlock]:
|
375
257
|
for block in blocks:
|
376
258
|
api_block = block.to_api_model()
|
377
259
|
if api_block.id == block_id:
|
@@ -387,13 +269,13 @@ class _FilteredCanvasBuilderBlockStream:
|
|
387
269
|
"""Return a count of the elements in the list of blocks."""
|
388
270
|
return len(self._selected_blocks)
|
389
271
|
|
390
|
-
def first(self) ->
|
272
|
+
def first(self) -> CanvasBuilderUiBlock:
|
391
273
|
"""Return the first block in the list."""
|
392
274
|
if len(self._selected_blocks) < 1:
|
393
275
|
raise NoMatchingBlocksError
|
394
276
|
return self._selected_blocks[0]
|
395
277
|
|
396
|
-
def last(self) ->
|
278
|
+
def last(self) -> CanvasBuilderUiBlock:
|
397
279
|
"""Return the last block in the list."""
|
398
280
|
if len(self._selected_blocks) < 1:
|
399
281
|
raise NoMatchingBlocksError
|
@@ -408,26 +290,27 @@ class _FilteredCanvasBuilderBlockStream:
|
|
408
290
|
self._builder._source_canvas.blocks = updated_blocks
|
409
291
|
|
410
292
|
|
411
|
-
class
|
293
|
+
class CanvasBuilderBlockStream(FilteredCanvasBuilderBlockStream):
|
412
294
|
"""
|
413
295
|
Internal UI block list wrapper for CanvasBuilder.
|
414
296
|
|
415
297
|
Possesses some additional operations unavailable to filtered block streams.
|
416
298
|
"""
|
417
299
|
|
418
|
-
_parent: Optional[
|
300
|
+
_parent: Optional[CanvasBuilderUiBlock]
|
419
301
|
|
420
302
|
def __init__(
|
421
303
|
self,
|
422
304
|
builder: CanvasBuilder,
|
423
|
-
blocks: List[
|
424
|
-
selected_blocks: List[
|
425
|
-
parent: Optional[
|
305
|
+
blocks: List[CanvasBuilderUiBlock],
|
306
|
+
selected_blocks: List[CanvasBuilderUiBlock],
|
307
|
+
parent: Optional[CanvasBuilderUiBlock] = None,
|
426
308
|
):
|
309
|
+
"""Init CanvasBuilderBlockStream."""
|
427
310
|
super().__init__(builder, blocks, selected_blocks)
|
428
311
|
self._parent = parent
|
429
312
|
|
430
|
-
def append(self, new_blocks: List[
|
313
|
+
def append(self, new_blocks: List[UiBlock]) -> None:
|
431
314
|
"""
|
432
315
|
Append new_blocks to the end of list of blocks.
|
433
316
|
|
@@ -484,7 +367,8 @@ class CanvasBuilder:
|
|
484
367
|
resource_id: str,
|
485
368
|
enabled: bool = True,
|
486
369
|
session_id: Optional[str] = None,
|
487
|
-
blocks: Optional[List[
|
370
|
+
blocks: Optional[List[UiBlock]] = None,
|
371
|
+
data: Optional[JsonType] = None,
|
488
372
|
):
|
489
373
|
"""
|
490
374
|
Init AppCanvas.
|
@@ -498,6 +382,7 @@ class CanvasBuilder:
|
|
498
382
|
enabled=enabled,
|
499
383
|
session_id=session_id,
|
500
384
|
blocks=blocks if blocks else [],
|
385
|
+
data=json.dumps(data) if data is not None else None,
|
501
386
|
)
|
502
387
|
|
503
388
|
@classmethod
|
@@ -514,6 +399,7 @@ class CanvasBuilder:
|
|
514
399
|
enabled=canvas.enabled,
|
515
400
|
session_id=canvas.session_id,
|
516
401
|
blocks=canvas.blocks,
|
402
|
+
data=json.loads(canvas.data) if isinstance(canvas.data, str) else None,
|
517
403
|
)
|
518
404
|
|
519
405
|
def _with_enabled(self, value: bool) -> CanvasBuilder:
|
@@ -525,23 +411,65 @@ class CanvasBuilder:
|
|
525
411
|
enabled=value,
|
526
412
|
session_id=self._source_canvas.session_id,
|
527
413
|
blocks=self._source_canvas.blocks,
|
414
|
+
data=self.data_to_json(),
|
528
415
|
)
|
529
416
|
|
530
|
-
def
|
417
|
+
def with_enabled(self, enabled: bool = True) -> CanvasBuilder:
|
531
418
|
"""
|
532
|
-
Return a new CanvasBuilder with the underlying canvas
|
419
|
+
Return a new CanvasBuilder with the underlying canvas enabled set to the specified value.
|
533
420
|
|
421
|
+
Specify `False` to disable the canvas.
|
534
422
|
This does not call the API, it only assigns state in the CanvasBuilder.
|
535
423
|
"""
|
536
|
-
return self._with_enabled(
|
424
|
+
return self._with_enabled(enabled)
|
537
425
|
|
538
|
-
def
|
426
|
+
def with_blocks(self, new_blocks: List[UiBlock]) -> CanvasBuilder:
|
539
427
|
"""
|
540
|
-
Return a new CanvasBuilder with the underlying
|
428
|
+
Return a new CanvasBuilder with the underlying blocks replaced.
|
541
429
|
|
542
430
|
This does not call the API, it only assigns state in the CanvasBuilder.
|
543
431
|
"""
|
544
|
-
return
|
432
|
+
return CanvasBuilder(
|
433
|
+
app_id=self._source_canvas.app.id,
|
434
|
+
feature_id=self._source_canvas.feature_id,
|
435
|
+
resource_id=self._source_canvas.resource_id,
|
436
|
+
enabled=self._source_canvas.enabled,
|
437
|
+
session_id=self._source_canvas.session_id,
|
438
|
+
blocks=new_blocks,
|
439
|
+
data=self.data_to_json(),
|
440
|
+
)
|
441
|
+
|
442
|
+
def with_data(self, new_data: Optional[JsonType]) -> CanvasBuilder:
|
443
|
+
"""
|
444
|
+
Return a new CanvasBuilder with the underlying data replaced.
|
445
|
+
|
446
|
+
This does not call the API, it only assigns state in the CanvasBuilder.
|
447
|
+
"""
|
448
|
+
return CanvasBuilder(
|
449
|
+
app_id=self._source_canvas.app.id,
|
450
|
+
feature_id=self._source_canvas.feature_id,
|
451
|
+
resource_id=self._source_canvas.resource_id,
|
452
|
+
enabled=self._source_canvas.enabled,
|
453
|
+
session_id=self._source_canvas.session_id,
|
454
|
+
blocks=self._source_canvas.blocks,
|
455
|
+
data=new_data,
|
456
|
+
)
|
457
|
+
|
458
|
+
def with_session_id(self, session_id: Optional[str]) -> CanvasBuilder:
|
459
|
+
"""
|
460
|
+
Return a new CanvasBuilder with an optional session_id set.
|
461
|
+
|
462
|
+
This does not call the API, it only assigns state in the CanvasBuilder.
|
463
|
+
"""
|
464
|
+
return CanvasBuilder(
|
465
|
+
app_id=self._source_canvas.app.id,
|
466
|
+
feature_id=self._source_canvas.feature_id,
|
467
|
+
resource_id=self._source_canvas.resource_id,
|
468
|
+
enabled=self._source_canvas.enabled,
|
469
|
+
session_id=session_id,
|
470
|
+
blocks=self._source_canvas.blocks,
|
471
|
+
data=self.data_to_json(),
|
472
|
+
)
|
545
473
|
|
546
474
|
def inputs_to_dict(self) -> Dict[str, Union[str, List[str]]]:
|
547
475
|
"""
|
@@ -605,7 +533,7 @@ class CanvasBuilder:
|
|
605
533
|
|
606
534
|
def inputs_to_dict_multi_value(self) -> Dict[str, List[str]]:
|
607
535
|
"""
|
608
|
-
Read Inputs to dict, but only for
|
536
|
+
Read Inputs to dict, but only for multivalued blocks.
|
609
537
|
|
610
538
|
Return a dictionary of {block_id: block_value} for all blocks on the canvas with multivalued input values.
|
611
539
|
Blocks that only have read attributes are omitted. Excludes TableUiBlock.
|
@@ -631,9 +559,9 @@ class CanvasBuilder:
|
|
631
559
|
|
632
560
|
def _values_from_blocks(
|
633
561
|
self,
|
634
|
-
blocks: List[
|
562
|
+
blocks: List[UiBlock],
|
635
563
|
existing_keys: Optional[List[str]] = None,
|
636
|
-
included_classes: Optional[Set[Type[
|
564
|
+
included_classes: Optional[Set[Type[UiBlock]]] = None,
|
637
565
|
) -> Dict[str, Union[str, List[str]]]:
|
638
566
|
existing_keys = existing_keys if existing_keys else []
|
639
567
|
values: Dict[str, Union[str, List[str]]] = dict()
|
@@ -670,6 +598,7 @@ class CanvasBuilder:
|
|
670
598
|
enabled=self._source_canvas.enabled,
|
671
599
|
session_id=self._source_canvas.session_id,
|
672
600
|
blocks=[_ui_block_to_update(block) for block in self._source_canvas.blocks],
|
601
|
+
data=self._source_canvas.data,
|
673
602
|
)
|
674
603
|
|
675
604
|
def to_create(self) -> AppCanvasCreate:
|
@@ -681,18 +610,30 @@ class CanvasBuilder:
|
|
681
610
|
enabled=self._source_canvas.enabled,
|
682
611
|
session_id=self._source_canvas.session_id,
|
683
612
|
blocks=[_ui_block_to_create(block) for block in self._source_canvas.blocks],
|
613
|
+
data=self._source_canvas.data,
|
684
614
|
)
|
685
615
|
|
686
616
|
@property
|
687
|
-
def blocks(self) ->
|
617
|
+
def blocks(self) -> CanvasBuilderBlockStream:
|
688
618
|
"""
|
689
619
|
Blocks.
|
690
620
|
|
691
621
|
Return a stream of blocks which can be iterated and operated on to mutate the canvas
|
692
622
|
stored by the builder.
|
693
623
|
"""
|
694
|
-
return
|
624
|
+
return CanvasBuilderBlockStream.from_builder(self)
|
625
|
+
|
626
|
+
def data_to_json(self) -> Optional[JsonType]:
|
627
|
+
"""
|
628
|
+
Convert Canvas data to JSON.
|
629
|
+
|
630
|
+
Return a JSON object parsed from the string of the canvas's `data`, if present. Otherwise, return None.
|
631
|
+
"""
|
632
|
+
return json.loads(self._source_canvas.data) if self._source_canvas.data is not None else None
|
633
|
+
|
634
|
+
def __eq__(self, other) -> bool:
|
635
|
+
return isinstance(other, CanvasBuilder) and self._source_canvas == other._source_canvas
|
695
636
|
|
696
637
|
|
697
|
-
def _is_included_class(included_classes: Set[Type[
|
638
|
+
def _is_included_class(included_classes: Set[Type[UiBlock]], target_class: UiBlock) -> bool:
|
698
639
|
return isinstance(target_class, tuple(c for c in included_classes))
|