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
liminal/validation/__init__.py
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
1
|
+
import inspect
|
2
2
|
from datetime import datetime
|
3
|
-
from
|
3
|
+
from functools import wraps
|
4
|
+
from typing import TYPE_CHECKING, Callable
|
4
5
|
|
5
6
|
from pydantic import BaseModel, ConfigDict
|
6
7
|
|
7
|
-
from liminal.
|
8
|
+
from liminal.utils import pascalize
|
9
|
+
from liminal.validation.validation_severity import ValidationSeverity
|
8
10
|
|
9
11
|
if TYPE_CHECKING:
|
10
|
-
from liminal.orm.base_model import BaseModel as
|
12
|
+
from liminal.orm.base_model import BaseModel as BenchlingBaseModel
|
11
13
|
|
12
14
|
|
13
15
|
class BenchlingValidatorReport(BaseModel):
|
@@ -20,7 +22,7 @@ class BenchlingValidatorReport(BaseModel):
|
|
20
22
|
Indicates whether the validation passed or failed.
|
21
23
|
model : str
|
22
24
|
The name of the model being validated. (eg: NGSSample)
|
23
|
-
level :
|
25
|
+
level : ValidationSeverity
|
24
26
|
The severity level of the validation report.
|
25
27
|
validator_name : str | None
|
26
28
|
The name of the validator that generated this report. (eg: BioContextValidator)
|
@@ -44,7 +46,7 @@ class BenchlingValidatorReport(BaseModel):
|
|
44
46
|
|
45
47
|
valid: bool
|
46
48
|
model: str
|
47
|
-
level:
|
49
|
+
level: ValidationSeverity
|
48
50
|
validator_name: str | None = None
|
49
51
|
entity_id: str | None = None
|
50
52
|
registry_id: str | None = None
|
@@ -57,89 +59,35 @@ class BenchlingValidatorReport(BaseModel):
|
|
57
59
|
|
58
60
|
model_config = ConfigDict(extra="allow")
|
59
61
|
|
60
|
-
|
61
|
-
class BenchlingValidator(ABC):
|
62
|
-
"""Base class for benchling validators."""
|
63
|
-
|
64
|
-
def __str__(self) -> str:
|
65
|
-
return self.__class__.__name__ + "()"
|
66
|
-
|
67
|
-
def _prefix(self) -> str:
|
68
|
-
"""Creates a prefix for the formatted error message which includes the class name and any instance variables.
|
69
|
-
Ex: "BenchlingValidator(field_name=sample_code, field_value=123):"
|
70
|
-
"""
|
71
|
-
prefix = f"{self.__class__.__name__}"
|
72
|
-
if vars(self):
|
73
|
-
prefix += "("
|
74
|
-
for key, val in vars(self).items():
|
75
|
-
prefix += f"{key}={self.truncate_msg(val, max_len=50)}, "
|
76
|
-
prefix = prefix[:-2] + "):"
|
77
|
-
else:
|
78
|
-
prefix += ":"
|
79
|
-
return prefix
|
80
|
-
|
81
|
-
@abstractmethod
|
82
|
-
def validate(self, entity: type["BaseModelBenchling"]) -> BenchlingValidatorReport:
|
83
|
-
"""Abstract method that all validator subclass must implement. Each subclass will have a differently defined validation
|
84
|
-
function that runs on the given benchling entity.
|
85
|
-
|
86
|
-
Parameters
|
87
|
-
----------
|
88
|
-
entity : type["BaseModelBenchling"]
|
89
|
-
The Benchling entity to validate.
|
90
|
-
|
91
|
-
Returns
|
92
|
-
-------
|
93
|
-
BenchlingValidatorReport
|
94
|
-
A report indicating whether the validation passed or failed, and any additional metadata.
|
95
|
-
"""
|
96
|
-
raise NotImplementedError
|
97
|
-
|
98
|
-
def __getattribute__(self, name: str) -> Any:
|
99
|
-
attr = super().__getattribute__(name)
|
100
|
-
if name == "validate":
|
101
|
-
# Wrap the validate method in a try-except block to catch any unexpected errors that occur during validation.
|
102
|
-
# If an unexpected error occurs, return a BenchlingValidatorReport with the unexpected error message.
|
103
|
-
def try_except_wrapped_func(
|
104
|
-
*args: Any, **kwargs: dict
|
105
|
-
) -> BenchlingValidatorReport:
|
106
|
-
try:
|
107
|
-
return attr(*args, **kwargs)
|
108
|
-
except Exception as e:
|
109
|
-
entity: type[BaseModelBenchling] = args[0]
|
110
|
-
return BenchlingValidatorReport(
|
111
|
-
valid=False,
|
112
|
-
model=entity.__class__.__name__,
|
113
|
-
validator_name=self.__class__.__name__,
|
114
|
-
level=BenchlingReportLevel.UNEXPECTED,
|
115
|
-
entity_id=entity.id,
|
116
|
-
registry_id=entity.file_registry_id,
|
117
|
-
entity_name=entity.name,
|
118
|
-
web_url=entity.url if entity.url else None,
|
119
|
-
creator_name=entity.creator.name if entity.creator else None,
|
120
|
-
creator_email=entity.creator.email if entity.creator else None,
|
121
|
-
updated_date=entity.modified_at,
|
122
|
-
message=f"Unexpected exception: {e}",
|
123
|
-
)
|
124
|
-
|
125
|
-
return try_except_wrapped_func
|
126
|
-
return attr
|
127
|
-
|
128
62
|
@classmethod
|
129
|
-
def
|
63
|
+
def create_validation_report(
|
130
64
|
cls,
|
131
65
|
valid: bool,
|
132
|
-
level:
|
133
|
-
entity: type["
|
66
|
+
level: ValidationSeverity,
|
67
|
+
entity: type["BenchlingBaseModel"],
|
68
|
+
validator_name: str,
|
134
69
|
message: str | None = None,
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
70
|
+
) -> "BenchlingValidatorReport":
|
71
|
+
"""Creates a BenchlingValidatorReport with the given parameters.
|
72
|
+
|
73
|
+
Parameters
|
74
|
+
----------
|
75
|
+
valid: bool
|
76
|
+
Indicates whether the validation passed or failed.
|
77
|
+
level: ValidationSeverity
|
78
|
+
The severity level of the validation report.
|
79
|
+
entity: type[BenchlingBaseModel]
|
80
|
+
The entity being validated.
|
81
|
+
validator_name: str
|
82
|
+
The name of the validator that generated this report.
|
83
|
+
message: str | None
|
84
|
+
A message describing the result of the validation.
|
85
|
+
"""
|
86
|
+
return cls(
|
139
87
|
valid=valid,
|
140
88
|
level=level,
|
141
89
|
model=entity.__class__.__name__,
|
142
|
-
validator_name=
|
90
|
+
validator_name=validator_name,
|
143
91
|
entity_id=entity.id,
|
144
92
|
registry_id=entity.file_registry_id,
|
145
93
|
entity_name=entity.name,
|
@@ -148,31 +96,59 @@ class BenchlingValidator(ABC):
|
|
148
96
|
creator_email=entity.creator.email if entity.creator else None,
|
149
97
|
updated_date=entity.modified_at,
|
150
98
|
message=message,
|
151
|
-
**kwargs,
|
152
99
|
)
|
153
100
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
101
|
+
|
102
|
+
def liminal_validator(
|
103
|
+
validator_level: ValidationSeverity = ValidationSeverity.LOW,
|
104
|
+
validator_name: str | None = None,
|
105
|
+
) -> Callable:
|
106
|
+
"""A decorator that validates a function that takes a Benchling entity as an argument and returns None.
|
107
|
+
|
108
|
+
Parameters:
|
109
|
+
validator_level: ValidationSeverity
|
110
|
+
The level of the validator.
|
111
|
+
validator_name: str | None
|
112
|
+
The name of the validator. Defaults to the pascalized name of the function.
|
113
|
+
"""
|
114
|
+
|
115
|
+
def decorator(func: Callable[[type["BenchlingBaseModel"]], None]) -> Callable:
|
116
|
+
"""Decorator that validates a function that takes a Benchling entity as an argument and returns None."""
|
117
|
+
sig = inspect.signature(func)
|
118
|
+
params = list(sig.parameters.values())
|
119
|
+
if not params or params[0].name != "self" or len(params) > 1:
|
120
|
+
raise TypeError(
|
121
|
+
"Validator must defined in a schema class, where the only argument to this validator must be 'self'."
|
122
|
+
)
|
123
|
+
|
124
|
+
if sig.return_annotation is not None:
|
125
|
+
raise TypeError("The return type must be None.")
|
126
|
+
|
127
|
+
nonlocal validator_name
|
128
|
+
if validator_name is None:
|
129
|
+
validator_name = pascalize(func.__name__)
|
130
|
+
|
131
|
+
@wraps(func)
|
132
|
+
def wrapper(self: type["BenchlingBaseModel"]) -> BenchlingValidatorReport:
|
133
|
+
"""Wrapper that runs the validator function and returns a BenchlingValidatorReport."""
|
134
|
+
try:
|
135
|
+
func(self)
|
136
|
+
except Exception as e:
|
137
|
+
return BenchlingValidatorReport.create_validation_report(
|
138
|
+
valid=False,
|
139
|
+
level=validator_level,
|
140
|
+
entity=self,
|
141
|
+
validator_name=validator_name,
|
142
|
+
message=str(e),
|
143
|
+
)
|
144
|
+
return BenchlingValidatorReport.create_validation_report(
|
145
|
+
valid=True,
|
146
|
+
level=validator_level,
|
147
|
+
entity=self,
|
148
|
+
validator_name=validator_name,
|
149
|
+
)
|
150
|
+
|
151
|
+
setattr(wrapper, "_is_liminal_validator", True)
|
152
|
+
return wrapper
|
153
|
+
|
154
|
+
return decorator
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from liminal.base.str_enum import StrEnum
|
2
2
|
|
3
3
|
|
4
|
-
class
|
5
|
-
"""This enum represents the different levels of validation that can be returned by
|
4
|
+
class ValidationSeverity(StrEnum):
|
5
|
+
"""This enum represents the different levels of validation that can be returned by Liminal."""
|
6
6
|
|
7
7
|
LOW = "LOW"
|
8
8
|
MED = "MED"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: liminal-orm
|
3
|
-
Version:
|
3
|
+
Version: 2.0.0
|
4
4
|
Summary: An ORM and toolkit that builds on top of Benchling's platform to keep your schemas and downstream code dependencies in sync.
|
5
5
|
Home-page: https://github.com/dynotx/liminal-orm
|
6
6
|
Author: DynoTx Open Source
|
@@ -41,13 +41,12 @@ Liminal ORM<sup>1</sup> is an open-source Python package that builds on [Benchli
|
|
41
41
|
Liminal provides an ORM framework using [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy) along with a schema migration service inspired by [Alembic](https://alembic.sqlalchemy.org/en/latest/). This allows you to define your Benchling schemas in code and create a *single source of truth* that synchronizes between your upstream Benchling tenant(s) and downstream dependencies. By creating a standard interface and through using one-line CLI<sup>3</sup> commands, Liminal enables a code-first approach for managing Benchling tenants and accessing Benchling data. With the schemas defined in code, you can also take advantage of the additional capabilities that the Liminal toolkit provides. This includes:
|
42
42
|
|
43
43
|
- The ability to run migrations to your Benchling tenant(s) through an easy to use CLI.
|
44
|
-
- One source of truth defined in code for your Benchling schema model that your many Benchling tenants can stay in sync with.
|
45
44
|
- Easy to implement validation rules to reflect business logic for all of your Benchling entities.
|
46
45
|
- Strongly typed queries for all your Benchling entities.
|
47
46
|
- CI/CD integration with GitHub Actions to ensure that your Benchling schemas and code are always in sync.
|
48
47
|
- And more based on community contributions/feedback :)
|
49
48
|
|
50
|
-
If you are a Benchling user, try out Liminal by following the [**Quick Start Guide**](https://dynotx.github.io/liminal-orm/getting-started/prerequisites/)! Reach out in the [
|
49
|
+
If you are a Benchling user, try out Liminal by following the [**Quick Start Guide**](https://dynotx.github.io/liminal-orm/getting-started/prerequisites/)! Reach out in the [Slack community](https://join.slack.com/t/liminalorm/shared_invite/zt-2ujrp07s3-bctook4e~cAjn1LgOLVY~Q) (preferred method) with any questions or to simply introduce yourself! If there is something blocking you from using Liminal or you're having trouble setting Liminal up, please share in [Issues](https://github.com/dynotx/liminal-orm/issues) or reach out directly (info below).
|
51
50
|
|
52
51
|
Benchling is an industry standard cloud platform for life sciences R&D. Liminal builds on top of Benchling's platform and assumes that you already have a Benchling tenant set up and have (or have access to) an admin user account. If not, learn more about getting started with Benchling [here](https://www.benchling.com/explore-benchling)!
|
53
52
|
|
@@ -67,6 +66,7 @@ If you or your organization use Liminal, please consider adding yourself or your
|
|
67
66
|
- [Community](#community)
|
68
67
|
- [Contributing](#contributing)
|
69
68
|
- [License](#license)
|
69
|
+
- [Direct Contact](#direct-contact)
|
70
70
|
- [Acknowledgements](#acknowledgements)
|
71
71
|
- [Footnotes](#footnotes)
|
72
72
|
|
@@ -83,22 +83,19 @@ With your schemas defined in code, you can now take advantage of the additional
|
|
83
83
|
1. Entity validation: Easily create custom validation rules for your Benchling entities.
|
84
84
|
|
85
85
|
```python
|
86
|
-
from liminal.validation import
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
if
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
valid = False
|
100
|
-
message = "Cook time is required if cook temp is set"
|
101
|
-
return self.create_report(valid, BenchlingReportLevel.MED, entity, message)
|
86
|
+
from liminal.validation import ValidationSeverity, liminal_validator
|
87
|
+
|
88
|
+
class Pizza(BaseModel, CustomEntityMixin):
|
89
|
+
...
|
90
|
+
|
91
|
+
@liminal_validator(ValidationSeverity.MED)
|
92
|
+
def cook_time_and_temp_validator(self) -> None:
|
93
|
+
if self.cook_time is not None and self.cook_temp is None:
|
94
|
+
raise ValueError("Cook temp is required if cook time is set")
|
95
|
+
if self.cook_time is None and self.cook_temp is not None:
|
96
|
+
raise ValueError("Cook time is required if cook temp is set")
|
97
|
+
|
98
|
+
validation_reports = Pizza.validate(session)
|
102
99
|
```
|
103
100
|
|
104
101
|
2. Strongly typed queries: Write type-safe queries using SQLAlchemy to access your Benchling entities.
|
@@ -106,7 +103,6 @@ With your schemas defined in code, you can now take advantage of the additional
|
|
106
103
|
```python
|
107
104
|
with BenchlingSession(benchling_connection, with_db=True) as session:
|
108
105
|
pizza = session.query(Pizza).filter(Pizza.name == "Margherita").first()
|
109
|
-
print(pizza)
|
110
106
|
```
|
111
107
|
|
112
108
|
3. CI/CD integration: Use Liminal to automatically generate and apply your revision files to your Benchling tenant(s) as part of your CI/CD pipeline.
|
@@ -136,6 +132,7 @@ Liminal ORM is distributed under the [Apache License, Version 2.0](./LICENSE.md)
|
|
136
132
|
|
137
133
|
## [Direct Contact](#direct-contact)
|
138
134
|
|
135
|
+
- Liminal Community Slack group: [Join here](https://join.slack.com/t/liminalorm/shared_invite/zt-2ujrp07s3-bctook4e~cAjn1LgOLVY~Q)
|
139
136
|
- Email: <opensource@dynotx.com>
|
140
137
|
- LinkedIn: [Nirmit Damania](https://www.linkedin.com/in/nirmit-damania/)
|
141
138
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
liminal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
liminal/base/base_dropdown.py,sha256=Unk4l_5Y8rj_eSWYqzFi2BAFSQToQDWW2qdXwiCHTg8,2523
|
3
|
-
liminal/base/base_operation.py,sha256=
|
4
|
-
liminal/base/base_validation_filters.py,sha256=
|
3
|
+
liminal/base/base_operation.py,sha256=RjGRaCTNQ5oVI4PAQ5D3svymw_HAcGvzBXWWrMRo29k,3128
|
4
|
+
liminal/base/base_validation_filters.py,sha256=kHG3G5gXkuNHQosMTrxRc57OTmczcaoSx0DmkrScIr4,1043
|
5
5
|
liminal/base/compare_operation.py,sha256=hkpv4ewHhxy4dlTPKgJuzBjsAqO6Km7OrrKB44pRA_o,352
|
6
|
-
liminal/base/
|
7
|
-
liminal/base/properties/
|
6
|
+
liminal/base/name_template_parts.py,sha256=KCGXAcCuOqCjlgYn-mw1K7fwDI92D20l-FnlpEVrbM8,2771
|
7
|
+
liminal/base/properties/base_field_properties.py,sha256=NvuQjYZ5U_2363P2c8FXmmLfOtdzUqTuZTjDDfXnO-E,4922
|
8
|
+
liminal/base/properties/base_name_template.py,sha256=EHytur3jcPSRx-it_2elYSjdgx7OOr206qyf2bFcweg,3151
|
9
|
+
liminal/base/properties/base_schema_properties.py,sha256=pVeIVHea-3Wt0fde9CsOvluwVmYMbsMhGeSncRL2Ats,5351
|
8
10
|
liminal/base/str_enum.py,sha256=jF3d-Lo8zsHUe6GsctX2L-TSj92Y3qCYDrTD-saeJoc,210
|
9
11
|
liminal/cli/cli.py,sha256=JxWHLO9KMeMaOnOYwzdH0w71l0477ScFOkWNtTlc97Y,9045
|
10
12
|
liminal/cli/controller.py,sha256=QNj3QO9TMb9hfc6U-VhLuFa0_aohOHZUmvY4XkATPhw,10118
|
@@ -14,50 +16,52 @@ liminal/connection/__init__.py,sha256=3z4pSANIOkc9mh1Xp763oYQuJZDEh4lauN901PU4vq
|
|
14
16
|
liminal/connection/benchling_connection.py,sha256=nALLAA-hPIO2Eb_KhUL-nU3jOlMDSIrPMUgUyDKGRRw,2862
|
15
17
|
liminal/connection/benchling_service.py,sha256=lEYCHF1U8nII8Rn3rMBPTffTFiVFjoFeNmX2Kq36-qE,7170
|
16
18
|
liminal/dropdowns/api.py,sha256=n5oxi1EhkmpmPpNi1LOI4xcIQmk1C069XFaGP5XSBx8,6959
|
17
|
-
liminal/dropdowns/compare.py,sha256
|
19
|
+
liminal/dropdowns/compare.py,sha256=-UbCkeTKx3THwvjMTUubyYVXBkhmvyhEKzwrIzBkthY,7141
|
18
20
|
liminal/dropdowns/generate_files.py,sha256=IqnBs-IyLsIZE0NUkdB99zd5EAF-1f9CPBeblz-GzJE,2041
|
19
|
-
liminal/dropdowns/operations.py,sha256
|
21
|
+
liminal/dropdowns/operations.py,sha256=-TRIsxqnUtrIUjhrt5k_PdiBCDUXsXDzsOUmznJE-6Q,13516
|
20
22
|
liminal/dropdowns/utils.py,sha256=1-H7bTszCUeqeRBpiYXjRjreDzhn1Fd1MFwIsrEI-o4,4109
|
21
|
-
liminal/entity_schemas/api.py,sha256=
|
22
|
-
liminal/entity_schemas/compare.py,sha256=
|
23
|
-
liminal/entity_schemas/entity_schema_models.py,sha256=
|
24
|
-
liminal/entity_schemas/generate_files.py,sha256=
|
25
|
-
liminal/entity_schemas/operations.py,sha256=
|
26
|
-
liminal/entity_schemas/tag_schema_models.py,sha256=
|
27
|
-
liminal/entity_schemas/utils.py,sha256=
|
28
|
-
liminal/enums/__init__.py,sha256=
|
23
|
+
liminal/entity_schemas/api.py,sha256=Emn_Y95cAG9Wis6tpchw6QBVKQh4If86LOdgKk0Ndjw,3575
|
24
|
+
liminal/entity_schemas/compare.py,sha256=CIYglq1F-g9jGc1eRRD4LnNErrH2n__pPIJc4EB1hkM,16570
|
25
|
+
liminal/entity_schemas/entity_schema_models.py,sha256=YDpz1XkNc9e51zah8Z6qCk30gAuXP6xLEYv1Lb3ECpA,6838
|
26
|
+
liminal/entity_schemas/generate_files.py,sha256=ujzofsGlr76z5YadOar0_6ufkjBYZjz0aawBUupIvnU,8878
|
27
|
+
liminal/entity_schemas/operations.py,sha256=rs9EXmHDgnUad2SSfZ3tnDPFA6L-2wvllAGqBwBurMs,24020
|
28
|
+
liminal/entity_schemas/tag_schema_models.py,sha256=BGvfQwjfIcRl3yHmYUM6sQpkbFTUMaeT6ix62fjKp2A,22017
|
29
|
+
liminal/entity_schemas/utils.py,sha256=iZ1_M2r8zKOCFj9QSMdrv-_4XznDn_znAOfoP4Mh1jA,4943
|
30
|
+
liminal/enums/__init__.py,sha256=Ue_3QtElW-JMSWtu4vGsAOFQbYnzHHZUdkWpdkzkKA4,453
|
29
31
|
liminal/enums/benchling_api_field_type.py,sha256=0QamSWEMnxZtedZXlh6zNhSRogS9ZqvWskdHHN19xJo,633
|
30
|
-
liminal/enums/benchling_entity_type.py,sha256=
|
32
|
+
liminal/enums/benchling_entity_type.py,sha256=BS6U8qnRM3I3xTTqp9BbInV7yjPh9gC3ULvN6-zLaCM,624
|
31
33
|
liminal/enums/benchling_field_type.py,sha256=uinDm5Mn_yGK1jlmlRH3NlAlXUzA1guNk8wF6lbUKD4,947
|
32
34
|
liminal/enums/benchling_folder_item_type.py,sha256=Jb-YxCvB8O86_qTsfwtLQOkKGjTWGKHFwIKf24eemYk,248
|
33
35
|
liminal/enums/benchling_naming_strategy.py,sha256=wG3AfnPOui5Qfc0Fihszm5uKWjuc7gdpI8jptNB5A-w,1201
|
34
|
-
liminal/enums/benchling_report_level.py,sha256=HtnSW_yNuRpJ_iQHhzcZudb1Me4QubVg3n9sPSnJiNI,263
|
35
36
|
liminal/enums/benchling_sequence_type.py,sha256=TBI4C5c1XKE4ZXqsz1ApDUzy2wR-04u-M3VO_zLikjM,202
|
36
|
-
liminal/
|
37
|
+
liminal/enums/name_template_part_type.py,sha256=Kv0phZIO_dPN3tLHM0lT2tjUd3zBGqpJQGahEpGjNcU,365
|
38
|
+
liminal/external/__init__.py,sha256=rYg51-fI6FO7H2iZkbIPUzWpSW8MTBKfiTNwLZt3yvY,1265
|
37
39
|
liminal/mappers.py,sha256=O9gc95b7JvfaR8xVrn0X1d0Tcs6Iwh-yhBHXhWSX8i0,9616
|
38
40
|
liminal/migrate/components.py,sha256=2HuFp5KDNhofROMRI-BioUoA4CCjhQ_v_F0QmGJzUBU,3480
|
39
41
|
liminal/migrate/revision.py,sha256=KppU0u-d0JsfPsXsmncxy9Q_XBJyf-o4e16wNZAJODM,7774
|
40
|
-
liminal/migrate/revisions_timeline.py,sha256=
|
42
|
+
liminal/migrate/revisions_timeline.py,sha256=G9VwxPrLhLqKOrIXyxrXyHpujc-72m7omsZjI5-0D0M,14520
|
41
43
|
liminal/migrate/utils.py,sha256=HdSr3N2WN_1S-PLRGVWSMYl-4gIcP-Ph2wPycGi2cGg,3404
|
42
44
|
liminal/orm/base.py,sha256=fFSpiNRYgK5UG7lbXdQGV8KgO8pwjMqt0pycM3rWJ2o,615
|
43
|
-
liminal/orm/base_model.py,sha256=
|
45
|
+
liminal/orm/base_model.py,sha256=RYVQ2kFaxMDGYWL2Lv63KMUZljSyIkdkjoSHoHLU8UU,13892
|
44
46
|
liminal/orm/base_tables/registry_entity.py,sha256=4ET1cepTGjZ3AMFI5q-iMYxMObzXwuUDBD0jNNqCipE,2126
|
45
47
|
liminal/orm/base_tables/schema.py,sha256=7_btCVSUJxjVdGcKVRKL8sKcNw7-_gazTpfEh1jru3o,921
|
46
48
|
liminal/orm/base_tables/user.py,sha256=elRAHj7HgO3iVLK_pNCIwf_9Rl_9k6vkBgaYazoJSQc,818
|
47
49
|
liminal/orm/column.py,sha256=e4JWn97s_4EVJ1LOO5l6iucHQUd39Vl0stqMEj0uet8,5114
|
48
50
|
liminal/orm/mixins.py,sha256=yEeUDF1qEBLP523q8bZra4KtNVK0gwZN9mXJSNe3GEE,4802
|
51
|
+
liminal/orm/name_template.py,sha256=qsppCDPCVBhVZs3Uz-x4QdJbElH6VPlwfRD1BX_pAwE,1739
|
49
52
|
liminal/orm/relationship.py,sha256=Zl4bMHbtDSPx1psGHYnojGGJpA8B8hwcPJdgjB1lmW0,2490
|
50
|
-
liminal/orm/schema_properties.py,sha256=
|
53
|
+
liminal/orm/schema_properties.py,sha256=yv6MOsE_16OWJnGDh2K8wI_054PJwafYmHgY_Awr3XA,3420
|
51
54
|
liminal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
55
|
liminal/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
-
liminal/tests/conftest.py,sha256=
|
56
|
+
liminal/tests/conftest.py,sha256=B463eOfe1uCHDJsUNvG-6tY8Qx8FJMByGDOtuyM87lA,17669
|
54
57
|
liminal/tests/from benchling_sdk.py,sha256=CjRUHFB3iaa4rUPLGOqDiBq5EPKldm-Fd8aQQr92zF4,147
|
55
58
|
liminal/tests/test_dropdown_compare.py,sha256=yHB0ovQlBLRu8-qYkqIPd8VtYEOmOft_93FQM86g_z8,8198
|
56
|
-
liminal/tests/test_entity_schema_compare.py,sha256=
|
57
|
-
liminal/utils.py,sha256=
|
58
|
-
liminal/validation/__init__.py,sha256=
|
59
|
-
|
60
|
-
liminal_orm-
|
61
|
-
liminal_orm-
|
62
|
-
liminal_orm-
|
63
|
-
liminal_orm-
|
59
|
+
liminal/tests/test_entity_schema_compare.py,sha256=JfvrdRfnm77dchHL5mwTLXfrKYW47wANacFJlS5Iw80,18953
|
60
|
+
liminal/utils.py,sha256=radRtRsZmCiNblMvxOX1DH0rcO5TR09kFlp6OONIPBU,2951
|
61
|
+
liminal/validation/__init__.py,sha256=HOjBHCwxvQao6SN_Q5B-JbabG7Z6ff44JIDKLeK96l8,5458
|
62
|
+
liminal/validation/validation_severity.py,sha256=ib03PTZCQHcbBDc01v4gJF53YtA-ANY6QSFnhTV-FbU,259
|
63
|
+
liminal_orm-2.0.0.dist-info/LICENSE.md,sha256=oVA877F_D1AV44dpjsv4f-4k690uNGApX1EtzOo3T8U,11353
|
64
|
+
liminal_orm-2.0.0.dist-info/METADATA,sha256=_ioXetNNEIXfaO4Zmgis49Y86FfiUyGbmpCqy5SJI3E,11056
|
65
|
+
liminal_orm-2.0.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
66
|
+
liminal_orm-2.0.0.dist-info/entry_points.txt,sha256=atIrU63rrzH81dWC2sjUbFLlc5FWMmYRdMxXEWexIZA,47
|
67
|
+
liminal_orm-2.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|