liminal-orm 1.0.5__tar.gz → 1.0.6__tar.gz
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_orm-1.0.5 → liminal_orm-1.0.6}/PKG-INFO +10 -4
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/README.md +8 -3
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/properties/base_schema_properties.py +9 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/cli/cli.py +4 -1
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/connection/benchling_service.py +7 -1
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/generate_files.py +2 -2
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/operations.py +3 -7
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/tag_schema_models.py +2 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/column.py +5 -1
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/pyproject.toml +2 -1
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/LICENSE.md +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/__init__.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/base_dropdown.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/base_operation.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/base_validation_filters.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/compare_operation.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/properties/base_field_properties.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/base/str_enum.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/cli/controller.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/cli/live_test_dropdown_migration.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/cli/live_test_entity_schema_migration.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/connection/__init__.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/connection/benchling_connection.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/dropdowns/api.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/dropdowns/compare.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/dropdowns/generate_files.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/dropdowns/operations.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/dropdowns/utils.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/api.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/compare.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/entity_schema_models.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/entity_schemas/utils.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/__init__.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_api_field_type.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_entity_type.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_field_type.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_folder_item_type.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_naming_strategy.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_report_level.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/enums/benchling_sequence_type.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/external/__init__.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/mappers.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/migrate/components.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/migrate/revision.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/migrate/revisions_timeline.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/migrate/utils.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/base.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/base_model.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/mixins.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/relationship.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/schema_properties.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/orm/user.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/py.typed +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/tests/__init__.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/tests/conftest.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/tests/from benchling_sdk.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/tests/test_dropdown_compare.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/tests/test_entity_schema_compare.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/utils.py +0 -0
- {liminal_orm-1.0.5 → liminal_orm-1.0.6}/liminal/validation/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: liminal-orm
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.6
|
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
|
@@ -14,6 +14,7 @@ Requires-Dist: benchling-sdk (>=1.8.0)
|
|
14
14
|
Requires-Dist: bs4 (>=0.0.2,<0.0.3)
|
15
15
|
Requires-Dist: lxml (>=5.3.0,<6.0.0)
|
16
16
|
Requires-Dist: pandas (>=1.5.3)
|
17
|
+
Requires-Dist: psycopg2-binary (>=2.9.10,<3.0.0)
|
17
18
|
Requires-Dist: pydantic (>=2,<=2.7)
|
18
19
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
19
20
|
Requires-Dist: rich (>=13.9.2,<14.0.0)
|
@@ -27,7 +28,12 @@ Description-Content-Type: text/markdown
|
|
27
28
|
|
28
29
|
# [Liminal ORM](#liminal-orm)
|
29
30
|
|
30
|
-
|
31
|
+
[](https://pypi.org/project/liminal-orm/)
|
32
|
+
[](https://github.com/dynotx/liminal-orm/blob/main/LICENSE.md)
|
33
|
+
[](https://github.com/dynotx/liminal-orm/actions/workflows/liminal.yml)
|
34
|
+
[](https://pepy.tech/project/liminal-orm)
|
35
|
+
|
36
|
+
Liminal ORM<sup>1</sup> is an open-source Python package that builds on [Benchling's](https://www.benchling.com/) LIMS<sup>2</sup> platform and provides a simple, code-first approach for synchronizing and managing your Benchling schemas. Check out the [**full documentation here**](https://dynotx.github.io/liminal-orm/) and join our [**Slack community here**](https://join.slack.com/t/liminalorm/shared_invite/zt-2ujrp07s3-bctook4e~cAjn1LgOLVY~Q)!
|
31
37
|
|
32
38
|
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:
|
33
39
|
|
@@ -38,10 +44,10 @@ Liminal provides an ORM framework using [SQLAlchemy](https://github.com/sqlalche
|
|
38
44
|
- CI/CD integration with GitHub Actions to ensure that your Benchling schemas and code are always in sync.
|
39
45
|
- And more based on community contributions/feedback :)
|
40
46
|
|
41
|
-
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)!
|
42
|
-
|
43
47
|
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 [Discussions](https://github.com/dynotx/liminal-orm/discussions) forum 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 (contact information below). You can expect responses within 48 hours :)
|
44
48
|
|
49
|
+
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)!
|
50
|
+
|
45
51
|
Nirmit Damania is the creator and current maintainer of Liminal (I post Liminal updates to [Discussions](https://github.com/dynotx/liminal-orm/discussions) and my [LinkedIn](https://www.linkedin.com/in/nirmit-damania/)). Most importantly, **you** have the ability to influence the future of Liminal! Any feedback, positive or negative, is highly encouraged and will be used to steer the direction of Liminal. Refer to the [Contributing guide](https://github.com/dynotx/liminal-orm/blob/main/CONTRIBUTING.md) to learn more about how you can contribute to Liminal.
|
46
52
|
|
47
53
|
⭐️ Leave a star on the repo to spread the word!
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# [Liminal ORM](#liminal-orm)
|
2
2
|
|
3
|
-
|
3
|
+
[](https://pypi.org/project/liminal-orm/)
|
4
|
+
[](https://github.com/dynotx/liminal-orm/blob/main/LICENSE.md)
|
5
|
+
[](https://github.com/dynotx/liminal-orm/actions/workflows/liminal.yml)
|
6
|
+
[](https://pepy.tech/project/liminal-orm)
|
7
|
+
|
8
|
+
Liminal ORM<sup>1</sup> is an open-source Python package that builds on [Benchling's](https://www.benchling.com/) LIMS<sup>2</sup> platform and provides a simple, code-first approach for synchronizing and managing your Benchling schemas. Check out the [**full documentation here**](https://dynotx.github.io/liminal-orm/) and join our [**Slack community here**](https://join.slack.com/t/liminalorm/shared_invite/zt-2ujrp07s3-bctook4e~cAjn1LgOLVY~Q)!
|
4
9
|
|
5
10
|
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:
|
6
11
|
|
@@ -11,10 +16,10 @@ Liminal provides an ORM framework using [SQLAlchemy](https://github.com/sqlalche
|
|
11
16
|
- CI/CD integration with GitHub Actions to ensure that your Benchling schemas and code are always in sync.
|
12
17
|
- And more based on community contributions/feedback :)
|
13
18
|
|
14
|
-
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)!
|
15
|
-
|
16
19
|
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 [Discussions](https://github.com/dynotx/liminal-orm/discussions) forum 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 (contact information below). You can expect responses within 48 hours :)
|
17
20
|
|
21
|
+
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)!
|
22
|
+
|
18
23
|
Nirmit Damania is the creator and current maintainer of Liminal (I post Liminal updates to [Discussions](https://github.com/dynotx/liminal-orm/discussions) and my [LinkedIn](https://www.linkedin.com/in/nirmit-damania/)). Most importantly, **you** have the ability to influence the future of Liminal! Any feedback, positive or negative, is highly encouraged and will be used to steer the direction of Liminal. Refer to the [Contributing guide](https://github.com/dynotx/liminal-orm/blob/main/CONTRIBUTING.md) to learn more about how you can contribute to Liminal.
|
19
24
|
|
20
25
|
⭐️ Leave a star on the repo to spread the word!
|
@@ -97,3 +97,12 @@ class BaseSchemaProperties(BaseModel):
|
|
97
97
|
if not isinstance(other, BaseSchemaProperties):
|
98
98
|
return False
|
99
99
|
return self.model_dump() == other.model_dump()
|
100
|
+
|
101
|
+
def __str__(self) -> str:
|
102
|
+
return ", ".join(
|
103
|
+
[f"{k}={v}" for k, v in self.model_dump(exclude_unset=True).items()]
|
104
|
+
)
|
105
|
+
|
106
|
+
def __repr__(self) -> str:
|
107
|
+
"""Generates a string representation of the class so that it can be executed."""
|
108
|
+
return f"{self.__class__.__name__}({', '.join([f'{k}={v.__repr__()}' for k, v in self.model_dump(exclude_defaults=True).items()])})"
|
@@ -79,7 +79,10 @@ def generate_files(
|
|
79
79
|
..., help="Benchling tenant (or alias) to connect to."
|
80
80
|
),
|
81
81
|
write_path: Path = typer.Option(
|
82
|
-
Path("."),
|
82
|
+
Path("."),
|
83
|
+
"-p",
|
84
|
+
"--write-path",
|
85
|
+
help="The path to write the generated files to.",
|
83
86
|
),
|
84
87
|
) -> None:
|
85
88
|
current_revision_id, benchling_connection = read_local_env_file(
|
@@ -9,7 +9,12 @@ from bs4 import BeautifulSoup
|
|
9
9
|
from sqlalchemy import create_engine
|
10
10
|
from sqlalchemy.engine import Engine
|
11
11
|
from sqlalchemy.orm import Session, configure_mappers
|
12
|
-
from tenacity import
|
12
|
+
from tenacity import (
|
13
|
+
retry,
|
14
|
+
retry_if_exception_type,
|
15
|
+
stop_after_attempt,
|
16
|
+
wait_exponential,
|
17
|
+
)
|
13
18
|
|
14
19
|
from liminal.connection.benchling_connection import BenchlingConnection
|
15
20
|
|
@@ -144,6 +149,7 @@ class BenchlingService(Benchling):
|
|
144
149
|
@retry(
|
145
150
|
stop=stop_after_attempt(3),
|
146
151
|
retry=retry_if_exception_type(ValueError),
|
152
|
+
wait=wait_exponential(multiplier=1, min=1, max=8),
|
147
153
|
reraise=True,
|
148
154
|
)
|
149
155
|
def autogenerate_auth(
|
@@ -106,14 +106,14 @@ def generate_all_entity_schema_files(
|
|
106
106
|
):
|
107
107
|
if not col.is_multi:
|
108
108
|
relationship_strings.append(
|
109
|
-
f"""{tab}single_relationship("{wh_name_to_classname[col.entity_link]}", {col_name})"""
|
109
|
+
f"""{tab}{col_name}_entity = single_relationship("{wh_name_to_classname[col.entity_link]}", {col_name})"""
|
110
110
|
)
|
111
111
|
import_strings.append(
|
112
112
|
"from liminal.orm.relationship import single_relationship"
|
113
113
|
)
|
114
114
|
else:
|
115
115
|
relationship_strings.append(
|
116
|
-
f"""{tab}multi_relationship("{wh_name_to_classname[col.entity_link]}", "{classname}", "{col_name}")"""
|
116
|
+
f"""{tab}{col_name}_entities = multi_relationship("{wh_name_to_classname[col.entity_link]}", "{classname}", "{col_name}")"""
|
117
117
|
)
|
118
118
|
import_strings.append(
|
119
119
|
"from liminal.orm.relationship import multi_relationship"
|
@@ -195,10 +195,10 @@ class UpdateEntitySchema(BaseOperation):
|
|
195
195
|
return update_tag_schema(benchling_service, tag_schema.id, update.model_dump())
|
196
196
|
|
197
197
|
def describe_operation(self) -> str:
|
198
|
-
return f"Updating properties for entity schema {self.wh_schema_name}: {
|
198
|
+
return f"Updating properties for entity schema {self.wh_schema_name}: {str(self.update_props)}."
|
199
199
|
|
200
200
|
def describe(self) -> str:
|
201
|
-
return f"Schema properties for {self.wh_schema_name} are different in code versus Benchling: {
|
201
|
+
return f"Schema properties for {self.wh_schema_name} are different in code versus Benchling: {str(self.update_props)}."
|
202
202
|
|
203
203
|
def _validate(self, benchling_service: BenchlingService) -> TagSchemaModel:
|
204
204
|
all_schemas = TagSchemaModel.get_all_json(benchling_service)
|
@@ -485,11 +485,7 @@ class UpdateEntitySchemaField(BaseOperation):
|
|
485
485
|
# Only if changing name of field
|
486
486
|
if self.update_props.name:
|
487
487
|
existing_new_field = next(
|
488
|
-
(
|
489
|
-
f
|
490
|
-
for f in tag_schema.allFields
|
491
|
-
if f.systemName == self.update_props.name
|
492
|
-
),
|
488
|
+
(f for f in tag_schema.allFields if f.name == self.update_props.name),
|
493
489
|
None,
|
494
490
|
)
|
495
491
|
if existing_new_field:
|
@@ -59,6 +59,7 @@ class CreateTagSchemaFieldModel(BaseModel):
|
|
59
59
|
systemName: str
|
60
60
|
name: str
|
61
61
|
requiredLink: FieldRequiredLinkShortModel | None = None
|
62
|
+
tooltipText: str | None = None
|
62
63
|
|
63
64
|
@classmethod
|
64
65
|
def from_props(
|
@@ -121,6 +122,7 @@ class CreateTagSchemaFieldModel(BaseModel):
|
|
121
122
|
folderItemType=folder_item_type,
|
122
123
|
tagSchema=tagSchema,
|
123
124
|
),
|
125
|
+
tooltipText=new_props.tooltip,
|
124
126
|
)
|
125
127
|
|
126
128
|
|
@@ -82,7 +82,7 @@ class Column(SqlColumn):
|
|
82
82
|
super().__init__(
|
83
83
|
self.sqlalchemy_type,
|
84
84
|
foreign_key,
|
85
|
-
nullable=not
|
85
|
+
nullable=not required,
|
86
86
|
info={"benchling_properties": properties},
|
87
87
|
**kwargs,
|
88
88
|
)
|
@@ -107,3 +107,7 @@ class Column(SqlColumn):
|
|
107
107
|
f"Could not set benchling properties for column {column.name}. Please check that the column has a valid benchling properties set."
|
108
108
|
)
|
109
109
|
return Column(**properties.model_dump())
|
110
|
+
|
111
|
+
def _constructor(self, *args: Any, **kwargs: Any) -> SqlColumn:
|
112
|
+
"""Returns a new instance of the SqlAlchemy Column class."""
|
113
|
+
return SqlColumn(*args, **kwargs)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "liminal-orm"
|
3
|
-
version = "1.0.
|
3
|
+
version = "1.0.6"
|
4
4
|
description = "An ORM and toolkit that builds on top of Benchling's platform to keep your schemas and downstream code dependencies in sync."
|
5
5
|
authors = ["DynoTx Open Source <opensource@dynotx.com>"]
|
6
6
|
readme = "README.md"
|
@@ -24,6 +24,7 @@ sqlalchemy = "<2" # TODO: We need to assess this upgrade
|
|
24
24
|
tenacity = ">=8,<10"
|
25
25
|
typer = "^0.12.5"
|
26
26
|
lxml = "^5.3.0"
|
27
|
+
psycopg2-binary = "^2.9.10"
|
27
28
|
|
28
29
|
[tool.poetry.group.dev.dependencies]
|
29
30
|
ipykernel = "^6.29.5"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|