benchling-sdk 1.9.0a5__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.
Files changed (32) hide show
  1. benchling_sdk/apps/canvas/__init__.py +0 -0
  2. benchling_sdk/apps/canvas/errors.py +14 -0
  3. benchling_sdk/apps/{helpers/canvas_helpers.py → canvas/framework.py} +129 -188
  4. benchling_sdk/apps/canvas/types.py +125 -0
  5. benchling_sdk/apps/config/__init__.py +0 -3
  6. benchling_sdk/apps/config/decryption_provider.py +1 -1
  7. benchling_sdk/apps/config/errors.py +38 -0
  8. benchling_sdk/apps/config/framework.py +343 -0
  9. benchling_sdk/apps/config/helpers.py +157 -0
  10. benchling_sdk/apps/config/{mock_dependencies.py → mock_config.py} +78 -99
  11. benchling_sdk/apps/config/types.py +36 -0
  12. benchling_sdk/apps/framework.py +49 -338
  13. benchling_sdk/apps/helpers/webhook_helpers.py +2 -2
  14. benchling_sdk/apps/status/__init__.py +0 -0
  15. benchling_sdk/apps/status/errors.py +85 -0
  16. benchling_sdk/apps/{helpers/session_helpers.py → status/framework.py} +58 -167
  17. benchling_sdk/apps/status/helpers.py +20 -0
  18. benchling_sdk/apps/status/types.py +45 -0
  19. benchling_sdk/apps/types.py +3 -0
  20. benchling_sdk/errors.py +4 -4
  21. benchling_sdk/models/__init__.py +44 -0
  22. benchling_sdk/services/v2/beta/{v2_beta_dataset_service.py → v2_beta_data_frame_service.py} +126 -116
  23. benchling_sdk/services/v2/stable/assay_result_service.py +18 -0
  24. benchling_sdk/services/v2/v2_beta_service.py +11 -11
  25. {benchling_sdk-1.9.0a5.dist-info → benchling_sdk-1.10.0.dist-info}/METADATA +4 -4
  26. {benchling_sdk-1.9.0a5.dist-info → benchling_sdk-1.10.0.dist-info}/RECORD +29 -20
  27. benchling_sdk/apps/config/dependencies.py +0 -1085
  28. benchling_sdk/apps/config/scalars.py +0 -226
  29. benchling_sdk/apps/helpers/config_helpers.py +0 -409
  30. /benchling_sdk/apps/{helpers → config}/cryptography_helpers.py +0 -0
  31. {benchling_sdk-1.9.0a5.dist-info → benchling_sdk-1.10.0.dist-info}/LICENSE +0 -0
  32. {benchling_sdk-1.9.0a5.dist-info → benchling_sdk-1.10.0.dist-info}/WHEEL +0 -0
