benchling-sdk 1.10.0a5__py3-none-any.whl → 1.10.0a7__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/framework.py +34 -0
- benchling_sdk/apps/config/__init__.py +0 -3
- benchling_sdk/apps/config/decryption_provider.py +0 -3
- benchling_sdk/apps/config/framework.py +12 -11
- benchling_sdk/apps/{helpers/config_helpers.py → config/helpers.py} +16 -97
- benchling_sdk/apps/config/mock_config.py +68 -68
- benchling_sdk/apps/status/framework.py +1 -21
- benchling_sdk/apps/status/helpers.py +20 -0
- benchling_sdk/apps/status/types.py +1 -1
- benchling_sdk/apps/types.py +3 -0
- benchling_sdk/services/v2/stable/assay_result_service.py +18 -0
- {benchling_sdk-1.10.0a5.dist-info → benchling_sdk-1.10.0a7.dist-info}/METADATA +2 -2
- {benchling_sdk-1.10.0a5.dist-info → benchling_sdk-1.10.0a7.dist-info}/RECORD +15 -14
- benchling_sdk/apps/config/scalars.py +0 -190
- {benchling_sdk-1.10.0a5.dist-info → benchling_sdk-1.10.0a7.dist-info}/LICENSE +0 -0
- {benchling_sdk-1.10.0a5.dist-info → benchling_sdk-1.10.0a7.dist-info}/WHEEL +0 -0
@@ -1,5 +1,6 @@
|
|
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
|
@@ -13,6 +14,7 @@ from benchling_sdk.apps.canvas.types import (
|
|
13
14
|
UiBlock,
|
14
15
|
UiBlockType,
|
15
16
|
)
|
17
|
+
from benchling_sdk.apps.types import JsonType
|
16
18
|
from benchling_sdk.models import (
|
17
19
|
AppCanvas,
|
18
20
|
AppCanvasApp,
|
@@ -366,6 +368,7 @@ class CanvasBuilder:
|
|
366
368
|
enabled: bool = True,
|
367
369
|
session_id: Optional[str] = None,
|
368
370
|
blocks: Optional[List[UiBlock]] = None,
|
371
|
+
data: Optional[JsonType] = None,
|
369
372
|
):
|
370
373
|
"""
|
371
374
|
Init AppCanvas.
|
@@ -379,6 +382,7 @@ class CanvasBuilder:
|
|
379
382
|
enabled=enabled,
|
380
383
|
session_id=session_id,
|
381
384
|
blocks=blocks if blocks else [],
|
385
|
+
data=json.dumps(data) if data is not None else None,
|
382
386
|
)
|
383
387
|
|
384
388
|
@classmethod
|
@@ -395,6 +399,7 @@ class CanvasBuilder:
|
|
395
399
|
enabled=canvas.enabled,
|
396
400
|
session_id=canvas.session_id,
|
397
401
|
blocks=canvas.blocks,
|
402
|
+
data=json.loads(canvas.data) if canvas.data is not None else None,
|
398
403
|
)
|
399
404
|
|
400
405
|
def _with_enabled(self, value: bool) -> CanvasBuilder:
|
@@ -406,6 +411,7 @@ class CanvasBuilder:
|
|
406
411
|
enabled=value,
|
407
412
|
session_id=self._source_canvas.session_id,
|
408
413
|
blocks=self._source_canvas.blocks,
|
414
|
+
data=self._source_canvas.data,
|
409
415
|
)
|
410
416
|
|
411
417
|
def with_enabled(self, enabled: bool = True) -> CanvasBuilder:
|
@@ -430,6 +436,23 @@ class CanvasBuilder:
|
|
430
436
|
enabled=self._source_canvas.enabled,
|
431
437
|
session_id=self._source_canvas.session_id,
|
432
438
|
blocks=new_blocks,
|
439
|
+
data=self._source_canvas.data,
|
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,
|
433
456
|
)
|
434
457
|
|
435
458
|
def with_session_id(self, session_id: Optional[str]) -> CanvasBuilder:
|
@@ -445,6 +468,7 @@ class CanvasBuilder:
|
|
445
468
|
enabled=self._source_canvas.enabled,
|
446
469
|
session_id=session_id,
|
447
470
|
blocks=self._source_canvas.blocks,
|
471
|
+
data=self._source_canvas.data,
|
448
472
|
)
|
449
473
|
|
450
474
|
def inputs_to_dict(self) -> Dict[str, Union[str, List[str]]]:
|
@@ -574,6 +598,7 @@ class CanvasBuilder:
|
|
574
598
|
enabled=self._source_canvas.enabled,
|
575
599
|
session_id=self._source_canvas.session_id,
|
576
600
|
blocks=[_ui_block_to_update(block) for block in self._source_canvas.blocks],
|
601
|
+
data=self._source_canvas.data,
|
577
602
|
)
|
578
603
|
|
579
604
|
def to_create(self) -> AppCanvasCreate:
|
@@ -585,6 +610,7 @@ class CanvasBuilder:
|
|
585
610
|
enabled=self._source_canvas.enabled,
|
586
611
|
session_id=self._source_canvas.session_id,
|
587
612
|
blocks=[_ui_block_to_create(block) for block in self._source_canvas.blocks],
|
613
|
+
data=self._source_canvas.data,
|
588
614
|
)
|
589
615
|
|
590
616
|
@property
|
@@ -597,6 +623,14 @@ class CanvasBuilder:
|
|
597
623
|
"""
|
598
624
|
return CanvasBuilderBlockStream.from_builder(self)
|
599
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
|
+
|
600
634
|
|
601
635
|
def _is_included_class(included_classes: Set[Type[UiBlock]], target_class: UiBlock) -> bool:
|
602
636
|
return isinstance(target_class, tuple(c for c in included_classes))
|
@@ -11,9 +11,6 @@ class BaseDecryptionProvider(ABC):
|
|
11
11
|
Various implementations might use AWS KMS, Azure, etc.
|
12
12
|
"""
|
13
13
|
|
14
|
-
# TODO BNCH-52772 should we loosen this method to accept None and not attempt decryption,
|
15
|
-
# now that config is no longer type safe?
|
16
|
-
|
17
14
|
@abstractmethod
|
18
15
|
def decrypt(self, ciphertext: str) -> str:
|
19
16
|
"""
|
@@ -77,7 +77,8 @@ class BenchlingConfigProvider(ConfigProvider):
|
|
77
77
|
|
78
78
|
# Eager load all config items for now since we don't yet have a way of lazily querying by path
|
79
79
|
all_config_pages = list(app_pages)
|
80
|
-
# Punt on UnknownType for now as apps using manifests with new types +
|
80
|
+
# Punt on UnknownType for now as apps using manifests with new types +
|
81
|
+
# older client could lead to unpredictable results
|
81
82
|
all_config_items = [
|
82
83
|
_supported_config_item(config_item) for page in all_config_pages for config_item in page
|
83
84
|
]
|
@@ -220,13 +221,13 @@ class ConfigItemStore:
|
|
220
221
|
"""
|
221
222
|
Dependency Link Store.
|
222
223
|
|
223
|
-
Marshals an app configuration from the configuration provider into an
|
224
|
+
Marshals an app configuration from the configuration provider into an indexed structure.
|
224
225
|
Only retrieves app configuration once unless its cache is invalidated.
|
225
226
|
"""
|
226
227
|
|
227
228
|
_configuration_provider: ConfigProvider
|
228
229
|
_configuration: Optional[List[ConfigurationReference]] = None
|
229
|
-
|
230
|
+
_configuration_dict: Optional[Dict[ConfigItemPath, ConfigItemWrapper]] = None
|
230
231
|
_array_path_row_names: Dict[Tuple[str, ...], OrderedSet[str]] = dict()
|
231
232
|
|
232
233
|
def __init__(self, configuration_provider: ConfigProvider):
|
@@ -252,17 +253,17 @@ class ConfigItemStore:
|
|
252
253
|
return self._configuration
|
253
254
|
|
254
255
|
@property
|
255
|
-
def
|
256
|
+
def configuration_path_dict(self) -> Dict[ConfigItemPath, ConfigItemWrapper]:
|
256
257
|
"""
|
257
258
|
Config links.
|
258
259
|
|
259
|
-
Return a
|
260
|
+
Return a dict of configuration item paths to their corresponding configuration items.
|
260
261
|
"""
|
261
|
-
if not self.
|
262
|
-
self.
|
262
|
+
if not self._configuration_dict:
|
263
|
+
self._configuration_dict = {
|
263
264
|
tuple(item.path): ConfigItemWrapper(item, item.path) for item in self.configuration
|
264
265
|
}
|
265
|
-
return self.
|
266
|
+
return self._configuration_dict
|
266
267
|
|
267
268
|
def config_by_path(self, path: List[str]) -> ConfigItemWrapper:
|
268
269
|
"""
|
@@ -272,7 +273,7 @@ class ConfigItemStore:
|
|
272
273
|
"""
|
273
274
|
# Since we eager load all config now, we know that missing path means it's not configured in Benchling
|
274
275
|
# Later if we support lazy loading, we'll need to differentiate what's in our cache versus missing
|
275
|
-
return self.
|
276
|
+
return self.configuration_path_dict.get(tuple(path), ConfigItemWrapper(None, path))
|
276
277
|
|
277
278
|
def config_keys_by_path(self, path: List[str]) -> OrderedSet[str]:
|
278
279
|
"""
|
@@ -296,7 +297,7 @@ class ConfigItemStore:
|
|
296
297
|
self._array_path_row_names[path_tuple] = OrderedSet(
|
297
298
|
[
|
298
299
|
config_item.path[len(path)]
|
299
|
-
# Use the list instead of
|
300
|
+
# Use the list instead of configuration_dict to preserve order
|
300
301
|
for config_item in self.configuration
|
301
302
|
# The +1 is the name of the array row
|
302
303
|
if len(config_item.path) >= len(path) + 1
|
@@ -330,7 +331,7 @@ class ConfigItemStore:
|
|
330
331
|
Will force retrieval of configuration from the ConfigProvider the next time the link store is accessed.
|
331
332
|
"""
|
332
333
|
self._configuration = None
|
333
|
-
self.
|
334
|
+
self._configuration_dict = None
|
334
335
|
self._array_path_row_names = dict()
|
335
336
|
|
336
337
|
|
@@ -1,7 +1,6 @@
|
|
1
|
-
from datetime import
|
1
|
+
from datetime import datetime
|
2
2
|
from typing import List, Optional, Union
|
3
3
|
|
4
|
-
from benchling_api_client.v2.beta.models.app_config_field_type import AppConfigFieldType
|
5
4
|
from benchling_api_client.v2.beta.models.base_manifest_config import BaseManifestConfig
|
6
5
|
from benchling_api_client.v2.beta.models.dropdown_dependency import DropdownDependency
|
7
6
|
from benchling_api_client.v2.beta.models.dropdown_dependency_types import DropdownDependencyTypes
|
@@ -29,92 +28,7 @@ from benchling_api_client.v2.beta.models.workflow_task_schema_dependency_type im
|
|
29
28
|
from benchling_api_client.v2.extensions import UnknownType
|
30
29
|
from benchling_api_client.v2.stable.extensions import NotPresentError
|
31
30
|
|
32
|
-
|
33
|
-
from benchling_sdk.models import (
|
34
|
-
AaSequence,
|
35
|
-
AssayResult,
|
36
|
-
AssayRun,
|
37
|
-
Box,
|
38
|
-
Container,
|
39
|
-
CustomEntity,
|
40
|
-
DnaOligo,
|
41
|
-
DnaSequence,
|
42
|
-
Entry,
|
43
|
-
Location,
|
44
|
-
Mixture,
|
45
|
-
Molecule,
|
46
|
-
Plate,
|
47
|
-
Request,
|
48
|
-
RnaOligo,
|
49
|
-
RnaSequence,
|
50
|
-
WorkflowTask,
|
51
|
-
)
|
52
|
-
|
53
|
-
_MODEL_TYPES_FROM_SCHEMA_TYPE = {
|
54
|
-
SchemaDependencyTypes.CONTAINER_SCHEMA: Container,
|
55
|
-
SchemaDependencyTypes.PLATE_SCHEMA: Plate,
|
56
|
-
SchemaDependencyTypes.BOX_SCHEMA: Box,
|
57
|
-
SchemaDependencyTypes.LOCATION_SCHEMA: Location,
|
58
|
-
SchemaDependencyTypes.ENTRY_SCHEMA: Entry,
|
59
|
-
SchemaDependencyTypes.REQUEST_SCHEMA: Request,
|
60
|
-
SchemaDependencyTypes.RESULT_SCHEMA: AssayResult,
|
61
|
-
SchemaDependencyTypes.RUN_SCHEMA: AssayRun,
|
62
|
-
SchemaDependencyTypes.WORKFLOW_TASK_SCHEMA: WorkflowTask,
|
63
|
-
}
|
64
|
-
|
65
|
-
|
66
|
-
_SCALAR_TYPES_FROM_CONFIG = {
|
67
|
-
ScalarConfigTypes.BOOLEAN: bool,
|
68
|
-
ScalarConfigTypes.DATE: date,
|
69
|
-
ScalarConfigTypes.DATETIME: datetime,
|
70
|
-
ScalarConfigTypes.FLOAT: float,
|
71
|
-
ScalarConfigTypes.INTEGER: int,
|
72
|
-
ScalarConfigTypes.JSON: JsonType,
|
73
|
-
ScalarConfigTypes.TEXT: str,
|
74
|
-
}
|
75
|
-
|
76
|
-
|
77
|
-
_FIELD_SCALAR_TYPES_FROM_CONFIG = {
|
78
|
-
AppConfigFieldType.BOOLEAN: bool,
|
79
|
-
AppConfigFieldType.DATE: date,
|
80
|
-
AppConfigFieldType.DATETIME: datetime,
|
81
|
-
AppConfigFieldType.FLOAT: float,
|
82
|
-
AppConfigFieldType.INTEGER: int,
|
83
|
-
AppConfigFieldType.JSON: JsonType,
|
84
|
-
AppConfigFieldType.TEXT: str,
|
85
|
-
}
|
86
|
-
|
87
|
-
|
88
|
-
ModelType = Union[AssayResult, AssayRun, Box, Container, Entry, Location, Plate, Request]
|
89
|
-
|
90
|
-
_INSTANCE_FROM_SCHEMA_SUBTYPE = {
|
91
|
-
SchemaDependencySubtypes.AA_SEQUENCE: AaSequence,
|
92
|
-
SchemaDependencySubtypes.CUSTOM_ENTITY: CustomEntity,
|
93
|
-
SchemaDependencySubtypes.DNA_SEQUENCE: DnaSequence,
|
94
|
-
SchemaDependencySubtypes.DNA_OLIGO: DnaOligo,
|
95
|
-
SchemaDependencySubtypes.MIXTURE: Mixture,
|
96
|
-
SchemaDependencySubtypes.MOLECULE: Molecule,
|
97
|
-
SchemaDependencySubtypes.RNA_OLIGO: RnaOligo,
|
98
|
-
SchemaDependencySubtypes.RNA_SEQUENCE: RnaSequence,
|
99
|
-
}
|
100
|
-
|
101
|
-
EntitySubtype = Union[
|
102
|
-
AaSequence, CustomEntity, DnaOligo, DnaSequence, Mixture, Molecule, RnaOligo, RnaSequence
|
103
|
-
]
|
104
|
-
|
105
|
-
AnyDependency = Union[
|
106
|
-
BaseManifestConfig,
|
107
|
-
DropdownDependency,
|
108
|
-
EntitySchemaDependency,
|
109
|
-
FieldDefinitionsManifest,
|
110
|
-
ManifestArrayConfig,
|
111
|
-
ManifestScalarConfig,
|
112
|
-
ResourceDependency,
|
113
|
-
SchemaDependency,
|
114
|
-
WorkflowTaskSchemaDependency,
|
115
|
-
]
|
116
|
-
|
117
|
-
ArrayElementDependency = Union[
|
31
|
+
_ArrayElementDependency = Union[
|
118
32
|
SchemaDependency,
|
119
33
|
EntitySchemaDependency,
|
120
34
|
WorkflowTaskSchemaDependency,
|
@@ -124,13 +38,13 @@ ArrayElementDependency = Union[
|
|
124
38
|
]
|
125
39
|
|
126
40
|
|
127
|
-
class
|
41
|
+
class _UnsupportedSubTypeError(Exception):
|
128
42
|
"""Error when an unsupported subtype is encountered."""
|
129
43
|
|
130
44
|
pass
|
131
45
|
|
132
46
|
|
133
|
-
def
|
47
|
+
def _field_definitions_from_dependency(
|
134
48
|
dependency: Union[
|
135
49
|
EntitySchemaDependency,
|
136
50
|
SchemaDependency,
|
@@ -148,7 +62,7 @@ def field_definitions_from_dependency(
|
|
148
62
|
return []
|
149
63
|
|
150
64
|
|
151
|
-
def
|
65
|
+
def _element_definition_from_dependency(dependency: ManifestArrayConfig) -> List[_ArrayElementDependency]:
|
152
66
|
"""Safely return an element definition as a list of dependencies from an array dependency or empty list."""
|
153
67
|
try:
|
154
68
|
if hasattr(dependency, "element_definition"):
|
@@ -161,7 +75,7 @@ def element_definition_from_dependency(dependency: ManifestArrayConfig) -> List[
|
|
161
75
|
return []
|
162
76
|
|
163
77
|
|
164
|
-
def
|
78
|
+
def _enum_from_dependency(
|
165
79
|
dependency: Union[
|
166
80
|
ManifestFloatScalarConfig,
|
167
81
|
ManifestIntegerScalarConfig,
|
@@ -180,8 +94,8 @@ def enum_from_dependency(
|
|
180
94
|
|
181
95
|
# TODO BNCH-57036 All element definitions currently deserialize to UnknownType. Hack around this temporarily
|
182
96
|
def _fix_element_definition_deserialization(
|
183
|
-
element: Union[UnknownType,
|
184
|
-
) ->
|
97
|
+
element: Union[UnknownType, _ArrayElementDependency]
|
98
|
+
) -> _ArrayElementDependency:
|
185
99
|
if isinstance(element, UnknownType):
|
186
100
|
if "type" in element.value:
|
187
101
|
element_type = element.value["type"]
|
@@ -201,7 +115,7 @@ def _fix_element_definition_deserialization(
|
|
201
115
|
return element
|
202
116
|
|
203
117
|
|
204
|
-
def
|
118
|
+
def _workflow_task_schema_output_from_dependency(
|
205
119
|
dependency: WorkflowTaskSchemaDependency,
|
206
120
|
) -> Optional[WorkflowTaskSchemaDependencyOutput]:
|
207
121
|
"""Safely return a workflow task schema output from a workflow task schema or None."""
|
@@ -214,7 +128,7 @@ def workflow_task_schema_output_from_dependency(
|
|
214
128
|
return None
|
215
129
|
|
216
130
|
|
217
|
-
def
|
131
|
+
def _options_from_dependency(dependency: DropdownDependency) -> List[BaseManifestConfig]:
|
218
132
|
"""Safely return a list of options from a dropdown dependency or empty list."""
|
219
133
|
try:
|
220
134
|
if hasattr(dependency, "options"):
|
@@ -225,7 +139,7 @@ def options_from_dependency(dependency: DropdownDependency) -> List[BaseManifest
|
|
225
139
|
return []
|
226
140
|
|
227
141
|
|
228
|
-
def
|
142
|
+
def _subtype_from_entity_schema_dependency(
|
229
143
|
dependency: EntitySchemaDependency,
|
230
144
|
) -> Optional[SchemaDependencySubtypes]:
|
231
145
|
"""Safely return an entity schema dependency's subtype, if present."""
|
@@ -236,3 +150,8 @@ def subtype_from_entity_schema_dependency(
|
|
236
150
|
except NotPresentError:
|
237
151
|
pass
|
238
152
|
return None
|
153
|
+
|
154
|
+
|
155
|
+
def datetime_config_value_to_str(value: datetime) -> str:
|
156
|
+
"""Convert a datetime value to a valid string accepted by a datetime app config item."""
|
157
|
+
return value.strftime("%Y-%m-%d %I:%M:%S %p")
|
@@ -4,7 +4,7 @@ from datetime import date, datetime
|
|
4
4
|
import json
|
5
5
|
import random
|
6
6
|
import string
|
7
|
-
from typing import Dict, get_args, List, Optional, Protocol,
|
7
|
+
from typing import cast, Dict, get_args, List, Optional, Protocol, Union
|
8
8
|
|
9
9
|
from benchling_api_client.v2.beta.models.base_manifest_config import BaseManifestConfig
|
10
10
|
from benchling_api_client.v2.beta.models.benchling_app_manifest import BenchlingAppManifest
|
@@ -34,29 +34,20 @@ from benchling_api_client.v2.extensions import UnknownType
|
|
34
34
|
from benchling_api_client.v2.stable.types import UNSET, Unset
|
35
35
|
|
36
36
|
from benchling_sdk.apps.config.decryption_provider import BaseDecryptionProvider
|
37
|
+
from benchling_sdk.apps.config.errors import UnsupportedConfigItemError
|
37
38
|
from benchling_sdk.apps.config.framework import _supported_config_item, ConfigItemStore, StaticConfigProvider
|
38
|
-
from benchling_sdk.apps.config.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
ScalarDefinition,
|
47
|
-
ScalarType,
|
48
|
-
SecureTextScalar,
|
49
|
-
TextScalar,
|
39
|
+
from benchling_sdk.apps.config.helpers import (
|
40
|
+
_element_definition_from_dependency,
|
41
|
+
_enum_from_dependency,
|
42
|
+
_field_definitions_from_dependency,
|
43
|
+
_options_from_dependency,
|
44
|
+
_subtype_from_entity_schema_dependency,
|
45
|
+
_workflow_task_schema_output_from_dependency,
|
46
|
+
datetime_config_value_to_str,
|
50
47
|
)
|
51
48
|
from benchling_sdk.apps.config.types import ConfigurationReference
|
52
|
-
from benchling_sdk.apps.
|
53
|
-
|
54
|
-
enum_from_dependency,
|
55
|
-
field_definitions_from_dependency,
|
56
|
-
options_from_dependency,
|
57
|
-
subtype_from_entity_schema_dependency,
|
58
|
-
workflow_task_schema_output_from_dependency,
|
59
|
-
)
|
49
|
+
from benchling_sdk.apps.types import JsonType
|
50
|
+
from benchling_sdk.helpers.logging_helpers import log_stability_warning, StabilityLevel
|
60
51
|
from benchling_sdk.models import (
|
61
52
|
AppConfigItem,
|
62
53
|
ArrayElementAppConfigItem,
|
@@ -98,6 +89,8 @@ ManifestDependencies = Union[
|
|
98
89
|
UnknownType,
|
99
90
|
]
|
100
91
|
|
92
|
+
log_stability_warning(StabilityLevel.BETA)
|
93
|
+
|
101
94
|
|
102
95
|
class MockDecryptionFunction(Protocol):
|
103
96
|
"""Mock out a decryption function for use with secure text."""
|
@@ -296,7 +289,7 @@ def mock_datetime_app_config_item(path: List[str], value: Optional[datetime]) ->
|
|
296
289
|
"""Mock a datetime app config item with a path and specified value."""
|
297
290
|
return DatetimeAppConfigItem(
|
298
291
|
path=path,
|
299
|
-
value=value
|
292
|
+
value=datetime_config_value_to_str(value) if value else None,
|
300
293
|
type=DatetimeAppConfigItemType.DATETIME,
|
301
294
|
id=_random_string("aci_"),
|
302
295
|
)
|
@@ -354,9 +347,10 @@ def mock_text_app_config_item(path: List[str], value: Optional[str]) -> TextAppC
|
|
354
347
|
|
355
348
|
def _mock_dependency(
|
356
349
|
dependency: ManifestDependencies,
|
357
|
-
parent_path: List[str] =
|
350
|
+
parent_path: Optional[List[str]] = None,
|
358
351
|
) -> List[AppConfigItem]:
|
359
352
|
"""Mock a dependency from its manifest definition."""
|
353
|
+
parent_path = parent_path if parent_path else []
|
360
354
|
# MyPy has trouble inferring lists with [config_item] + sub_items so use the syntax like:
|
361
355
|
# [*[config_item], *sub_items]
|
362
356
|
# See https://github.com/python/mypy/issues/3933#issuecomment-808739063
|
@@ -371,12 +365,12 @@ def _mock_dependency(
|
|
371
365
|
)
|
372
366
|
sub_items = [
|
373
367
|
_mock_subdependency(subdependency, dependency, parent_path=parent_path)
|
374
|
-
for subdependency in
|
368
|
+
for subdependency in _options_from_dependency(dependency)
|
375
369
|
]
|
376
370
|
return [*[config_item], *sub_items]
|
377
371
|
elif isinstance(dependency, EntitySchemaDependency):
|
378
372
|
linked_resource_id = _random_string("val_")
|
379
|
-
subtype =
|
373
|
+
subtype = _subtype_from_entity_schema_dependency(dependency)
|
380
374
|
optional_subtype: Union[SchemaDependencySubtypes, Unset] = (
|
381
375
|
_convert_entity_subtype(subtype) if subtype is not None else UNSET
|
382
376
|
)
|
@@ -390,7 +384,7 @@ def _mock_dependency(
|
|
390
384
|
)
|
391
385
|
sub_items = [
|
392
386
|
_mock_subdependency(subdependency, dependency, parent_path=parent_path)
|
393
|
-
for subdependency in
|
387
|
+
for subdependency in _field_definitions_from_dependency(dependency)
|
394
388
|
]
|
395
389
|
return [*[entity_item], *sub_items]
|
396
390
|
elif isinstance(dependency, SchemaDependency):
|
@@ -404,7 +398,7 @@ def _mock_dependency(
|
|
404
398
|
)
|
405
399
|
sub_items = [
|
406
400
|
_mock_subdependency(subdependency, dependency, parent_path=parent_path)
|
407
|
-
for subdependency in
|
401
|
+
for subdependency in _field_definitions_from_dependency(dependency)
|
408
402
|
]
|
409
403
|
return [*[config_item], *sub_items]
|
410
404
|
elif isinstance(dependency, WorkflowTaskSchemaDependency):
|
@@ -418,11 +412,11 @@ def _mock_dependency(
|
|
418
412
|
)
|
419
413
|
sub_items = [
|
420
414
|
_mock_subdependency(subdependency, dependency, parent_path=parent_path)
|
421
|
-
for subdependency in
|
415
|
+
for subdependency in _field_definitions_from_dependency(dependency)
|
422
416
|
]
|
423
|
-
workflow_task_output =
|
417
|
+
workflow_task_output = _workflow_task_schema_output_from_dependency(dependency)
|
424
418
|
if workflow_task_output:
|
425
|
-
output_fields =
|
419
|
+
output_fields = _field_definitions_from_dependency(workflow_task_output)
|
426
420
|
output_items = [
|
427
421
|
_mock_workflow_output_subdependency(subdependency, dependency, parent_path=parent_path)
|
428
422
|
for subdependency in output_fields
|
@@ -458,39 +452,40 @@ def _convert_entity_subtype(manifest_subtype: SchemaDependencySubtypesBeta) -> S
|
|
458
452
|
|
459
453
|
|
460
454
|
def _mock_scalar_dependency(
|
461
|
-
dependency: ManifestScalarConfig, parent_path: List[str] =
|
455
|
+
dependency: ManifestScalarConfig, parent_path: Optional[List[str]] = None
|
462
456
|
) -> AppConfigItem:
|
457
|
+
parent_path = parent_path if parent_path else []
|
463
458
|
if isinstance(dependency, ManifestBooleanScalarConfig):
|
464
|
-
bool_value =
|
459
|
+
bool_value = cast(bool, _mock_scalar_value(dependency))
|
465
460
|
bool_config = mock_bool_app_config_item([dependency.name], bool_value)
|
466
461
|
return _append_config_item_path(bool_config, parent_path)
|
467
462
|
elif isinstance(dependency, ManifestDateScalarConfig):
|
468
|
-
date_value =
|
463
|
+
date_value = cast(date, _mock_scalar_value(dependency))
|
469
464
|
date_config = mock_date_app_config_item([dependency.name], date_value)
|
470
465
|
return _append_config_item_path(date_config, parent_path)
|
471
466
|
elif isinstance(dependency, ManifestDatetimeScalarConfig):
|
472
|
-
datetime_value =
|
467
|
+
datetime_value = cast(datetime, _mock_scalar_value(dependency))
|
473
468
|
datetime_config = mock_datetime_app_config_item([dependency.name], datetime_value)
|
474
469
|
return _append_config_item_path(datetime_config, parent_path)
|
475
470
|
elif isinstance(dependency, ManifestFloatScalarConfig):
|
476
|
-
float_value =
|
471
|
+
float_value = cast(float, _mock_scalar_value(dependency))
|
477
472
|
float_config = mock_float_app_config_item([dependency.name], float_value)
|
478
473
|
return _append_config_item_path(float_config, parent_path)
|
479
474
|
elif isinstance(dependency, ManifestIntegerScalarConfig):
|
480
|
-
int_value =
|
475
|
+
int_value = cast(int, _mock_scalar_value(dependency))
|
481
476
|
int_config = mock_int_app_config_item([dependency.name], int_value)
|
482
477
|
return _append_config_item_path(int_config, parent_path)
|
483
478
|
elif isinstance(dependency, ManifestJsonScalarConfig):
|
484
|
-
json_value =
|
479
|
+
json_value = cast(JsonType, _mock_scalar_value(dependency))
|
485
480
|
json_config = mock_json_app_config_item([dependency.name], json_value)
|
486
481
|
return _append_config_item_path(json_config, parent_path)
|
487
482
|
elif isinstance(dependency, ManifestSecureTextScalarConfig):
|
488
|
-
secure_text_value =
|
483
|
+
secure_text_value = cast(str, _mock_scalar_value(dependency))
|
489
484
|
secure_text_config = mock_secure_text_app_config_item([dependency.name], secure_text_value)
|
490
485
|
return _append_config_item_path(secure_text_config, parent_path)
|
491
486
|
else:
|
492
487
|
assert not isinstance(dependency, UnknownType), f"Unable to mock unknown type {dependency}"
|
493
|
-
text_value =
|
488
|
+
text_value = cast(str, _mock_scalar_value(dependency))
|
494
489
|
text_config = mock_text_app_config_item([dependency.name], text_value)
|
495
490
|
return _append_config_item_path(text_config, parent_path)
|
496
491
|
|
@@ -503,12 +498,13 @@ def _append_config_item_path(config_item: AppConfigItem, parent_path: List[str])
|
|
503
498
|
|
504
499
|
|
505
500
|
def _mock_array_dependency(
|
506
|
-
dependency: ManifestArrayConfig, parent_path: List[str] =
|
501
|
+
dependency: ManifestArrayConfig, parent_path: Optional[List[str]] = None, rows: int = 1
|
507
502
|
) -> List[AppConfigItem]:
|
508
503
|
config_rows = []
|
504
|
+
parent_path = parent_path if parent_path else []
|
509
505
|
for i in range(rows):
|
510
506
|
row = _mock_array_row(dependency, parent_path=parent_path)
|
511
|
-
elements =
|
507
|
+
elements = _element_definition_from_dependency(dependency)
|
512
508
|
element_configs = [_mock_dependency(element, row.path) for element in elements]
|
513
509
|
flattened_configs = [element for sublist in element_configs for element in sublist]
|
514
510
|
config_rows.append(row)
|
@@ -516,8 +512,9 @@ def _mock_array_dependency(
|
|
516
512
|
return config_rows
|
517
513
|
|
518
514
|
|
519
|
-
def _mock_array_row(dependency: ManifestArrayConfig, parent_path: List[str] =
|
515
|
+
def _mock_array_row(dependency: ManifestArrayConfig, parent_path: Optional[List[str]] = None):
|
520
516
|
row_name = _random_string("Row ")
|
517
|
+
parent_path = parent_path if parent_path else []
|
521
518
|
return ArrayElementAppConfigItem(
|
522
519
|
id=_random_string("aci_"),
|
523
520
|
path=parent_path + [dependency.name, row_name],
|
@@ -526,25 +523,16 @@ def _mock_array_row(dependency: ManifestArrayConfig, parent_path: List[str] = li
|
|
526
523
|
)
|
527
524
|
|
528
525
|
|
529
|
-
def
|
530
|
-
dependency: ManifestScalarConfig, scalar_definition_type: Type[ScalarDefinition[ScalarType]]
|
531
|
-
) -> Optional[ScalarType]:
|
532
|
-
assert not isinstance(dependency, UnknownType), f"Unable to mock unknown type {dependency}"
|
533
|
-
# These types should be equivalent and this appeases MyPy
|
534
|
-
mocked_value_type = ScalarConfigTypes(dependency.type)
|
535
|
-
mocked_value_str = (
|
536
|
-
_mock_scalar_with_enum(dependency)
|
537
|
-
if _is_scalar_with_enum(dependency)
|
538
|
-
else _mock_scalar_value(mocked_value_type)
|
539
|
-
)
|
540
|
-
return scalar_definition_type.from_str(mocked_value_str)
|
541
|
-
|
542
|
-
|
543
|
-
def _mock_scalar_with_enum(dependency: ManifestScalarConfig) -> str:
|
526
|
+
def _mock_scalar_with_enum(dependency: ManifestScalarConfig) -> Union[float, int, str]:
|
544
527
|
assert isinstance(
|
545
528
|
dependency, (ManifestFloatScalarConfig, ManifestIntegerScalarConfig, ManifestTextScalarConfig)
|
546
529
|
)
|
547
|
-
|
530
|
+
value = random.choice(dependency.enum)
|
531
|
+
if isinstance(dependency, ManifestFloatScalarConfig):
|
532
|
+
return cast(float, value)
|
533
|
+
elif isinstance(dependency, ManifestIntegerScalarConfig):
|
534
|
+
return cast(int, value)
|
535
|
+
return str(value)
|
548
536
|
|
549
537
|
|
550
538
|
def _is_scalar_with_enum(dependency: ManifestScalarConfig) -> bool:
|
@@ -552,15 +540,16 @@ def _is_scalar_with_enum(dependency: ManifestScalarConfig) -> bool:
|
|
552
540
|
dependency, (ManifestFloatScalarConfig, ManifestIntegerScalarConfig, ManifestTextScalarConfig)
|
553
541
|
):
|
554
542
|
# MyPy doesn't find this to be truthy without a specific len check
|
555
|
-
return len(
|
543
|
+
return len(_enum_from_dependency(dependency)) > 0
|
556
544
|
return False
|
557
545
|
|
558
546
|
|
559
547
|
def _mock_subdependency(
|
560
548
|
subdependency: Union[BaseManifestConfig, FieldDefinitionsManifest],
|
561
549
|
parent_config,
|
562
|
-
parent_path: List[str] =
|
550
|
+
parent_path: Optional[List[str]] = None,
|
563
551
|
) -> AppConfigItem:
|
552
|
+
parent_path = parent_path if parent_path else []
|
564
553
|
if isinstance(parent_config, DropdownDependency):
|
565
554
|
linked_resource_id = _random_string("opt_")
|
566
555
|
return GenericApiIdentifiedAppConfigItem(
|
@@ -587,8 +576,9 @@ def _mock_subdependency(
|
|
587
576
|
def _mock_workflow_output_subdependency(
|
588
577
|
subdependency: Union[BaseManifestConfig, FieldDefinitionsManifest],
|
589
578
|
parent_config,
|
590
|
-
parent_path: List[str] =
|
579
|
+
parent_path: Optional[List[str]] = None,
|
591
580
|
) -> AppConfigItem:
|
581
|
+
parent_path = parent_path if parent_path else []
|
592
582
|
linked_resource_id = _random_string("tsf_")
|
593
583
|
app_config = FieldAppConfigItem(
|
594
584
|
id=_random_string("aci_"),
|
@@ -604,18 +594,28 @@ def _mock_linked_resource(id: str, name: Optional[str] = None) -> LinkedAppConfi
|
|
604
594
|
return LinkedAppConfigResourceSummary(id=id, name=name if name else _random_string("Resource Name"))
|
605
595
|
|
606
596
|
|
607
|
-
def _mock_scalar_value(
|
597
|
+
def _mock_scalar_value(
|
598
|
+
dependency: ManifestScalarConfig,
|
599
|
+
) -> Union[bool, date, datetime, int, float, str, Dict[str, Union[str, float]]]:
|
608
600
|
"""Mock a scalar config value from its manifest definition."""
|
609
|
-
if
|
610
|
-
|
601
|
+
if isinstance(dependency, UnknownType):
|
602
|
+
raise UnsupportedConfigItemError(
|
603
|
+
f"Unable to mock scalar value for unsupported dependency type {dependency}"
|
604
|
+
)
|
605
|
+
# These types should be equivalent and this appeases MyPy
|
606
|
+
scalar_type = ScalarConfigTypes(dependency.type)
|
607
|
+
if _is_scalar_with_enum(dependency):
|
608
|
+
return _mock_scalar_with_enum(dependency)
|
609
|
+
elif scalar_type == scalar_type.BOOLEAN:
|
610
|
+
return True
|
611
611
|
elif scalar_type == scalar_type.DATE:
|
612
|
-
return date.today()
|
612
|
+
return date.today()
|
613
613
|
elif scalar_type == scalar_type.DATETIME:
|
614
|
-
return datetime.now()
|
614
|
+
return datetime.now()
|
615
615
|
elif scalar_type == scalar_type.FLOAT:
|
616
|
-
return
|
616
|
+
return random.random()
|
617
617
|
elif scalar_type == scalar_type.INTEGER:
|
618
|
-
return
|
618
|
+
return random.randint(-1000, 1000)
|
619
619
|
elif scalar_type == scalar_type.JSON:
|
620
620
|
return json.dumps(
|
621
621
|
{_random_string(): [_random_string(), _random_string()], _random_string(): random.random()}
|
@@ -14,9 +14,8 @@ from benchling_sdk.apps.status.errors import (
|
|
14
14
|
SessionClosedError,
|
15
15
|
SessionContextClosedError,
|
16
16
|
)
|
17
|
-
from benchling_sdk.apps.status.types import _ReferencedSessionLinkType
|
18
17
|
from benchling_sdk.errors import BenchlingError
|
19
|
-
from benchling_sdk.helpers.logging_helpers import
|
18
|
+
from benchling_sdk.helpers.logging_helpers import sdk_logger
|
20
19
|
from benchling_sdk.models import (
|
21
20
|
AppCanvasUpdate,
|
22
21
|
AppSession,
|
@@ -35,8 +34,6 @@ if TYPE_CHECKING:
|
|
35
34
|
|
36
35
|
_DEFAULT_APP_ERROR_MESSAGE = "An unexpected error occurred in the app"
|
37
36
|
|
38
|
-
log_stability_warning(StabilityLevel.BETA)
|
39
|
-
|
40
37
|
|
41
38
|
class SessionProvider(Protocol):
|
42
39
|
"""Provide a Benchling App Session to convey app status."""
|
@@ -685,20 +682,3 @@ def continue_session_context(
|
|
685
682
|
context_enter_handler,
|
686
683
|
context_exit_handler,
|
687
684
|
)
|
688
|
-
|
689
|
-
|
690
|
-
def ref(reference: _ReferencedSessionLinkType) -> str:
|
691
|
-
"""
|
692
|
-
Ref.
|
693
|
-
|
694
|
-
Helper method for easily serializing a referenced object into a string embeddable in AppSessionMessageCreate
|
695
|
-
content.
|
696
|
-
|
697
|
-
Example:
|
698
|
-
dna_sequence = benchling.dna_sequences.get_by_id("seq_1234")
|
699
|
-
AppSessionMessageCreate(f"This is my DNA sequence {ref(dna_sequence)} for analysis"
|
700
|
-
"""
|
701
|
-
# Not sure {} are possible in Benchling IDs, but the spec says we're escaping
|
702
|
-
unescape_id = reference.id
|
703
|
-
escaped_id = unescape_id.replace("{", "\\{").replace("}", "\\}")
|
704
|
-
return f"{{id:{escaped_id}}}"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from benchling_sdk.apps.status.types import ReferencedSessionLinkType
|
4
|
+
|
5
|
+
|
6
|
+
def ref(reference: ReferencedSessionLinkType) -> str:
|
7
|
+
"""
|
8
|
+
Ref.
|
9
|
+
|
10
|
+
Helper method for easily serializing a referenced object into a string embeddable in AppSessionMessageCreate
|
11
|
+
content.
|
12
|
+
|
13
|
+
Example:
|
14
|
+
dna_sequence = benchling.dna_sequences.get_by_id("seq_1234")
|
15
|
+
AppSessionMessageCreate(f"This is my DNA sequence {ref(dna_sequence)} for analysis"
|
16
|
+
"""
|
17
|
+
# Not sure {} are possible in Benchling IDs, but the spec says we're escaping
|
18
|
+
unescape_id = reference.id
|
19
|
+
escaped_id = unescape_id.replace("{", "\\{").replace("}", "\\}")
|
20
|
+
return f"{{id:{escaped_id}}}"
|
@@ -23,7 +23,7 @@ from benchling_sdk.models import (
|
|
23
23
|
|
24
24
|
# Taken from CHIP_SUPPORTED_COLUMN_TYPES in Benchling server
|
25
25
|
# Anything we miss, they can still embed the ID themselves in a message
|
26
|
-
|
26
|
+
ReferencedSessionLinkType = Union[
|
27
27
|
AaSequence,
|
28
28
|
Blob,
|
29
29
|
Box,
|
@@ -3,6 +3,7 @@ from typing import Iterable, List, Optional, Union
|
|
3
3
|
from benchling_api_client.v2.stable.api.assay_results import (
|
4
4
|
abort_assay_results_transaction,
|
5
5
|
archive_assay_results,
|
6
|
+
bulk_create_assay_results,
|
6
7
|
bulk_get_assay_results,
|
7
8
|
commit_assay_results_transaction,
|
8
9
|
create_assay_results,
|
@@ -31,10 +32,12 @@ from benchling_sdk.models import (
|
|
31
32
|
AssayResultIdsRequest,
|
32
33
|
AssayResultIdsResponse,
|
33
34
|
AssayResultsArchive,
|
35
|
+
AssayResultsBulkCreateInTableRequest,
|
34
36
|
AssayResultsBulkCreateRequest,
|
35
37
|
AssayResultsCreateResponse,
|
36
38
|
AssayResultsPaginatedList,
|
37
39
|
AssayResultTransactionCreateResponse,
|
40
|
+
AsyncTaskLink,
|
38
41
|
ListAssayResultsSort,
|
39
42
|
)
|
40
43
|
from benchling_sdk.services.v2.base_service import BaseService
|
@@ -196,6 +199,21 @@ class AssayResultService(BaseService):
|
|
196
199
|
response = create_assay_results.sync_detailed(client=self.client, json_body=create_results)
|
197
200
|
return model_from_detailed(response)
|
198
201
|
|
202
|
+
@api_method
|
203
|
+
def bulk_create(
|
204
|
+
self, assay_results: Iterable[AssayResultCreate], table_id: Optional[str] = None
|
205
|
+
) -> AsyncTaskLink:
|
206
|
+
"""
|
207
|
+
Create 1 or more results.
|
208
|
+
|
209
|
+
See https://benchling.com/api/reference#/Assay%20Results/bulkCreateAssayResults
|
210
|
+
"""
|
211
|
+
request_body = AssayResultsBulkCreateInTableRequest(
|
212
|
+
assay_results=list(assay_results), **({"table_id": table_id} if table_id else {})
|
213
|
+
)
|
214
|
+
response = bulk_create_assay_results.sync_detailed(client=self.client, json_body=request_body)
|
215
|
+
return model_from_detailed(response)
|
216
|
+
|
199
217
|
@api_method
|
200
218
|
def archive(self, assay_result_ids: Iterable[str]) -> AssayResultIdsResponse:
|
201
219
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: benchling-sdk
|
3
|
-
Version: 1.10.
|
3
|
+
Version: 1.10.0a7
|
4
4
|
Summary: SDK for interacting with the Benchling Platform.
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: Benchling Support
|
@@ -17,7 +17,7 @@ Provides-Extra: python-jose
|
|
17
17
|
Requires-Dist: PyYAML (>=6.0,<7.0)
|
18
18
|
Requires-Dist: attrs (>=20.1.0,<23)
|
19
19
|
Requires-Dist: backoff (>=1.10.0,<2.0.0)
|
20
|
-
Requires-Dist: benchling-api-client (==2.0.
|
20
|
+
Requires-Dist: benchling-api-client (==2.0.243)
|
21
21
|
Requires-Dist: certifi (>=2022.12.7)
|
22
22
|
Requires-Dist: cryptography (>=41.0.3,<42.0.0) ; extra == "cryptography"
|
23
23
|
Requires-Dist: dataclasses-json (>=0.5.2,<0.6.0)
|
@@ -3,25 +3,26 @@ benchling_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
benchling_sdk/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
benchling_sdk/apps/canvas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
benchling_sdk/apps/canvas/errors.py,sha256=5YTZOhSV-O0WqURjB1a676BIO429drCKfz5aQjsezms,358
|
6
|
-
benchling_sdk/apps/canvas/framework.py,sha256=
|
6
|
+
benchling_sdk/apps/canvas/framework.py,sha256=a6XbCZIUsz4VmOCtu6kZnBQoQiLJtBk2Ndw94J0s4kM,24381
|
7
7
|
benchling_sdk/apps/canvas/types.py,sha256=tmuU0kpzd1pXqxs3X6x5kjWpCZJrJMb6hnfN1CbtFG4,3613
|
8
|
-
benchling_sdk/apps/config/__init__.py,sha256=
|
8
|
+
benchling_sdk/apps/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
benchling_sdk/apps/config/cryptography_helpers.py,sha256=VCzgQURLAitYjcjdwFzMPSKZ7MOD6ghxFdbPGA_6RbY,1778
|
10
|
-
benchling_sdk/apps/config/decryption_provider.py,sha256
|
10
|
+
benchling_sdk/apps/config/decryption_provider.py,sha256=-HgjkBto8mYlooV0LXFenfaiP7PDhHRnKEHkK1P6gh4,2184
|
11
11
|
benchling_sdk/apps/config/errors.py,sha256=-qkfLdcUTuuRD-V4L2l7nzQWnWTRuifDtkNDv8tfHoo,800
|
12
|
-
benchling_sdk/apps/config/framework.py,sha256=
|
13
|
-
benchling_sdk/apps/config/
|
14
|
-
benchling_sdk/apps/config/
|
12
|
+
benchling_sdk/apps/config/framework.py,sha256=a2cIkPugEVUfBNtHm2cbE3Qu326xb-SpMuM0Gi6U-3Q,13337
|
13
|
+
benchling_sdk/apps/config/helpers.py,sha256=LTLDR0GCDoo_8Sx4kepQnMmgVEQT7MHfKAxIoAvV9TM,7077
|
14
|
+
benchling_sdk/apps/config/mock_config.py,sha256=EPUCxWiUSsWxWilnHAJIq-_f1q6ckZkXoIFv1S25hnM,26967
|
15
15
|
benchling_sdk/apps/config/types.py,sha256=XKfSGv-75CU-j1XwfXBGq8zbtnkF-PQnuY6Z2U47-Tg,953
|
16
16
|
benchling_sdk/apps/framework.py,sha256=H51rAzwH4PQHMGTxx2MdYgHMW1oKa_FLnozzY8XGL2g,3308
|
17
17
|
benchling_sdk/apps/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
-
benchling_sdk/apps/helpers/config_helpers.py,sha256=_t_ccSS53WpaNnwcSx3Mx5ranRJgxIQWcpBoUSWFKFA,9318
|
19
18
|
benchling_sdk/apps/helpers/manifest_helpers.py,sha256=yidiKA5mwWdAFR1ZSUu40QoG0Us-bc6V8tYHYqheEtM,945
|
20
19
|
benchling_sdk/apps/helpers/webhook_helpers.py,sha256=T-ZJLWb37nzSKMQFAQQ8FJU7al_QFBgNRhTfWDfCfYU,7077
|
21
20
|
benchling_sdk/apps/status/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
21
|
benchling_sdk/apps/status/errors.py,sha256=E9PugMd0YwZQWweTztIZyqycECBuVvH6PcLfij0Cb3k,2279
|
23
|
-
benchling_sdk/apps/status/framework.py,sha256=
|
24
|
-
benchling_sdk/apps/status/
|
22
|
+
benchling_sdk/apps/status/framework.py,sha256=CWPIlj8WhRZeIImCLka9LmhXvzbK0be9ekdLxiUKKJk,26358
|
23
|
+
benchling_sdk/apps/status/helpers.py,sha256=o8jdgdxUYdGh2j0Gb3AYoeXI9Bu-ubyIkgWBuCGLKgE,705
|
24
|
+
benchling_sdk/apps/status/types.py,sha256=vE7-_7ns3mvPRJoVv-GQxc3389dIIH4mcG0VDNWpVhQ,746
|
25
|
+
benchling_sdk/apps/types.py,sha256=TBTfAB3IOoZjZqzTOK25kN3b6RTU9Z7tOMdBbq6u8lA,110
|
25
26
|
benchling_sdk/auth/__init__.py,sha256=N4pJYVUnTLzg5HO9ZldHaI-Am97i6AOCdQS0M5QcVpA,120
|
26
27
|
benchling_sdk/auth/api_key_auth.py,sha256=Ui-cnvGMjcwVPV_b2GdBaoTjEyHJIu9CjtZScVBEUvU,641
|
27
28
|
benchling_sdk/auth/bearer_token_auth.py,sha256=nymI8V91evcnK-TWKkBXZwck8U1qSh4WaseyQbvF-Cg,1268
|
@@ -70,7 +71,7 @@ benchling_sdk/services/v2/stable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
70
71
|
benchling_sdk/services/v2/stable/aa_sequence_service.py,sha256=3RCNwyFBrryQowC9fbLoQHSSqKyGA6TQ0VQYBUyeg1U,11782
|
71
72
|
benchling_sdk/services/v2/stable/api_service.py,sha256=e0RNp4Jne9UTaHOYMOxxXJpsyUO3WMSFPzN7hB8iliU,12371
|
72
73
|
benchling_sdk/services/v2/stable/app_service.py,sha256=dy9FMVvMiJrkYbxZswKuB37EB9K_jCqQr9FfAa0BMgE,23126
|
73
|
-
benchling_sdk/services/v2/stable/assay_result_service.py,sha256=
|
74
|
+
benchling_sdk/services/v2/stable/assay_result_service.py,sha256=_qtSpMznVrGHlB2VnHI87IPjVQHCX1pZbLPJ_LYuW7U,13362
|
74
75
|
benchling_sdk/services/v2/stable/assay_run_service.py,sha256=tLpG1pAztEoaDatqlgYlRZ_LgwDly1_UeWt4G4UXvd4,9023
|
75
76
|
benchling_sdk/services/v2/stable/blob_service.py,sha256=KwchH3FGzPLfZx85GEG3voQp_ZxyVL_dds_9awRWa0Q,17115
|
76
77
|
benchling_sdk/services/v2/stable/box_service.py,sha256=M40smqG-jQlioyRfLBu9Cr9aQmdh06crsYbH1fiZ0BM,12359
|
@@ -114,7 +115,7 @@ benchling_sdk/services/v2/v2_alpha_service.py,sha256=vNfYK0Dheml9ozR_0tzTlA3blPD
|
|
114
115
|
benchling_sdk/services/v2/v2_beta_service.py,sha256=7v9ngWH_XTinkVC7bIxxbaA1UeFQqkzR4ANGtQQN-fA,11521
|
115
116
|
benchling_sdk/services/v2/v2_stable_service.py,sha256=YIc-_0p6x1NQqj7awnWgCTHxbxYO7ZOolePZyW90whc,35246
|
116
117
|
benchling_sdk/services/v2_service.py,sha256=3eoIjYEmGLPdWCpBN0pl7q7_HNWCsUvfvTn3Hcz0wSM,2860
|
117
|
-
benchling_sdk-1.10.
|
118
|
-
benchling_sdk-1.10.
|
119
|
-
benchling_sdk-1.10.
|
120
|
-
benchling_sdk-1.10.
|
118
|
+
benchling_sdk-1.10.0a7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
119
|
+
benchling_sdk-1.10.0a7.dist-info/METADATA,sha256=GKfUuppZ9cw6GIv2w-jZQ_I4B5sm1I-2jXS2h_ccb4Q,2126
|
120
|
+
benchling_sdk-1.10.0a7.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
121
|
+
benchling_sdk-1.10.0a7.dist-info/RECORD,,
|
@@ -1,190 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from abc import ABC, abstractmethod
|
4
|
-
from datetime import date, datetime
|
5
|
-
import json
|
6
|
-
from typing import Any, Dict, Generic, List, Optional, TypeVar, Union
|
7
|
-
|
8
|
-
from benchling_sdk.models import (
|
9
|
-
BooleanAppConfigItemType,
|
10
|
-
DateAppConfigItemType,
|
11
|
-
DatetimeAppConfigItemType,
|
12
|
-
FloatAppConfigItemType,
|
13
|
-
IntegerAppConfigItemType,
|
14
|
-
JsonAppConfigItemType,
|
15
|
-
SecureTextAppConfigItemType,
|
16
|
-
TextAppConfigItemType,
|
17
|
-
)
|
18
|
-
|
19
|
-
JsonType = Union[Dict[str, Any], List[Any], str, int, float, bool]
|
20
|
-
ScalarType = TypeVar("ScalarType", bool, date, datetime, float, int, JsonType, str)
|
21
|
-
# JsonType support requires object to be unioned. Currently we do it inline.
|
22
|
-
ScalarModelType = Union[bool, date, datetime, float, int, str]
|
23
|
-
# Enum values cannot be used in literals, so copy the strings
|
24
|
-
ScalarConfigItemType = Union[
|
25
|
-
BooleanAppConfigItemType,
|
26
|
-
DateAppConfigItemType,
|
27
|
-
DatetimeAppConfigItemType,
|
28
|
-
FloatAppConfigItemType,
|
29
|
-
IntegerAppConfigItemType,
|
30
|
-
JsonAppConfigItemType,
|
31
|
-
SecureTextAppConfigItemType,
|
32
|
-
TextAppConfigItemType,
|
33
|
-
]
|
34
|
-
|
35
|
-
|
36
|
-
# TODO BNCH-52772 We should probably consider moving all of these to a weakly _ internal scoped usage
|
37
|
-
|
38
|
-
|
39
|
-
class ScalarDefinition(ABC, Generic[ScalarType]):
|
40
|
-
"""
|
41
|
-
Scalar definition.
|
42
|
-
|
43
|
-
Map how ScalarConfigTypes values can be converted into corresponding Python types.
|
44
|
-
"""
|
45
|
-
|
46
|
-
@classmethod
|
47
|
-
def init(cls):
|
48
|
-
"""Init."""
|
49
|
-
return cls()
|
50
|
-
|
51
|
-
@classmethod
|
52
|
-
@abstractmethod
|
53
|
-
def from_str(cls, value: Optional[str]) -> Optional[ScalarType]:
|
54
|
-
"""
|
55
|
-
From string.
|
56
|
-
|
57
|
-
Given an optional string value of scalar configuration, produce an Optional instance of the
|
58
|
-
specific ScalarType. For instance, converting str to int.
|
59
|
-
|
60
|
-
Used when coercing Python types from string values in API responses.
|
61
|
-
"""
|
62
|
-
pass
|
63
|
-
|
64
|
-
|
65
|
-
class BoolScalar(ScalarDefinition[bool]):
|
66
|
-
"""
|
67
|
-
Bool Scalar.
|
68
|
-
|
69
|
-
Turn a Boolean-like string value into bool. Any permutation of "true" - case insensitive - is interpreted
|
70
|
-
as True. Any other non-empty string is False.
|
71
|
-
"""
|
72
|
-
|
73
|
-
@classmethod
|
74
|
-
def from_str(cls, value: Optional[str]) -> Optional[bool]:
|
75
|
-
"""Convert optional str to optional bool."""
|
76
|
-
# Though the spec declares str, this is actually being sent in JSON as a real Boolean
|
77
|
-
# So runtime check defensively
|
78
|
-
if value is not None:
|
79
|
-
if isinstance(value, bool):
|
80
|
-
return value
|
81
|
-
if value.lower() == "true":
|
82
|
-
return True
|
83
|
-
return False
|
84
|
-
return None
|
85
|
-
|
86
|
-
|
87
|
-
class DateScalar(ScalarDefinition[date]):
|
88
|
-
"""
|
89
|
-
Date Scalar.
|
90
|
-
|
91
|
-
Turn an ISO formatted date like YYYY-MM-dd into a date.
|
92
|
-
"""
|
93
|
-
|
94
|
-
@classmethod
|
95
|
-
def from_str(cls, value: Optional[str]) -> Optional[date]:
|
96
|
-
"""Convert optional str to optional date."""
|
97
|
-
return date.fromisoformat(value) if value is not None else None
|
98
|
-
|
99
|
-
|
100
|
-
class DateTimeScalar(ScalarDefinition[datetime]):
|
101
|
-
"""
|
102
|
-
Date Time Scalar.
|
103
|
-
|
104
|
-
Turn a date time string into datetime.
|
105
|
-
"""
|
106
|
-
|
107
|
-
@classmethod
|
108
|
-
def from_str(cls, value: Optional[str]) -> Optional[datetime]:
|
109
|
-
"""Convert optional str to optional datetime."""
|
110
|
-
return datetime.strptime(value, cls.expected_format()) if value is not None else None
|
111
|
-
|
112
|
-
@staticmethod
|
113
|
-
def expected_format() -> str:
|
114
|
-
"""Return the expected date mask for parsing string to datetime."""
|
115
|
-
return "%Y-%m-%d %I:%M:%S %p"
|
116
|
-
|
117
|
-
|
118
|
-
class IsoDateTimeScalar(ScalarDefinition[datetime]):
|
119
|
-
"""
|
120
|
-
Iso Date Time Scalar.
|
121
|
-
|
122
|
-
Turn a ISO 8601 date time string into datetime. Benchling fields use RFC 3339, unlike app config date times.
|
123
|
-
"""
|
124
|
-
|
125
|
-
@classmethod
|
126
|
-
def from_str(cls, value: Optional[str]) -> Optional[datetime]:
|
127
|
-
"""Convert optional str to optional datetime."""
|
128
|
-
return datetime.fromisoformat(value) if value is not None else None
|
129
|
-
|
130
|
-
|
131
|
-
class FloatScalar(ScalarDefinition[float]):
|
132
|
-
"""
|
133
|
-
Float Scalar.
|
134
|
-
|
135
|
-
Turn a string into float. Assumes the string, if not empty, is a valid floating point.
|
136
|
-
"""
|
137
|
-
|
138
|
-
@classmethod
|
139
|
-
def from_str(cls, value: Optional[str]) -> Optional[float]:
|
140
|
-
"""Convert optional str to optional float."""
|
141
|
-
return float(value) if value is not None else None
|
142
|
-
|
143
|
-
|
144
|
-
class IntScalar(ScalarDefinition[int]):
|
145
|
-
"""
|
146
|
-
Int Scalar.
|
147
|
-
|
148
|
-
Turn a string into int. Assumes the string, if not empty, is a valid integer.
|
149
|
-
"""
|
150
|
-
|
151
|
-
@classmethod
|
152
|
-
def from_str(cls, value: Optional[str]) -> Optional[int]:
|
153
|
-
"""Convert optional str to optional int."""
|
154
|
-
return int(value) if value is not None else None
|
155
|
-
|
156
|
-
|
157
|
-
class JsonScalar(ScalarDefinition[JsonType]):
|
158
|
-
"""
|
159
|
-
Json Scalar.
|
160
|
-
|
161
|
-
Turn a string into JSON. Assumes the string is a valid JSON string.
|
162
|
-
"""
|
163
|
-
|
164
|
-
@classmethod
|
165
|
-
def from_str(cls, value: Optional[str]) -> Optional[JsonType]:
|
166
|
-
"""Convert optional str to optional JsonType."""
|
167
|
-
return json.loads(value) if value is not None else None
|
168
|
-
|
169
|
-
|
170
|
-
class TextScalar(ScalarDefinition[str]):
|
171
|
-
"""
|
172
|
-
Text Scalar.
|
173
|
-
|
174
|
-
Text is already a string, so no conversion is performed.
|
175
|
-
"""
|
176
|
-
|
177
|
-
@classmethod
|
178
|
-
def from_str(cls, value: Optional[str]) -> Optional[str]:
|
179
|
-
"""Convert optional str to optional str. Implemented to appease ScalarDefinition contract."""
|
180
|
-
return value
|
181
|
-
|
182
|
-
|
183
|
-
class SecureTextScalar(TextScalar):
|
184
|
-
"""
|
185
|
-
Secure Text Scalar.
|
186
|
-
|
187
|
-
Text is already a string, so no conversion is performed.
|
188
|
-
"""
|
189
|
-
|
190
|
-
pass
|
File without changes
|
File without changes
|