liminal-orm 1.1.4__py3-none-any.whl → 2.0.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.
- liminal/base/base_operation.py +4 -3
- liminal/base/base_validation_filters.py +15 -0
- liminal/base/name_template_parts.py +96 -0
- liminal/base/properties/base_field_properties.py +2 -2
- liminal/base/properties/base_name_template.py +83 -0
- liminal/base/properties/base_schema_properties.py +13 -1
- liminal/dropdowns/compare.py +8 -0
- liminal/dropdowns/operations.py +1 -1
- liminal/entity_schemas/api.py +18 -0
- liminal/entity_schemas/compare.py +62 -8
- liminal/entity_schemas/entity_schema_models.py +43 -0
- liminal/entity_schemas/generate_files.py +13 -11
- liminal/entity_schemas/operations.py +43 -18
- liminal/entity_schemas/tag_schema_models.py +146 -3
- liminal/entity_schemas/utils.py +15 -2
- liminal/enums/__init__.py +0 -1
- liminal/enums/benchling_entity_type.py +8 -0
- liminal/enums/name_template_part_type.py +12 -0
- liminal/external/__init__.py +11 -1
- liminal/migrate/revisions_timeline.py +2 -1
- liminal/orm/base_model.py +90 -29
- liminal/orm/name_template.py +39 -0
- liminal/orm/schema_properties.py +27 -1
- liminal/tests/conftest.py +18 -9
- liminal/tests/test_entity_schema_compare.py +61 -12
- liminal/utils.py +9 -0
- liminal/validation/__init__.py +84 -108
- liminal/{enums/benchling_report_level.py → validation/validation_severity.py} +2 -2
- {liminal_orm-1.1.4.dist-info → liminal_orm-2.0.0.dist-info}/METADATA +17 -20
- {liminal_orm-1.1.4.dist-info → liminal_orm-2.0.0.dist-info}/RECORD +33 -29
- {liminal_orm-1.1.4.dist-info → liminal_orm-2.0.0.dist-info}/LICENSE.md +0 -0
- {liminal_orm-1.1.4.dist-info → liminal_orm-2.0.0.dist-info}/WHEEL +0 -0
- {liminal_orm-1.1.4.dist-info → liminal_orm-2.0.0.dist-info}/entry_points.txt +0 -0
@@ -2,12 +2,14 @@ from typing import Any, ClassVar
|
|
2
2
|
|
3
3
|
from liminal.base.base_operation import BaseOperation
|
4
4
|
from liminal.base.properties.base_field_properties import BaseFieldProperties
|
5
|
+
from liminal.base.properties.base_name_template import BaseNameTemplate
|
5
6
|
from liminal.base.properties.base_schema_properties import BaseSchemaProperties
|
6
7
|
from liminal.connection import BenchlingService
|
7
8
|
from liminal.dropdowns.utils import get_benchling_dropdown_id_name_map
|
8
9
|
from liminal.entity_schemas.api import (
|
9
10
|
archive_tag_schemas,
|
10
11
|
create_entity_schema,
|
12
|
+
set_tag_schema_name_template,
|
11
13
|
unarchive_tag_schemas,
|
12
14
|
update_tag_schema,
|
13
15
|
)
|
@@ -21,7 +23,7 @@ from liminal.entity_schemas.utils import (
|
|
21
23
|
convert_tag_schema_field_to_field_properties,
|
22
24
|
convert_tag_schema_to_internal_schema,
|
23
25
|
)
|
24
|
-
from liminal.enums
|
26
|
+
from liminal.enums import BenchlingNamingStrategy
|
25
27
|
from liminal.orm.schema_properties import SchemaProperties
|
26
28
|
from liminal.utils import to_snake_case
|
27
29
|
|
@@ -121,7 +123,7 @@ class CreateEntitySchema(BaseOperation):
|
|
121
123
|
f"Entity schema {self._validated_schema_properties.warehouse_name} is already active in Benchling."
|
122
124
|
)
|
123
125
|
dropdowns_map = get_benchling_dropdown_id_name_map(benchling_service)
|
124
|
-
benchling_schema_props, benchling_fields_props = (
|
126
|
+
benchling_schema_props, _, benchling_fields_props = (
|
125
127
|
convert_tag_schema_to_internal_schema(schema, dropdowns_map)
|
126
128
|
)
|
127
129
|
if (
|
@@ -135,7 +137,7 @@ class CreateEntitySchema(BaseOperation):
|
|
135
137
|
|
136
138
|
|
137
139
|
class ArchiveEntitySchema(BaseOperation):
|
138
|
-
order: ClassVar[int] =
|
140
|
+
order: ClassVar[int] = 170
|
139
141
|
|
140
142
|
def __init__(self, wh_schema_name: str) -> None:
|
141
143
|
self.wh_schema_name = wh_schema_name
|
@@ -160,7 +162,7 @@ class ArchiveEntitySchema(BaseOperation):
|
|
160
162
|
|
161
163
|
|
162
164
|
class UnarchiveEntitySchema(BaseOperation):
|
163
|
-
order: ClassVar[int] =
|
165
|
+
order: ClassVar[int] = 100
|
164
166
|
|
165
167
|
def __init__(self, wh_schema_name: str) -> None:
|
166
168
|
self.wh_schema_name = wh_schema_name
|
@@ -245,20 +247,43 @@ class UpdateEntitySchema(BaseOperation):
|
|
245
247
|
raise ValueError(
|
246
248
|
f"Entity schema prefix {self.update_props.prefix} already exists in Benchling."
|
247
249
|
)
|
248
|
-
if (
|
249
|
-
self.update_props.naming_strategies
|
250
|
-
and not BenchlingNamingStrategy.is_valid_set(
|
251
|
-
self.update_props.naming_strategies, bool(tag_schema.nameTemplateParts)
|
252
|
-
)
|
253
|
-
):
|
254
|
-
raise ValueError(
|
255
|
-
"Invalid naming strategies for schema. The name template must be set on the schema through the UI when using template-based naming strategies."
|
256
|
-
)
|
257
250
|
return tag_schema
|
258
251
|
|
259
252
|
|
253
|
+
class UpdateEntitySchemaNameTemplate(BaseOperation):
|
254
|
+
order: ClassVar[int] = 150
|
255
|
+
|
256
|
+
def __init__(
|
257
|
+
self,
|
258
|
+
wh_schema_name: str,
|
259
|
+
update_name_template: BaseNameTemplate,
|
260
|
+
) -> None:
|
261
|
+
self.wh_schema_name = wh_schema_name
|
262
|
+
self.update_name_template = update_name_template
|
263
|
+
|
264
|
+
def execute(self, benchling_service: BenchlingService) -> dict[str, Any]:
|
265
|
+
tag_schema = TagSchemaModel.get_one(benchling_service, self.wh_schema_name)
|
266
|
+
updated_schema = tag_schema.update_name_template(self.update_name_template)
|
267
|
+
return set_tag_schema_name_template(
|
268
|
+
benchling_service,
|
269
|
+
tag_schema.id,
|
270
|
+
{
|
271
|
+
"nameTemplateParts": [
|
272
|
+
part.model_dump() for part in updated_schema.nameTemplateParts
|
273
|
+
],
|
274
|
+
"shouldOrderNamePartsBySequence": updated_schema.shouldOrderNamePartsBySequence,
|
275
|
+
},
|
276
|
+
)
|
277
|
+
|
278
|
+
def describe_operation(self) -> str:
|
279
|
+
return f"{self.wh_schema_name}: Updating name template to {str(self.update_name_template)}."
|
280
|
+
|
281
|
+
def describe(self) -> str:
|
282
|
+
return f"{self.wh_schema_name}: Name template is different in code versus Benchling."
|
283
|
+
|
284
|
+
|
260
285
|
class CreateEntitySchemaField(BaseOperation):
|
261
|
-
order: ClassVar[int] =
|
286
|
+
order: ClassVar[int] = 110
|
262
287
|
|
263
288
|
def __init__(
|
264
289
|
self,
|
@@ -345,7 +370,7 @@ class CreateEntitySchemaField(BaseOperation):
|
|
345
370
|
|
346
371
|
|
347
372
|
class ArchiveEntitySchemaField(BaseOperation):
|
348
|
-
order: ClassVar[int] =
|
373
|
+
order: ClassVar[int] = 140
|
349
374
|
|
350
375
|
def __init__(
|
351
376
|
self, wh_schema_name: str, wh_field_name: str, index: int | None = None
|
@@ -396,7 +421,7 @@ class ArchiveEntitySchemaField(BaseOperation):
|
|
396
421
|
|
397
422
|
|
398
423
|
class UnarchiveEntitySchemaField(BaseOperation):
|
399
|
-
order: ClassVar[int] =
|
424
|
+
order: ClassVar[int] = 120
|
400
425
|
|
401
426
|
def __init__(
|
402
427
|
self, wh_schema_name: str, wh_field_name: str, index: int | None = None
|
@@ -443,7 +468,7 @@ class UnarchiveEntitySchemaField(BaseOperation):
|
|
443
468
|
|
444
469
|
|
445
470
|
class UpdateEntitySchemaField(BaseOperation):
|
446
|
-
order: ClassVar[int] =
|
471
|
+
order: ClassVar[int] = 130
|
447
472
|
|
448
473
|
def __init__(
|
449
474
|
self,
|
@@ -514,7 +539,7 @@ class UpdateEntitySchemaField(BaseOperation):
|
|
514
539
|
|
515
540
|
|
516
541
|
class ReorderEntitySchemaFields(BaseOperation):
|
517
|
-
order: ClassVar[int] =
|
542
|
+
order: ClassVar[int] = 160
|
518
543
|
|
519
544
|
def __init__(self, wh_schema_name: str, new_order: list[str]) -> None:
|
520
545
|
self.wh_schema_name = wh_schema_name
|
@@ -5,7 +5,11 @@ from typing import Any
|
|
5
5
|
import requests
|
6
6
|
from pydantic import BaseModel
|
7
7
|
|
8
|
+
from liminal.base.name_template_parts import (
|
9
|
+
NameTemplatePart,
|
10
|
+
)
|
8
11
|
from liminal.base.properties.base_field_properties import BaseFieldProperties
|
12
|
+
from liminal.base.properties.base_name_template import BaseNameTemplate
|
9
13
|
from liminal.base.properties.base_schema_properties import BaseSchemaProperties
|
10
14
|
from liminal.connection import BenchlingService
|
11
15
|
from liminal.dropdowns.utils import get_benchling_dropdown_summary_by_name
|
@@ -15,6 +19,7 @@ from liminal.enums import (
|
|
15
19
|
BenchlingFolderItemType,
|
16
20
|
BenchlingSequenceType,
|
17
21
|
)
|
22
|
+
from liminal.enums.name_template_part_type import NameTemplatePartType
|
18
23
|
from liminal.mappers import (
|
19
24
|
convert_entity_type_to_api_entity_type,
|
20
25
|
convert_field_type_to_api_field_type,
|
@@ -32,6 +37,73 @@ class FieldRequiredLinkShortModel(BaseModel):
|
|
32
37
|
storableSchema: dict[str, Any] | None = None
|
33
38
|
|
34
39
|
|
40
|
+
class NameTemplatePartModel(BaseModel):
|
41
|
+
"""A pydantic model to define a part of a name template."""
|
42
|
+
|
43
|
+
type: NameTemplatePartType
|
44
|
+
fieldId: str | None = None
|
45
|
+
text: str | None = None
|
46
|
+
datetimeFormat: str | None = None
|
47
|
+
|
48
|
+
@classmethod
|
49
|
+
def from_name_template_part(
|
50
|
+
cls, part: NameTemplatePart, fields: list[TagSchemaFieldModel] | None = None
|
51
|
+
) -> NameTemplatePartModel:
|
52
|
+
data = part.model_dump()
|
53
|
+
field_id = None
|
54
|
+
if wh_field_name := data.get("wh_field_name"):
|
55
|
+
field = next((f for f in fields if f.systemName == wh_field_name), None)
|
56
|
+
if field is None:
|
57
|
+
raise ValueError(f"Field {wh_field_name} not found in fields")
|
58
|
+
field_id = field.id
|
59
|
+
if part.component_type == NameTemplatePartType.CHILD_ENTITY_LOT_NUMBER:
|
60
|
+
if not field.isParentLink:
|
61
|
+
raise ValueError(
|
62
|
+
f"Field {wh_field_name} is not a parent link field. The field for type {part.component_type} must be a parent link field."
|
63
|
+
)
|
64
|
+
return cls(
|
65
|
+
type=part.component_type,
|
66
|
+
fieldId=field_id,
|
67
|
+
text=data.get("value"),
|
68
|
+
)
|
69
|
+
|
70
|
+
def to_name_template_part(
|
71
|
+
self, fields: list[TagSchemaFieldModel] | None = None
|
72
|
+
) -> NameTemplatePart:
|
73
|
+
part_cls = NameTemplatePart.resolve_type(self.type)
|
74
|
+
if self.fieldId:
|
75
|
+
field = next((f for f in fields if f.apiId == self.fieldId), None)
|
76
|
+
if field is None:
|
77
|
+
raise ValueError(f"Field {self.fieldId} not found in fields")
|
78
|
+
return part_cls(wh_field_name=field.systemName, value=self.text)
|
79
|
+
return part_cls(value=self.text)
|
80
|
+
|
81
|
+
|
82
|
+
class TagSchemaConstraint(BaseModel):
|
83
|
+
"""
|
84
|
+
A class to define a constraint on an entity schema.
|
85
|
+
"""
|
86
|
+
|
87
|
+
areUniqueResiduesCaseSensitive: bool | None = None
|
88
|
+
fields: list[TagSchemaFieldModel] | None = None
|
89
|
+
uniqueCanonicalSmilers: bool | None = None
|
90
|
+
uniqueResidues: bool | None = None
|
91
|
+
|
92
|
+
@classmethod
|
93
|
+
def from_constraint_fields(
|
94
|
+
cls, constraint_fields: list[TagSchemaFieldModel], bases: bool
|
95
|
+
) -> TagSchemaConstraint:
|
96
|
+
"""
|
97
|
+
Generates a Constraint object from a set of constraint fields to create a constraint on a schema.
|
98
|
+
"""
|
99
|
+
return cls(
|
100
|
+
fields=constraint_fields,
|
101
|
+
uniqueResidues=bases,
|
102
|
+
uniqueCanonicalSmilers=False,
|
103
|
+
areUniqueResiduesCaseSensitive=False,
|
104
|
+
)
|
105
|
+
|
106
|
+
|
35
107
|
class UpdateTagSchemaModel(BaseModel):
|
36
108
|
"""A pydantic model to define the input for the internal tag schema update endpoint."""
|
37
109
|
|
@@ -46,6 +118,9 @@ class UpdateTagSchemaModel(BaseModel):
|
|
46
118
|
sequenceType: BenchlingSequenceType | None = None
|
47
119
|
shouldCreateAsOligo: bool | None = None
|
48
120
|
showResidues: bool | None = None
|
121
|
+
includeRegistryIdInChips: bool | None = None
|
122
|
+
useOrganizationCollectionAliasForDisplayLabel: bool | None = None
|
123
|
+
constraint: TagSchemaConstraint | None = None
|
49
124
|
|
50
125
|
|
51
126
|
class CreateTagSchemaFieldModel(BaseModel):
|
@@ -243,7 +318,7 @@ class TagSchemaModel(BaseModel):
|
|
243
318
|
authParentOption: str | None
|
244
319
|
batchSchemaId: str | None
|
245
320
|
childEntitySchemaSummaries: list[Any] | None
|
246
|
-
constraint:
|
321
|
+
constraint: TagSchemaConstraint | None
|
247
322
|
containableType: str | None
|
248
323
|
fields: list[TagSchemaFieldModel]
|
249
324
|
folderItemType: BenchlingFolderItemType
|
@@ -256,7 +331,7 @@ class TagSchemaModel(BaseModel):
|
|
256
331
|
mixtureSchemaConfig: MixtureSchemaConfig | None
|
257
332
|
name: str | None
|
258
333
|
nameTemplateFields: list[str] | None
|
259
|
-
nameTemplateParts: list[
|
334
|
+
nameTemplateParts: list[NameTemplatePartModel] | None
|
260
335
|
permissions: dict[str, bool] | None
|
261
336
|
prefix: str | None
|
262
337
|
registryId: str | None
|
@@ -299,7 +374,11 @@ class TagSchemaModel(BaseModel):
|
|
299
374
|
if len(filtered_schemas) == len(wh_schema_names):
|
300
375
|
break
|
301
376
|
else:
|
302
|
-
|
377
|
+
for schema in schemas_data:
|
378
|
+
try:
|
379
|
+
filtered_schemas.append(cls.model_validate(schema))
|
380
|
+
except Exception as e:
|
381
|
+
print(f"Error validating schema {schema['sqlIdentifier']}: {e}")
|
303
382
|
return filtered_schemas
|
304
383
|
|
305
384
|
@classmethod
|
@@ -333,6 +412,11 @@ class TagSchemaModel(BaseModel):
|
|
333
412
|
return field
|
334
413
|
raise ValueError(f"Field '{wh_field_name}' not found in schema")
|
335
414
|
|
415
|
+
def get_internal_name_template_parts(self) -> list[NameTemplatePart]:
|
416
|
+
return [
|
417
|
+
part.to_name_template_part(self.fields) for part in self.nameTemplateParts
|
418
|
+
]
|
419
|
+
|
336
420
|
def update_schema_props(self, update_diff: dict[str, Any]) -> TagSchemaModel:
|
337
421
|
"""Updates the schema properties given the schema properties defined in code."""
|
338
422
|
update_diff_names = list(update_diff.keys())
|
@@ -347,6 +431,46 @@ class TagSchemaModel(BaseModel):
|
|
347
431
|
self.labelingStrategies = [o.value for o in update_props.naming_strategies]
|
348
432
|
if "mixture_schema_config" in update_diff_names:
|
349
433
|
self.mixtureSchemaConfig = update_props.mixture_schema_config
|
434
|
+
if "use_registry_id_as_label" in update_diff_names:
|
435
|
+
self.useOrganizationCollectionAliasForDisplayLabel = (
|
436
|
+
update_props.use_registry_id_as_label
|
437
|
+
)
|
438
|
+
if "include_registry_id_in_chips" in update_diff_names:
|
439
|
+
self.includeRegistryIdInChips = update_props.include_registry_id_in_chips
|
440
|
+
|
441
|
+
if "constraint_fields" in update_diff_names:
|
442
|
+
if update_props.constraint_fields:
|
443
|
+
has_bases = False
|
444
|
+
if "bases" in update_props.constraint_fields:
|
445
|
+
has_bases = True
|
446
|
+
update_props.constraint_fields.discard("bases")
|
447
|
+
constraint_fields = [
|
448
|
+
f
|
449
|
+
for f in self.fields
|
450
|
+
if f.systemName in update_props.constraint_fields
|
451
|
+
]
|
452
|
+
self.constraint = TagSchemaConstraint.from_constraint_fields(
|
453
|
+
constraint_fields, has_bases
|
454
|
+
)
|
455
|
+
else:
|
456
|
+
self.constraint = None
|
457
|
+
|
458
|
+
if "constraint_fields" in update_diff_names:
|
459
|
+
if update_props.constraint_fields:
|
460
|
+
has_bases = False
|
461
|
+
if "bases" in update_props.constraint_fields:
|
462
|
+
has_bases = True
|
463
|
+
update_props.constraint_fields.discard("bases")
|
464
|
+
constraint_fields = [
|
465
|
+
f
|
466
|
+
for f in self.fields
|
467
|
+
if f.systemName in update_props.constraint_fields
|
468
|
+
]
|
469
|
+
self.constraint = TagSchemaConstraint.from_constraint_fields(
|
470
|
+
constraint_fields, has_bases
|
471
|
+
)
|
472
|
+
else:
|
473
|
+
self.constraint = None
|
350
474
|
|
351
475
|
self.prefix = (
|
352
476
|
update_props.prefix if "prefix" in update_diff_names else self.prefix
|
@@ -359,6 +483,25 @@ class TagSchemaModel(BaseModel):
|
|
359
483
|
self.name = update_props.name if "name" in update_diff_names else self.name
|
360
484
|
return self
|
361
485
|
|
486
|
+
def update_name_template(
|
487
|
+
self, update_name_template: BaseNameTemplate
|
488
|
+
) -> TagSchemaModel:
|
489
|
+
update_diff_names = update_name_template.model_dump(exclude_unset=True).keys()
|
490
|
+
self.nameTemplateParts = (
|
491
|
+
[
|
492
|
+
NameTemplatePartModel.from_name_template_part(part, self.fields)
|
493
|
+
for part in update_name_template.parts
|
494
|
+
]
|
495
|
+
if "parts" in update_diff_names
|
496
|
+
else self.nameTemplateParts
|
497
|
+
)
|
498
|
+
self.shouldOrderNamePartsBySequence = (
|
499
|
+
update_name_template.order_name_parts_by_sequence
|
500
|
+
if "order_name_parts_by_sequence" in update_diff_names
|
501
|
+
else self.shouldOrderNamePartsBySequence
|
502
|
+
)
|
503
|
+
return self
|
504
|
+
|
362
505
|
def update_field(
|
363
506
|
self,
|
364
507
|
benchling_service: BenchlingService,
|
liminal/entity_schemas/utils.py
CHANGED
@@ -9,6 +9,7 @@ from liminal.mappers import (
|
|
9
9
|
convert_api_entity_type_to_entity_type,
|
10
10
|
convert_api_field_type_to_field_type,
|
11
11
|
)
|
12
|
+
from liminal.orm.name_template import NameTemplate
|
12
13
|
from liminal.orm.schema_properties import MixtureSchemaConfig, SchemaProperties
|
13
14
|
|
14
15
|
|
@@ -16,7 +17,7 @@ def get_converted_tag_schemas(
|
|
16
17
|
benchling_service: BenchlingService,
|
17
18
|
include_archived: bool = False,
|
18
19
|
wh_schema_names: set[str] | None = None,
|
19
|
-
) -> list[tuple[SchemaProperties, dict[str, BaseFieldProperties]]]:
|
20
|
+
) -> list[tuple[SchemaProperties, NameTemplate, dict[str, BaseFieldProperties]]]:
|
20
21
|
"""This functions gets all Tag schemas from Benchling and converts them to our internal representation of a schema and its fields.
|
21
22
|
It parses the Tag Schema and creates SchemaProperties and a list of FieldProperties for each field in the schema.
|
22
23
|
If include_archived is True, it will include archived schemas and archived fields.
|
@@ -40,10 +41,15 @@ def convert_tag_schema_to_internal_schema(
|
|
40
41
|
tag_schema: TagSchemaModel,
|
41
42
|
dropdowns_map: dict[str, str],
|
42
43
|
include_archived_fields: bool = False,
|
43
|
-
) -> tuple[SchemaProperties, dict[str, BaseFieldProperties]]:
|
44
|
+
) -> tuple[SchemaProperties, NameTemplate, dict[str, BaseFieldProperties]]:
|
44
45
|
all_fields = tag_schema.allFields
|
45
46
|
if not include_archived_fields:
|
46
47
|
all_fields = [f for f in all_fields if not f.archiveRecord]
|
48
|
+
constraint_fields: set[str] | None = None
|
49
|
+
if tag_schema.constraint:
|
50
|
+
constraint_fields = set([f.systemName for f in tag_schema.constraint.fields])
|
51
|
+
if tag_schema.constraint.uniqueResidues:
|
52
|
+
constraint_fields.add("bases")
|
47
53
|
return (
|
48
54
|
SchemaProperties(
|
49
55
|
name=tag_schema.name,
|
@@ -63,7 +69,14 @@ def convert_tag_schema_to_internal_schema(
|
|
63
69
|
BenchlingNamingStrategy(strategy)
|
64
70
|
for strategy in tag_schema.labelingStrategies
|
65
71
|
),
|
72
|
+
constraint_fields=constraint_fields,
|
66
73
|
_archived=tag_schema.archiveRecord is not None,
|
74
|
+
use_registry_id_as_label=tag_schema.useOrganizationCollectionAliasForDisplayLabel,
|
75
|
+
include_registry_id_in_chips=tag_schema.includeRegistryIdInChips,
|
76
|
+
),
|
77
|
+
NameTemplate(
|
78
|
+
parts=tag_schema.get_internal_name_template_parts(),
|
79
|
+
order_name_parts_by_sequence=tag_schema.shouldOrderNamePartsBySequence,
|
67
80
|
),
|
68
81
|
{
|
69
82
|
f.systemName: convert_tag_schema_field_to_field_properties(f, dropdowns_map)
|
liminal/enums/__init__.py
CHANGED
@@ -4,5 +4,4 @@ from liminal.enums.benchling_entity_type import BenchlingEntityType
|
|
4
4
|
from liminal.enums.benchling_field_type import BenchlingFieldType
|
5
5
|
from liminal.enums.benchling_folder_item_type import BenchlingFolderItemType
|
6
6
|
from liminal.enums.benchling_naming_strategy import BenchlingNamingStrategy
|
7
|
-
from liminal.enums.benchling_report_level import BenchlingReportLevel
|
8
7
|
from liminal.enums.benchling_sequence_type import BenchlingSequenceType
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from liminal.base.str_enum import StrEnum
|
2
|
+
|
3
|
+
|
4
|
+
class NameTemplatePartType(StrEnum):
|
5
|
+
SEPARATOR = "SEPARATOR"
|
6
|
+
TEXT = "TEXT"
|
7
|
+
CREATION_YEAR = "CREATED_AT_YEAR"
|
8
|
+
CREATION_DATE = "CREATED_AT_DATE"
|
9
|
+
FIELD = "FIELD"
|
10
|
+
REGISTRY_IDENTIFIER_NUMBER = "REGISTRY_IDENTIFIER_NUMBER"
|
11
|
+
PROJECT = "PROJECT"
|
12
|
+
CHILD_ENTITY_LOT_NUMBER = "CHILD_ENTITY_LOT_NUMBER"
|
liminal/external/__init__.py
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
# flake8: noqa: F401
|
2
2
|
from liminal.base.base_operation import BaseOperation
|
3
|
+
from liminal.base.name_template_parts import (
|
4
|
+
CreationDatePart,
|
5
|
+
CreationYearPart,
|
6
|
+
FieldPart,
|
7
|
+
ProjectPart,
|
8
|
+
RegistryIdentifierNumberPart,
|
9
|
+
SeparatorPart,
|
10
|
+
TextPart,
|
11
|
+
)
|
3
12
|
from liminal.base.properties.base_field_properties import BaseFieldProperties
|
13
|
+
from liminal.base.properties.base_name_template import BaseNameTemplate
|
4
14
|
from liminal.base.properties.base_schema_properties import BaseSchemaProperties
|
5
15
|
from liminal.dropdowns.operations import (
|
6
16
|
ArchiveDropdown,
|
@@ -22,6 +32,7 @@ from liminal.entity_schemas.operations import (
|
|
22
32
|
UnarchiveEntitySchemaField,
|
23
33
|
UpdateEntitySchema,
|
24
34
|
UpdateEntitySchemaField,
|
35
|
+
UpdateEntitySchemaNameTemplate,
|
25
36
|
)
|
26
37
|
from liminal.enums import (
|
27
38
|
BenchlingAPIFieldType,
|
@@ -29,6 +40,5 @@ from liminal.enums import (
|
|
29
40
|
BenchlingFieldType,
|
30
41
|
BenchlingFolderItemType,
|
31
42
|
BenchlingNamingStrategy,
|
32
|
-
BenchlingReportLevel,
|
33
43
|
BenchlingSequenceType,
|
34
44
|
)
|
@@ -30,7 +30,8 @@ class RevisionsTimeline:
|
|
30
30
|
)
|
31
31
|
all_raw_revisions: list[Revision] = []
|
32
32
|
for file_path in versions_dir_path.iterdir():
|
33
|
-
|
33
|
+
if file_path.is_file() and file_path.suffix == ".py":
|
34
|
+
all_raw_revisions.append(Revision.parse_from_file(file_path))
|
34
35
|
self.revisions_map = self.validate_revisions(all_raw_revisions)
|
35
36
|
|
36
37
|
def get_first_revision(self) -> Revision:
|