@@ -1,226 +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
- FieldType,
13
- FloatAppConfigItemType,
14
- IntegerAppConfigItemType,
15
- JsonAppConfigItemType,
16
- SecureTextAppConfigItemType,
17
- TextAppConfigItemType,
18
- )
19
-
20
- JsonType = Union[Dict[str, Any], List[Any], str, int, float, bool]
21
- ScalarType = TypeVar("ScalarType", bool, date, datetime, float, int, JsonType, str)
22
- # JsonType support requires object to be unioned. Currently we do it inline.
23
- ScalarModelType = Union[bool, date, datetime, float, int, str]
24
- # Enum values cannot be used in literals, so copy the strings
25
- ScalarConfigItemType = Union[
26
- BooleanAppConfigItemType,
27
- DateAppConfigItemType,
28
- DatetimeAppConfigItemType,
29
- FloatAppConfigItemType,
30
- IntegerAppConfigItemType,
31
- JsonAppConfigItemType,
32
- SecureTextAppConfigItemType,
33
- TextAppConfigItemType,
34
- ]
35
-
36
-
37
- class ScalarDefinition(ABC, Generic[ScalarType]):
38
- """
39
- Scalar definition.
40
-
41
- Map how ScalarConfigTypes values can be converted into corresponding Python types.
42
- """
43
-
44
- @classmethod
45
- def init(cls):
46
- """Init."""
47
- return cls()
48
-
49
- @classmethod
50
- @abstractmethod
51
- def from_str(cls, value: Optional[str]) -> Optional[ScalarType]:
52
- """
53
- From string.
54
-
55
- Given an optional string value of scalar configuration, produce an Optional instance of the
56
- specific ScalarType. For instance, converting str to int.
57
-
58
- Used when coercing Python types from string values in API responses.
59
- """
60
- pass
61
-
62
-
63
- class BoolScalar(ScalarDefinition[bool]):
64
- """
65
- Bool Scalar.
66
-
67
- Turn a Boolean-like string value into bool. Any permutation of "true" - case insensitive - is interpreted
68
- as True. Any other non-empty string is False.
69
- """
70
-
71
- @classmethod
72
- def from_str(cls, value: Optional[str]) -> Optional[bool]:
73
- """Convert optional str to optional bool."""
74
- # Though the spec declares str, this is actually being sent in JSON as a real Boolean
75
- # So runtime check defensively
76
- if value is not None:
77
- if isinstance(value, bool):
78
- return value
79
- if value.lower() == "true":
80
- return True
81
- return False
82
- return None
83
-
84
-
85
- class DateScalar(ScalarDefinition[date]):
86
- """
87
- Date Scalar.
88
-
89
- Turn an ISO formatted date like YYYY-MM-dd into a date.
90
- """
91
-
92
- @classmethod
93
- def from_str(cls, value: Optional[str]) -> Optional[date]:
94
- """Convert optional str to optional date."""
95
- return date.fromisoformat(value) if value is not None else None
96
-
97
-
98
- class DateTimeScalar(ScalarDefinition[datetime]):
99
- """
100
- Date Time Scalar.
101
-
102
- Turn a date time string into datetime.
103
- """
104
-
105
- @classmethod
106
- def from_str(cls, value: Optional[str]) -> Optional[datetime]:
107
- """Convert optional str to optional datetime."""
108
- return datetime.strptime(value, cls.expected_format()) if value is not None else None
109
-
110
- @staticmethod
111
- def expected_format() -> str:
112
- """Return the expected date mask for parsing string to datetime."""
113
- return "%Y-%m-%d %I:%M:%S %p"
114
-
115
-
116
- class IsoDateTimeScalar(ScalarDefinition[datetime]):
117
- """
118
- Iso Date Time Scalar.
119
-
120
- Turn a ISO 8601 date time string into datetime. Benchling fields use RFC 3339, unlike app config date times.
121
- """
122
-
123
- @classmethod
124
- def from_str(cls, value: Optional[str]) -> Optional[datetime]:
125
- """Convert optional str to optional datetime."""
126
- return datetime.fromisoformat(value) if value is not None else None
127
-
128
-
129
- class FloatScalar(ScalarDefinition[float]):
130
- """
131
- Float Scalar.
132
-
133
- Turn a string into float. Assumes the string, if not empty, is a valid floating point.
134
- """
135
-
136
- @classmethod
137
- def from_str(cls, value: Optional[str]) -> Optional[float]:
138
- """Convert optional str to optional float."""
139
- return float(value) if value is not None else None
140
-
141
-
142
- class IntScalar(ScalarDefinition[int]):
143
- """
144
- Int Scalar.
145
-
146
- Turn a string into int. Assumes the string, if not empty, is a valid integer.
147
- """
148
-
149
- @classmethod
150
- def from_str(cls, value: Optional[str]) -> Optional[int]:
151
- """Convert optional str to optional int."""
152
- return int(value) if value is not None else None
153
-
154
-
155
- class JsonScalar(ScalarDefinition[JsonType]):
156
- """
157
- Json Scalar.
158
-
159
- Turn a string into JSON. Assumes the string is a valid JSON string.
160
- """
161
-
162
- @classmethod
163
- def from_str(cls, value: Optional[str]) -> Optional[JsonType]:
164
- """Convert optional str to optional JsonType."""
165
- return json.loads(value) if value is not None else None
166
-
167
-
168
- class TextScalar(ScalarDefinition[str]):
169
- """
170
- Text Scalar.
171
-
172
- Text is already a string, so no conversion is performed.
173
- """
174
-
175
- @classmethod
176
- def from_str(cls, value: Optional[str]) -> Optional[str]:
177
- """Convert optional str to optional str. Implemented to appease ScalarDefinition contract."""
178
- return value
179
-
180
-
181
- class SecureTextScalar(TextScalar):
182
- """
183
- Secure Text Scalar.
184
-
185
- Text is already a string, so no conversion is performed.
186
- """
187
-
188
- pass
189
-
190
-
191
- def scalar_definition_from_field_type(field_type: FieldType) -> ScalarDefinition:
192
- """
193
- Scalar Definition From Field Type.
194
-
195
- Returns a ScalarDefinition for parsing a typed value given a field type.
196
- Assumes TextScalar (string) for any types not specifically enumerated.
197
- """
198
- if field_type == field_type.BOOLEAN:
199
- return BoolScalar.init()
200
- elif field_type == field_type.DATE:
201
- return DateScalar.init()
202
- elif field_type == field_type.DATETIME:
203
- return IsoDateTimeScalar.init()
204
- elif field_type == field_type.FLOAT:
205
- return FloatScalar.init()
206
- elif field_type == field_type.INTEGER:
207
- return IntScalar.init()
208
- elif field_type == field_type.JSON:
209
- return JsonScalar.init()
210
- elif field_type == field_type.TEXT:
211
- return TextScalar.init()
212
- # Assume all other types are str, which is safe for fields
213
- return TextScalar.init()
214
-
215
-
216
- # Maps scalar types from the API into typed Python SDK scalar definitions
217
- DEFAULT_SCALAR_DEFINITIONS: Dict[ScalarConfigItemType, ScalarDefinition] = {
218
- BooleanAppConfigItemType.BOOLEAN: BoolScalar.init(),
219
- DateAppConfigItemType.DATE: DateScalar.init(),
220
- DatetimeAppConfigItemType.DATETIME: DateTimeScalar.init(),
221
- FloatAppConfigItemType.FLOAT: FloatScalar.init(),
222
- IntegerAppConfigItemType.INTEGER: IntScalar.init(),
223
- JsonAppConfigItemType.JSON: JsonScalar.init(),
224
- SecureTextAppConfigItemType.SECURE_TEXT: SecureTextScalar.init(),
225
- TextAppConfigItemType.TEXT: TextScalar.init(),
226
- }
@@ -1,409 +0,0 @@
1
- from datetime import date, datetime
2
- from typing import List, Optional, Type, Union
3
-
4
- from benchling_api_client.v2.beta.models.app_config_field_type import AppConfigFieldType
5
- from benchling_api_client.v2.beta.models.base_manifest_config import BaseManifestConfig
6
- from benchling_api_client.v2.beta.models.dropdown_dependency import DropdownDependency
7
- from benchling_api_client.v2.beta.models.dropdown_dependency_types import DropdownDependencyTypes
8
- from benchling_api_client.v2.beta.models.entity_schema_dependency import EntitySchemaDependency
9
- from benchling_api_client.v2.beta.models.entity_schema_dependency_type import EntitySchemaDependencyType
10
- from benchling_api_client.v2.beta.models.field_definitions_manifest import FieldDefinitionsManifest
11
- from benchling_api_client.v2.beta.models.manifest_array_config import ManifestArrayConfig
12
- from benchling_api_client.v2.beta.models.manifest_boolean_scalar_config import ManifestBooleanScalarConfig
13
- from benchling_api_client.v2.beta.models.manifest_date_scalar_config import ManifestDateScalarConfig
14
- from benchling_api_client.v2.beta.models.manifest_datetime_scalar_config import ManifestDatetimeScalarConfig
15
- from benchling_api_client.v2.beta.models.manifest_float_scalar_config import ManifestFloatScalarConfig
16
- from benchling_api_client.v2.beta.models.manifest_integer_scalar_config import ManifestIntegerScalarConfig
17
- from benchling_api_client.v2.beta.models.manifest_json_scalar_config import ManifestJsonScalarConfig
18
- from benchling_api_client.v2.beta.models.manifest_scalar_config import ManifestScalarConfig
19
- from benchling_api_client.v2.beta.models.manifest_secure_text_scalar_config import (
20
- ManifestSecureTextScalarConfig,
21
- )
22
- from benchling_api_client.v2.beta.models.manifest_text_scalar_config import ManifestTextScalarConfig
23
- from benchling_api_client.v2.beta.models.resource_dependency import ResourceDependency
24
- from benchling_api_client.v2.beta.models.resource_dependency_types import ResourceDependencyTypes
25
- from benchling_api_client.v2.beta.models.scalar_config import ScalarConfig
26
- from benchling_api_client.v2.beta.models.scalar_config_types import ScalarConfigTypes
27
- from benchling_api_client.v2.beta.models.schema_dependency import SchemaDependency
28
- from benchling_api_client.v2.beta.models.schema_dependency_subtypes import SchemaDependencySubtypes
29
- from benchling_api_client.v2.beta.models.schema_dependency_types import SchemaDependencyTypes
30
- from benchling_api_client.v2.beta.models.workflow_task_schema_dependency import WorkflowTaskSchemaDependency
31
- from benchling_api_client.v2.beta.models.workflow_task_schema_dependency_output import (
32
- WorkflowTaskSchemaDependencyOutput,
33
- )
34
- from benchling_api_client.v2.beta.models.workflow_task_schema_dependency_type import (
35
- WorkflowTaskSchemaDependencyType,
36
- )
37
- from benchling_api_client.v2.extensions import UnknownType
38
- from benchling_api_client.v2.stable.extensions import NotPresentError
39
-
40
- from benchling_sdk.apps.config.dependencies import ConfigurationReference, UnsupportedDependencyError
41
- from benchling_sdk.apps.config.scalars import JsonType, ScalarModelType
42
- from benchling_sdk.models import (
43
- AaSequence,
44
- ArrayElementAppConfigItem,
45
- AssayResult,
46
- AssayRun,
47
- BooleanAppConfigItem,
48
- Box,
49
- Container,
50
- CustomEntity,
51
- DateAppConfigItem,
52
- DatetimeAppConfigItem,
53
- DnaOligo,
54
- DnaSequence,
55
- EntitySchemaAppConfigItem,
56
- Entry,
57
- FieldAppConfigItem,
58
- FloatAppConfigItem,
59
- GenericApiIdentifiedAppConfigItem,
60
- IntegerAppConfigItem,
61
- JsonAppConfigItem,
62
- Location,
63
- Mixture,
64
- Molecule,
65
- Plate,
66
- Request,
67
- RnaOligo,
68
- RnaSequence,
69
- SecureTextAppConfigItem,
70
- TextAppConfigItem,
71
- WorkflowTask,
72
- )
73
-
74
- _MODEL_TYPES_FROM_SCHEMA_TYPE = {
75
- SchemaDependencyTypes.CONTAINER_SCHEMA: Container,
76
- SchemaDependencyTypes.PLATE_SCHEMA: Plate,
77
- SchemaDependencyTypes.BOX_SCHEMA: Box,
78
- SchemaDependencyTypes.LOCATION_SCHEMA: Location,
79
- SchemaDependencyTypes.ENTRY_SCHEMA: Entry,
80
- SchemaDependencyTypes.REQUEST_SCHEMA: Request,
81
- SchemaDependencyTypes.RESULT_SCHEMA: AssayResult,
82
- SchemaDependencyTypes.RUN_SCHEMA: AssayRun,
83
- SchemaDependencyTypes.WORKFLOW_TASK_SCHEMA: WorkflowTask,
84
- }
85
-
86
-
87
- _SCALAR_TYPES_FROM_CONFIG = {
88
- ScalarConfigTypes.BOOLEAN: bool,
89
- ScalarConfigTypes.DATE: date,
90
- ScalarConfigTypes.DATETIME: datetime,
91
- ScalarConfigTypes.FLOAT: float,
92
- ScalarConfigTypes.INTEGER: int,
93
- ScalarConfigTypes.JSON: JsonType,
94
- ScalarConfigTypes.TEXT: str,
95
- }
96
-
97
-
98
- _FIELD_SCALAR_TYPES_FROM_CONFIG = {
99
- AppConfigFieldType.BOOLEAN: bool,
100
- AppConfigFieldType.DATE: date,
101
- AppConfigFieldType.DATETIME: datetime,
102
- AppConfigFieldType.FLOAT: float,
103
- AppConfigFieldType.INTEGER: int,
104
- AppConfigFieldType.JSON: JsonType,
105
- AppConfigFieldType.TEXT: str,
106
- }
107
-
108
-
109
- ModelType = Union[AssayResult, AssayRun, Box, Container, Entry, Location, Plate, Request]
110
-
111
- _INSTANCE_FROM_SCHEMA_SUBTYPE = {
112
- SchemaDependencySubtypes.AA_SEQUENCE: AaSequence,
113
- SchemaDependencySubtypes.CUSTOM_ENTITY: CustomEntity,
114
- SchemaDependencySubtypes.DNA_SEQUENCE: DnaSequence,
115
- SchemaDependencySubtypes.DNA_OLIGO: DnaOligo,
116
- SchemaDependencySubtypes.MIXTURE: Mixture,
117
- SchemaDependencySubtypes.MOLECULE: Molecule,
118
- SchemaDependencySubtypes.RNA_OLIGO: RnaOligo,
119
- SchemaDependencySubtypes.RNA_SEQUENCE: RnaSequence,
120
- }
121
-
122
- EntitySubtype = Union[
123
- AaSequence, CustomEntity, DnaOligo, DnaSequence, Mixture, Molecule, RnaOligo, RnaSequence
124
- ]
125
-
126
- AnyDependency = Union[
127
- BaseManifestConfig,
128
- DropdownDependency,
129
- EntitySchemaDependency,
130
- FieldDefinitionsManifest,
131
- ManifestArrayConfig,
132
- ManifestScalarConfig,
133
- ResourceDependency,
134
- SchemaDependency,
135
- WorkflowTaskSchemaDependency,
136
- ]
137
-
138
- ArrayElementDependency = Union[
139
- SchemaDependency,
140
- EntitySchemaDependency,
141
- WorkflowTaskSchemaDependency,
142
- DropdownDependency,
143
- ResourceDependency,
144
- ManifestScalarConfig,
145
- ]
146
-
147
-
148
- class UnsupportedSubTypeError(Exception):
149
- """Error when an unsupported subtype is encountered."""
150
-
151
- pass
152
-
153
-
154
- def model_type_from_dependency(
155
- dependency: Union[EntitySchemaDependency, SchemaDependency]
156
- ) -> Optional[Type[Union[ModelType, EntitySubtype]]]:
157
- """Translate a schema dependency to its model class. Must have a valid subtype."""
158
- if isinstance(dependency, EntitySchemaDependency):
159
- subtype = subtype_from_entity_schema_dependency(dependency)
160
- if subtype:
161
- return _subtype_instance_from_dependency(dependency)
162
- return None
163
- return _MODEL_TYPES_FROM_SCHEMA_TYPE[dependency.type]
164
-
165
-
166
- def scalar_type_from_config(config: ScalarConfig) -> Union[object, Type[ScalarModelType]]:
167
- """Translate a scalar config to its Pyton type."""
168
- # We union with object to satisfy JsonType.
169
- return _SCALAR_TYPES_FROM_CONFIG.get(config.type, str)
170
-
171
-
172
- def scalar_type_from_field_config(config: FieldDefinitionsManifest) -> Union[object, Type[ScalarModelType]]:
173
- """Translate a field config to its Pyton type."""
174
- # type may not be specified, so handle NotPresentError
175
- try:
176
- if hasattr(config, "type"):
177
- # We union with object to satisfy JsonType.
178
- return _FIELD_SCALAR_TYPES_FROM_CONFIG.get(config.type, str)
179
- # We can't seem to handle this programmatically by checking isinstance() or output truthiness
180
- except NotPresentError:
181
- pass
182
- return str
183
-
184
-
185
- def field_definitions_from_dependency(
186
- dependency: Union[
187
- EntitySchemaDependency,
188
- SchemaDependency,
189
- WorkflowTaskSchemaDependency,
190
- WorkflowTaskSchemaDependencyOutput,
191
- ]
192
- ) -> List[FieldDefinitionsManifest]:
193
- """Safely return a list of field definitions from a schema dependency or empty list."""
194
- try:
195
- if hasattr(dependency, "field_definitions"):
196
- return dependency.field_definitions
197
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
198
- except NotPresentError:
199
- pass
200
- return []
201
-
202
-
203
- def element_definition_from_dependency(dependency: ManifestArrayConfig) -> List[ArrayElementDependency]:
204
- """Safely return an element definition as a list of dependencies from an array dependency or empty list."""
205
- try:
206
- if hasattr(dependency, "element_definition"):
207
- return [
208
- _fix_element_definition_deserialization(element) for element in dependency.element_definition
209
- ]
210
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
211
- except NotPresentError:
212
- pass
213
- return []
214
-
215
-
216
- def enum_from_dependency(
217
- dependency: Union[
218
- ManifestFloatScalarConfig,
219
- ManifestIntegerScalarConfig,
220
- ManifestTextScalarConfig,
221
- ]
222
- ) -> List:
223
- """Safely return an enum from a scalar config."""
224
- try:
225
- if hasattr(dependency, "enum"):
226
- return dependency.enum
227
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
228
- except NotPresentError:
229
- pass
230
- return []
231
-
232
-
233
- # TODO BNCH-57036 All element definitions currently deserialize to UnknownType. Hack around this temporarily
234
- def _fix_element_definition_deserialization(
235
- element: Union[UnknownType, ArrayElementDependency]
236
- ) -> ArrayElementDependency:
237
- if isinstance(element, UnknownType):
238
- if "type" in element.value:
239
- element_type = element.value["type"]
240
- if element_type == WorkflowTaskSchemaDependencyType.WORKFLOW_TASK_SCHEMA:
241
- return WorkflowTaskSchemaDependency.from_dict(element.value)
242
- elif element_type == EntitySchemaDependencyType.ENTITY_SCHEMA:
243
- return EntitySchemaDependency.from_dict(element.value)
244
- elif element_type in [member.value for member in SchemaDependencyTypes]:
245
- return SchemaDependency.from_dict(element.value)
246
- elif element_type == DropdownDependencyTypes.DROPDOWN:
247
- return DropdownDependency.from_dict(element.value)
248
- elif element_type in [member.value for member in ResourceDependencyTypes]:
249
- return ResourceDependency.from_dict(element.value)
250
- elif element_type in [member.value for member in ScalarConfigTypes]:
251
- return type(element_type).from_dict(element.value)
252
- raise NotImplementedError(f"No array deserialization fix for {element}")
253
- return element
254
-
255
-
256
- def workflow_task_schema_output_from_dependency(
257
- dependency: WorkflowTaskSchemaDependency,
258
- ) -> Optional[WorkflowTaskSchemaDependencyOutput]:
259
- """Safely return a workflow task schema output from a workflow task schema or None."""
260
- try:
261
- if hasattr(dependency, "output"):
262
- return dependency.output
263
- # We can't seem to handle this programmatically by checking isinstance() or output truthiness
264
- except NotPresentError:
265
- pass
266
- return None
267
-
268
-
269
- def options_from_dependency(dependency: DropdownDependency) -> List[BaseManifestConfig]:
270
- """Safely return a list of options from a dropdown dependency or empty list."""
271
- try:
272
- if hasattr(dependency, "options"):
273
- return dependency.options
274
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
275
- except NotPresentError:
276
- pass
277
- return []
278
-
279
-
280
- def is_config_required(dependency: AnyDependency) -> bool:
281
- """Safely return if a config item is required."""
282
- try:
283
- if hasattr(dependency, "required_config"):
284
- # `type: ignore` is used here because casting would be inaccurate or fragile.
285
- return dependency.required_config # type: ignore
286
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
287
- except NotPresentError:
288
- pass
289
- return False
290
-
291
-
292
- def is_field_value_required(dependency: FieldDefinitionsManifest) -> bool:
293
- """
294
- Safely return if a field must have a value.
295
-
296
- A field must be specified as requiredConfig: true AND isRequired: true to require a value.
297
- """
298
- # Fields must be both linked and isRequired to always provide a value
299
- try:
300
- if hasattr(dependency, "required_config") and hasattr(dependency, "is_required"):
301
- # dependency.required_config is Optional so evaluate the bool value
302
- return dependency.required_config is True and dependency.is_required is True
303
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
304
- except NotPresentError:
305
- pass
306
- return False
307
-
308
-
309
- # For forwards compatibility with multi-valued scalars, which could infer Unset == False
310
- def is_config_multi_valued(dependency: FieldDefinitionsManifest) -> bool:
311
- """
312
- Safely return if a config item is multi-valued.
313
-
314
- Assumes False in the case that a multi-valued constraint is unspecified (Unset).
315
- """
316
- multi_valued_unset = is_config_multi_valued_or_unset(dependency)
317
- return multi_valued_unset if multi_valued_unset is not None else False
318
-
319
-
320
- def is_config_multi_valued_or_unset(dependency: FieldDefinitionsManifest) -> Optional[bool]:
321
- """
322
- Safely return if a config item is multi-valued or None if it's Unset.
323
-
324
- Multi-valued constraint being undefined cannot be safely inferred for type coercion.
325
-
326
- For instance, a required text field could be typed as:
327
- isMulti == True: List[str]
328
- isMulti == False: str
329
- isMulti == Unset: Union[str, List[str]]
330
- """
331
- try:
332
- if hasattr(dependency, "is_multi") and dependency.is_multi is not None:
333
- return dependency.is_multi
334
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
335
- except NotPresentError:
336
- pass
337
- return None
338
-
339
-
340
- def subtype_from_entity_schema_dependency(
341
- dependency: EntitySchemaDependency,
342
- ) -> Optional[SchemaDependencySubtypes]:
343
- """Safely return an entity schema dependency's subtype, if present."""
344
- try:
345
- if hasattr(dependency, "subtype") and dependency.subtype:
346
- return dependency.subtype
347
- # We can't seem to handle this programmatically by checking isinstance() or field truthiness
348
- except NotPresentError:
349
- pass
350
- return None
351
-
352
-
353
- def app_config_type_from_dependency(dependency: AnyDependency) -> Type[ConfigurationReference]:
354
- """
355
- App Config Item Type From Item.
356
-
357
- Returns the type of the API model corresponding to an app config item.
358
- Raises UnsupportedDependencyError if encountering an unknown type.
359
- """
360
- # Generic type
361
- if isinstance(
362
- dependency,
363
- (
364
- BaseManifestConfig,
365
- DropdownDependency,
366
- SchemaDependency,
367
- ResourceDependency,
368
- WorkflowTaskSchemaDependency,
369
- ),
370
- ):
371
- return GenericApiIdentifiedAppConfigItem
372
- # Specially handled Schema types
373
- elif isinstance(dependency, FieldDefinitionsManifest):
374
- return FieldAppConfigItem
375
- elif isinstance(dependency, EntitySchemaDependency):
376
- return EntitySchemaAppConfigItem
377
- # Scalar types
378
- elif isinstance(dependency, ManifestBooleanScalarConfig):
379
- return BooleanAppConfigItem
380
- elif isinstance(dependency, ManifestDateScalarConfig):
381
- return DateAppConfigItem
382
- elif isinstance(dependency, ManifestDatetimeScalarConfig):
383
- return DatetimeAppConfigItem
384
- elif isinstance(dependency, ManifestFloatScalarConfig):
385
- return FloatAppConfigItem
386
- elif isinstance(dependency, ManifestIntegerScalarConfig):
387
- return IntegerAppConfigItem
388
- elif isinstance(dependency, ManifestJsonScalarConfig):
389
- return JsonAppConfigItem
390
- elif isinstance(dependency, ManifestSecureTextScalarConfig):
391
- return SecureTextAppConfigItem
392
- elif isinstance(dependency, ManifestTextScalarConfig):
393
- return TextAppConfigItem
394
- # Array type
395
- elif isinstance(dependency, ManifestArrayConfig):
396
- return ArrayElementAppConfigItem
397
- raise UnsupportedDependencyError(f"Unrecognized type for {dependency}]")
398
-
399
-
400
- def _subtype_instance_from_dependency(dependency: EntitySchemaDependency) -> Type[EntitySubtype]:
401
- if dependency.subtype in _INSTANCE_FROM_SCHEMA_SUBTYPE:
402
- return _INSTANCE_FROM_SCHEMA_SUBTYPE[dependency.subtype]
403
- # This would mean the spec has a new subtype, the manifest installed in Benchling has declared it,
404
- # the user has linked it in Benchling, but the app code receiving it was never updated.
405
- # App developers should support it in deployed app code before republishing the manifest.
406
- raise UnsupportedSubTypeError(
407
- f"An unsupported subtype, {dependency.subtype.value} was received. "
408
- f"The version of the SDK may need to be upgraded to support this."
409
- )