liminal-orm 3.0.1__py3-none-any.whl → 3.1.1__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.
@@ -77,18 +77,18 @@ class BaseFieldProperties(BaseModel):
77
77
  for s in BenchlingBaseModel.get_all_subclasses()
78
78
  ]:
79
79
  raise ValueError(
80
- f"Could not find {self.entity_link} as a warehouse name for any currently defined schemas."
80
+ f"Field {wh_name}: could not find entity link {self.entity_link} as a warehouse name for any currently defined schemas."
81
81
  )
82
82
  if self.dropdown_link:
83
83
  if self.dropdown_link not in [
84
84
  d.__benchling_name__ for d in BaseDropdown.get_all_subclasses()
85
85
  ]:
86
86
  raise ValueError(
87
- f"Could not find {self.dropdown_link} as a name to any defined dropdowns."
87
+ f"Field {wh_name}: could not find dropdown link {self.dropdown_link} as a name to any defined dropdowns."
88
88
  )
89
89
  if not is_valid_wh_name(wh_name):
90
90
  raise ValueError(
91
- f"Invalid warehouse name '{wh_name}'. It should only contain alphanumeric characters and underscores."
91
+ f"Field {wh_name}: invalid warehouse name '{wh_name}'. It should only contain alphanumeric characters and underscores."
92
92
  )
93
93
  return True
94
94
 
liminal/cli/cli.py CHANGED
@@ -16,9 +16,9 @@ from liminal.cli.live_test_dropdown_migration import mock_dropdown_full_migratio
16
16
  from liminal.cli.live_test_entity_schema_migration import (
17
17
  mock_entity_schema_full_migration,
18
18
  )
19
+ from liminal.cli.utils import read_local_liminal_dir, update_env_revision_id
19
20
  from liminal.connection.benchling_service import BenchlingService
20
21
  from liminal.migrate.revisions_timeline import RevisionsTimeline
21
- from liminal.migrate.utils import read_local_env_file, update_env_revision_id
22
22
 
23
23
 
24
24
  class OrderCommands(TyperGroup):
@@ -34,8 +34,9 @@ app = typer.Typer(
34
34
  help="The Liminal CLI allows you to run revisions against different Benchling tenants and keep tenants in sync with dropdowns and schemas defined in code.",
35
35
  )
36
36
 
37
- ENV_FILE_PATH = Path("liminal/env.py")
38
- VERSIONS_DIR_PATH = Path("liminal/versions")
37
+ LIMINAL_DIR_PATH = Path("liminal")
38
+ ENV_FILE_PATH = LIMINAL_DIR_PATH / "env.py"
39
+ VERSIONS_DIR_PATH = LIMINAL_DIR_PATH / "versions"
39
40
 
40
41
 
41
42
  @app.command(
@@ -44,8 +45,8 @@ VERSIONS_DIR_PATH = Path("liminal/versions")
44
45
  )
45
46
  def init() -> None:
46
47
  try:
47
- Path("liminal").mkdir()
48
- Path("liminal/versions").mkdir()
48
+ LIMINAL_DIR_PATH.mkdir()
49
+ VERSIONS_DIR_PATH.mkdir()
49
50
  except Exception:
50
51
  raise Exception(
51
52
  "Liminal CLI already initialized. liminal/ already exists. Please delete it before running init."
@@ -85,8 +86,8 @@ def generate_files(
85
86
  help="The path to write the generated files to.",
86
87
  ),
87
88
  ) -> None:
88
- current_revision_id, benchling_connection = read_local_env_file(
89
- ENV_FILE_PATH, benchling_tenant
89
+ current_revision_id, benchling_connection = read_local_liminal_dir(
90
+ LIMINAL_DIR_PATH, benchling_tenant
90
91
  )
91
92
  benchling_service = BenchlingService(benchling_connection, use_internal_api=True)
92
93
  if not write_path.exists():
@@ -104,8 +105,8 @@ def current(
104
105
  ..., help="Benchling tenant (or alias) to connect to."
105
106
  ),
106
107
  ) -> None:
107
- current_revision_id, benchling_connection = read_local_env_file(
108
- ENV_FILE_PATH, benchling_tenant
108
+ current_revision_id, benchling_connection = read_local_liminal_dir(
109
+ LIMINAL_DIR_PATH, benchling_tenant
109
110
  )
110
111
  print(
111
112
  f"[blue]{benchling_connection.current_revision_id_var_name}: {current_revision_id}[/blue]"
@@ -125,8 +126,8 @@ def autogenerate(
125
126
  help="A description of the revision being generated. This will also be included in the file name.",
126
127
  ),
127
128
  ) -> None:
128
- current_revision_id, benchling_connection = read_local_env_file(
129
- ENV_FILE_PATH, benchling_tenant
129
+ current_revision_id, benchling_connection = read_local_liminal_dir(
130
+ LIMINAL_DIR_PATH, benchling_tenant
130
131
  )
131
132
  benchling_service = BenchlingService(benchling_connection, use_internal_api=True)
132
133
  autogenerate_revision_file(
@@ -148,8 +149,8 @@ def upgrade(
148
149
  help="Determines the revision files that get run. Pass in the 'revision_id' to upgrade to that revision. Pass in 'head' to upgrade to the latest revision. Pass in '+n' to make a relative revision based on the current revision id.",
149
150
  ),
150
151
  ) -> None:
151
- current_revision_id, benchling_connection = read_local_env_file(
152
- ENV_FILE_PATH, benchling_tenant
152
+ current_revision_id, benchling_connection = read_local_liminal_dir(
153
+ LIMINAL_DIR_PATH, benchling_tenant
153
154
  )
154
155
  benchling_service = BenchlingService(benchling_connection, use_internal_api=True)
155
156
  upgrade_revision_id = upgrade_benchling_tenant(
@@ -176,8 +177,8 @@ def downgrade(
176
177
  help="Determines the revision files that get run. Pass in the 'revision_id' to downgrade to that revision. Pass in '-n' to make a relative revision based on the current revision id.",
177
178
  ),
178
179
  ) -> None:
179
- current_revision_id, benchling_connection = read_local_env_file(
180
- ENV_FILE_PATH, benchling_tenant
180
+ current_revision_id, benchling_connection = read_local_liminal_dir(
181
+ LIMINAL_DIR_PATH, benchling_tenant
181
182
  )
182
183
  benchling_service = BenchlingService(benchling_connection, use_internal_api=True)
183
184
  downgrade_revision_id = downgrade_benchling_tenant(
@@ -216,8 +217,8 @@ def live_test(
216
217
  raise ValueError(
217
218
  "Only one of --entity-schema-migration or --dropdown-migration can be set."
218
219
  )
219
- current_revision_id, benchling_connection = read_local_env_file(
220
- ENV_FILE_PATH, benchling_tenant
220
+ current_revision_id, benchling_connection = read_local_liminal_dir(
221
+ LIMINAL_DIR_PATH, benchling_tenant
221
222
  )
222
223
  benchling_service = BenchlingService(benchling_connection, use_internal_api=True)
223
224
  if test_entity_schema_migration:
@@ -4,22 +4,41 @@ from pathlib import Path
4
4
  from liminal.connection.benchling_connection import BenchlingConnection
5
5
 
6
6
 
7
- def _check_env_file(env_file_path: Path) -> None:
8
- """Raises an exception if the env.py file does not exist at the given path."""
9
- if not env_file_path.exists():
7
+ def _check_liminal_directory_initialized(liminal_dir_path: Path) -> None:
8
+ """Raises an exception if the liminal directory does not exist at the given path."""
9
+ if not liminal_dir_path.exists() or not liminal_dir_path.is_dir():
10
10
  raise Exception(
11
- f"No {env_file_path} file found. Run `liminal init` or check your current working directory for liminal/env.py."
11
+ "Liminal directory not found at current working directory. Run `liminal init` or check your current working directory."
12
12
  )
13
+ else:
14
+ if not (liminal_dir_path / "env.py").exists():
15
+ raise Exception(
16
+ "No liminal/env.py file found. Run `liminal init` or check your current working directory for liminal/env.py."
17
+ )
18
+
19
+
20
+ def read_local_liminal_dir(
21
+ liminal_dir_path: Path, benchling_tenant: str
22
+ ) -> tuple[str, BenchlingConnection]:
23
+ """Imports the env.py file from /liminal/env.py and returns the CURRENT_REVISION_ID variable along with the BenchlingConnection object.
24
+ The env.py file is expected to have the CURRENT_REVISION_ID variable set to the revision id you are currently on.
25
+ The BenchlingConnection object is expected to be defined and have connection information for the Benchling API client and internal API.
26
+ """
27
+ _check_liminal_directory_initialized(liminal_dir_path)
28
+ env_file_path = liminal_dir_path / "env.py"
29
+ current_revision_id, benchling_connection = _read_local_env_file(
30
+ env_file_path, benchling_tenant
31
+ )
32
+ return current_revision_id, benchling_connection
13
33
 
14
34
 
15
- def read_local_env_file(
35
+ def _read_local_env_file(
16
36
  env_file_path: Path, benchling_tenant: str
17
37
  ) -> tuple[str, BenchlingConnection]:
18
38
  """Imports the env.py file from the current working directory and returns the CURRENT_REVISION_ID variable along with the BenchlingConnection object.
19
39
  The env.py file is expected to have the CURRENT_REVISION_ID variable set to the revision id you are currently on.
20
40
  The BenchlingConnection object is expected to be defined and have connection information for the Benchling API client and internal API.
21
41
  """
22
- _check_env_file(env_file_path)
23
42
  module_path = Path.cwd() / env_file_path
24
43
  spec = importlib.util.spec_from_file_location(env_file_path.stem, module_path)
25
44
  if spec is None or spec.loader is None:
@@ -4,6 +4,19 @@ import re
4
4
  from pydantic import BaseModel, model_validator
5
5
 
6
6
 
7
+ class TenantConfigFlags(BaseModel):
8
+ """Set of config flags that are configured on the tenant level. These can be updated on Benchling's end by contacting their support team.
9
+ Ask Benchling support to give you the full export of these flags.
10
+
11
+ Parameters
12
+ ----------
13
+ schemas_enable_change_warehouse_name: bool = False
14
+ If enabled, allows renaming schema and field warehouse names for all schema admins. Default value is False for Benchling
15
+ """
16
+
17
+ schemas_enable_change_warehouse_name: bool = False
18
+
19
+
7
20
  class BenchlingConnection(BaseModel):
8
21
  """Class that contains the connection information for a Benchling tenant.
9
22
 
@@ -27,11 +40,10 @@ class BenchlingConnection(BaseModel):
27
40
  The email of the internal API admin.
28
41
  internal_api_admin_password: str | None = None
29
42
  The password of the internal API admin.
30
- warehouse_access: bool = False
31
- Whether your Benchling tenant has access to the warehouse. If warehouse_connection_string is provided, this will default to True.
32
- warehouse_access is required to set a custom warehouse names on entity schemas and their fields.
33
43
  fieldsets: bool = False
34
44
  Whether your Benchling tenant has access to fieldsets.
45
+ config_flags: TenantConfigFlags = TenantConfigFlags()
46
+ Set of config flags that are configured on the tenant level. These can be updated on Benchling's end by contacting their support team.
35
47
  """
36
48
 
37
49
  tenant_name: str
@@ -42,14 +54,12 @@ class BenchlingConnection(BaseModel):
42
54
  warehouse_connection_string: str | None = None
43
55
  internal_api_admin_email: str | None = None
44
56
  internal_api_admin_password: str | None = None
45
- warehouse_access: bool = False
46
57
  fieldsets: bool = False
58
+ config_flags: TenantConfigFlags = TenantConfigFlags()
47
59
 
48
60
  @model_validator(mode="before")
49
61
  @classmethod
50
62
  def set_current_revision_id_var_name(cls, values: dict) -> dict:
51
- if values.get("warehouse_connection_string"):
52
- values["warehouse_access"] = True
53
63
  if not values.get("current_revision_id_var_name"):
54
64
  tenant_alias = values.get("tenant_alias")
55
65
  tenant_name = values.get("tenant_name")
@@ -4,7 +4,7 @@ from rich import print
4
4
 
5
5
  from liminal.connection import BenchlingService
6
6
  from liminal.dropdowns.utils import get_benchling_dropdowns_dict
7
- from liminal.utils import pascalize, to_snake_case
7
+ from liminal.utils import to_pascal_case, to_snake_case
8
8
 
9
9
 
10
10
  def generate_all_dropdown_files(
@@ -24,7 +24,7 @@ def generate_all_dropdown_files(
24
24
  for dropdown_name, dropdown_options in dropdowns.items():
25
25
  dropdown_values = [option.name for option in dropdown_options.options]
26
26
  options_list = str(dropdown_values).replace("'", '"')
27
- classname = pascalize(dropdown_name)
27
+ classname = to_pascal_case(dropdown_name)
28
28
  dropdown_content = f"""
29
29
  from liminal.base.base_dropdown import BaseDropdown
30
30
 
@@ -8,7 +8,7 @@ from liminal.entity_schemas.utils import get_converted_tag_schemas
8
8
  from liminal.enums import BenchlingEntityType, BenchlingFieldType
9
9
  from liminal.mappers import convert_benchling_type_to_python_type
10
10
  from liminal.orm.name_template import NameTemplate
11
- from liminal.utils import pascalize, to_snake_case
11
+ from liminal.utils import to_pascal_case, to_snake_case
12
12
 
13
13
 
14
14
  def get_entity_mixin(entity_type: BenchlingEntityType) -> str:
@@ -59,18 +59,18 @@ def generate_all_entity_schema_files(
59
59
  subdirectory_map: dict[str, list[tuple[str, str]]] = {}
60
60
  benchling_dropdowns = get_benchling_dropdowns_dict(benchling_service)
61
61
  dropdown_name_to_classname_map: dict[str, str] = {
62
- dropdown_name: pascalize(dropdown_name)
62
+ dropdown_name: to_pascal_case(dropdown_name)
63
63
  for dropdown_name in benchling_dropdowns.keys()
64
64
  }
65
65
  wh_name_to_classname: dict[str, str] = {
66
- sp.warehouse_name: pascalize(sp.name) for sp, _, _ in models
66
+ sp.warehouse_name: to_pascal_case(sp.name) for sp, _, _ in models
67
67
  }
68
68
 
69
69
  for schema_properties, name_template, columns in models:
70
- classname = pascalize(schema_properties.name)
70
+ classname = to_pascal_case(schema_properties.name)
71
71
 
72
72
  for schema_properties, name_template, columns in models:
73
- classname = pascalize(schema_properties.name)
73
+ classname = to_pascal_case(schema_properties.name)
74
74
  filename = to_snake_case(schema_properties.name) + ".py"
75
75
  columns = {key: columns[key] for key in columns}
76
76
  import_strings = [
@@ -81,14 +81,13 @@ class CreateEntitySchema(BaseOperation):
81
81
 
82
82
  def validate(self, benchling_service: BenchlingService) -> None:
83
83
  if (
84
- not benchling_service.connection.warehouse_access
84
+ benchling_service.connection.config_flags.schemas_enable_change_warehouse_name
85
+ is False
85
86
  and self._validated_schema_properties.warehouse_name
86
87
  != to_snake_case(self._validated_schema_properties.name)
87
88
  ):
88
89
  raise ValueError(
89
- f"Warehouse access is required to set a custom field warehouse name. \
90
- Either set warehouse_access to True in BenchlingConnection or set the schema warehouse_name to the given Benchling warehouse name: {to_snake_case(self._validated_schema_properties.name)}. \
91
- Reach out to Benchling support if you need help setting up warehouse access."
90
+ f"{self._validated_schema_properties.name}: Tenant config flag SCHEMAS_ENABLE_CHANGE_WAREHOUSE_NAME is required to set a custom schema warehouse name. Reach out to Benchling support to turn this config flag to True and then set the flag to True in BenchlingConnection.config_flags. Otherwise, define the schema warehouse_name in code to be the given Benchling warehouse name: {to_snake_case(self._validated_schema_properties.name)}."
92
91
  )
93
92
  for field in self.fields:
94
93
  if (
@@ -225,20 +224,19 @@ class UpdateEntitySchema(BaseOperation):
225
224
  return update_tag_schema(benchling_service, tag_schema.id, update.model_dump())
226
225
 
227
226
  def describe_operation(self) -> str:
228
- return f"Updating properties for entity schema {self.wh_schema_name}: {str(self.update_props)}."
227
+ return f"{self.wh_schema_name}: Updating schema properties to: {str(self.update_props)}."
229
228
 
230
229
  def describe(self) -> str:
231
- return f"Schema properties for {self.wh_schema_name} are different in code versus Benchling: {str(self.update_props)}."
230
+ return f"{self.wh_schema_name}: Schema properties are different in code versus Benchling: {str(self.update_props)}."
232
231
 
233
232
  def validate(self, benchling_service: BenchlingService) -> None:
234
233
  if (
235
- benchling_service.connection.warehouse_access
234
+ benchling_service.connection.config_flags.schemas_enable_change_warehouse_name
235
+ is False
236
236
  and self.update_props.warehouse_name is not None
237
237
  ):
238
238
  raise ValueError(
239
- "Warehouse access is required to change the schema warehouse name. \
240
- Either set warehouse_access to True in BenchlingConnection or do not change the warehouse name. \
241
- Reach out to Benchling support if you need help setting up warehouse access."
239
+ f"{self.wh_schema_name}: Tenant config flag SCHEMAS_ENABLE_CHANGE_WAREHOUSE_NAME is required to update the schema warehouse_name to a custom name. Reach out to Benchling support to turn this config flag to True and then set the flag to True in BenchlingConnection.config_flags."
242
240
  )
243
241
 
244
242
  def _validate(self, benchling_service: BenchlingService) -> TagSchemaModel:
@@ -315,10 +313,15 @@ class CreateEntitySchemaField(BaseOperation):
315
313
  self.index = index
316
314
 
317
315
  self._wh_field_name: str
316
+ self._field_name: str
318
317
  if field_props.warehouse_name:
319
318
  self._wh_field_name = field_props.warehouse_name
320
319
  else:
321
320
  raise ValueError("Field warehouse name is required.")
321
+ if field_props.name:
322
+ self._field_name = field_props.name
323
+ else:
324
+ raise ValueError("Field name is required.")
322
325
 
323
326
  def execute(self, benchling_service: BenchlingService) -> dict[str, Any]:
324
327
  try:
@@ -385,13 +388,12 @@ class CreateEntitySchemaField(BaseOperation):
385
388
 
386
389
  def validate(self, benchling_service: BenchlingService) -> None:
387
390
  if (
388
- not benchling_service.connection.warehouse_access
389
- and self.field_props.warehouse_name != to_snake_case(self.field_props.name)
391
+ benchling_service.connection.config_flags.schemas_enable_change_warehouse_name
392
+ is False
393
+ and self.field_props.warehouse_name != to_snake_case(self._field_name)
390
394
  ):
391
395
  raise ValueError(
392
- f"Warehouse access is required to set a custom field warehouse name. \
393
- Either set warehouse_access to True in BenchlingConnection or set the column variable name to the given Benchling field warehouse name: {to_snake_case(self.field_props.name)}. \
394
- Reach out to Benchling support if you need help setting up warehouse access."
396
+ f"{self.wh_schema_name}: Tenant config flag SCHEMAS_ENABLE_CHANGE_WAREHOUSE_NAME is required to set a custom field warehouse name. Reach out to Benchling support to turn this config flag to True and then set the flag to True in BenchlingConnection.config_flags. Otherwise, define the field warehouse_name in code to be the given Benchling warehouse name: {to_snake_case(self._field_name)}."
395
397
  )
396
398
  if (
397
399
  self.field_props.unit_name
@@ -538,13 +540,12 @@ class UpdateEntitySchemaField(BaseOperation):
538
540
  benchling_service, self.wh_schema_name
539
541
  )
540
542
  if (
541
- not benchling_service.connection.warehouse_access
543
+ benchling_service.connection.config_flags.schemas_enable_change_warehouse_name
544
+ is False
542
545
  and self.update_props.warehouse_name is not None
543
546
  ):
544
547
  raise ValueError(
545
- "Warehouse access is required to change the field warehouse name. \
546
- Either set warehouse_access to True in BenchlingConnection or do not change the warehouse name. \
547
- Reach out to Benchling support if you need help setting up warehouse access."
548
+ f"{self.wh_schema_name}: Tenant config flag SCHEMAS_ENABLE_CHANGE_WAREHOUSE_NAME is required to update the field warehouse_name to a custom name. Reach out to Benchling support to turn this config flag to True and then set the flag to True in BenchlingConnection.config_flags."
548
549
  )
549
550
  if "unit_name" in self.update_props.model_dump(exclude_unset=True):
550
551
  no_change_message = f"{self.wh_schema_name}: On field {self.wh_field_name}, updating unit name to {self.update_props.unit_name}. The unit of this field CANNOT be changed once it's been set."
liminal/orm/base_model.py CHANGED
@@ -131,7 +131,7 @@ class BaseModel(Generic[T], Base):
131
131
  for field_part in field_parts:
132
132
  if field_part.wh_field_name not in column_wh_names:
133
133
  raise ValueError(
134
- f"Field part {field_part.wh_field_name} is not a column on schema {cls.__schema_properties__.name}."
134
+ f"{cls.__schema_properties__.warehouse_name}: Field name template part {field_part.wh_field_name} is not a column on field warehouse name on schema."
135
135
  )
136
136
  cls._existing_schema_warehouse_names.add(warehouse_name)
137
137
  cls._existing_schema_names.add(cls.__schema_properties__.name)
liminal/utils.py CHANGED
@@ -10,30 +10,25 @@ from liminal.connection.benchling_service import BenchlingService
10
10
 
11
11
 
12
12
  def generate_random_id(length: int = 8) -> str:
13
- """Generate a random ID with only lowercase letters."""
13
+ """Generate a pseudo-random ID with only lowercase letters."""
14
14
  return "".join(random.choices(string.ascii_lowercase, k=length))
15
15
 
16
16
 
17
- def pascalize(input_string: str) -> str:
17
+ def to_pascal_case(input_string: str) -> str:
18
18
  """
19
- Convert a string to PascalCase.
19
+ Convert a string to PascalCase. Filters out any non-alphanumeric characters.
20
20
  """
21
- return "".join(
22
- re.sub(r"[\[\]{}():]", "", word).capitalize()
23
- for word in re.split(r"[ /_\-]", input_string)
24
- )
21
+ words = re.split(r"[ /_\-]", input_string)
22
+ # Then remove any non-alphanumeric characters and capitalize each word
23
+ return "".join(re.sub(r"[^a-zA-Z0-9]", "", word).capitalize() for word in words)
25
24
 
26
25
 
27
- def to_snake_case(input_string: str | None) -> str:
26
+ def to_snake_case(input_string: str) -> str:
28
27
  """
29
- Convert a string to snake_case.
28
+ Convert a string to snake_case. Filters out any non-alphanumeric characters.
30
29
  """
31
- if input_string is None:
32
- return ""
33
- return "_".join(
34
- re.sub(r"[\[\]{}():]", "", word).lower()
35
- for word in re.split(r"[ /_\-]", input_string)
36
- )
30
+ words = re.split(r"[ /_\-]", input_string)
31
+ return "_".join(re.sub(r"[^a-zA-Z0-9]", "", word).lower() for word in words)
37
32
 
38
33
 
39
34
  def to_string_val(input_val: Any) -> str:
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Callable
4
4
 
5
5
  from pydantic import BaseModel, ConfigDict
6
6
 
7
- from liminal.utils import pascalize
7
+ from liminal.utils import to_pascal_case
8
8
  from liminal.validation.validation_severity import ValidationSeverity
9
9
 
10
10
  if TYPE_CHECKING:
@@ -137,14 +137,14 @@ def liminal_validator(
137
137
  valid=False,
138
138
  level=validator_level,
139
139
  entity=self,
140
- validator_name=validator_name or pascalize(func.__name__),
140
+ validator_name=validator_name or to_pascal_case(func.__name__),
141
141
  message=str(e),
142
142
  )
143
143
  return BenchlingValidatorReport.create_validation_report(
144
144
  valid=True,
145
145
  level=validator_level,
146
146
  entity=self,
147
- validator_name=validator_name or pascalize(func.__name__),
147
+ validator_name=validator_name or to_pascal_case(func.__name__),
148
148
  )
149
149
 
150
150
  setattr(wrapper, "_is_liminal_validator", True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: liminal-orm
3
- Version: 3.0.1
3
+ Version: 3.1.1
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
@@ -1,31 +1,31 @@
1
- liminal/.DS_Store,sha256=s_ehSI1aIzOjVRnFlcSzhtWS3irmEDSGHyS6l0QRcus,8196
2
1
  liminal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
2
  liminal/base/base_dropdown.py,sha256=Unk4l_5Y8rj_eSWYqzFi2BAFSQToQDWW2qdXwiCHTg8,2523
4
3
  liminal/base/base_operation.py,sha256=opQfFZeC49YAFkg5ahE6CFpeSUNPh1ootWZxXyEXfFI,3128
5
4
  liminal/base/base_validation_filters.py,sha256=kHG3G5gXkuNHQosMTrxRc57OTmczcaoSx0DmkrScIr4,1043
6
5
  liminal/base/compare_operation.py,sha256=hkpv4ewHhxy4dlTPKgJuzBjsAqO6Km7OrrKB44pRA_o,352
7
6
  liminal/base/name_template_parts.py,sha256=dJeyrhhhZHDwKXe_p7AtgDlbZlzsnYQ8FoM8FXVF7q0,271
8
- liminal/base/properties/base_field_properties.py,sha256=ze8CLf0jPPYwklFYVKXkRvXiBBA9ilG5nK1_oP0rS04,4970
7
+ liminal/base/properties/base_field_properties.py,sha256=TqHLJnRx7EK7grzad6MOHpGJeZr0Srm9bPhshHslJRk,5047
9
8
  liminal/base/properties/base_name_template.py,sha256=AOtaW4QEDRC-mjZOZk6jgc_mopUMsHS2Fj6VVsO07WY,3150
10
9
  liminal/base/properties/base_schema_properties.py,sha256=11QaxtUoHZx25QFv7HP8gQBpknrFthVeyWuMnI_lV5g,5891
11
10
  liminal/base/str_enum.py,sha256=jF3d-Lo8zsHUe6GsctX2L-TSj92Y3qCYDrTD-saeJoc,210
12
- liminal/cli/cli.py,sha256=JxWHLO9KMeMaOnOYwzdH0w71l0477ScFOkWNtTlc97Y,9045
11
+ liminal/cli/cli.py,sha256=30ZCkbQUY8p9WLS6OIBWgig0hGM2QlMQweHMGQe1gwQ,9119
13
12
  liminal/cli/controller.py,sha256=QNj3QO9TMb9hfc6U-VhLuFa0_aohOHZUmvY4XkATPhw,10118
14
13
  liminal/cli/live_test_dropdown_migration.py,sha256=87JwxGD4A5ExjfsEEev9jgBNuldUj4CLoaFwsZ-BjEI,2889
15
14
  liminal/cli/live_test_entity_schema_migration.py,sha256=_JawaiJNHkAjIrtwe9_K15OoJSFq_4vaTK5vrmz-b6s,5576
15
+ liminal/cli/utils.py,sha256=hiBDeCDMjXdGnzjA7kwC9pYgNhSyF-oK_IicdO5u3U0,4478
16
16
  liminal/connection/__init__.py,sha256=3z4pSANIOkc9mh1Xp763oYQuJZDEh4lauN901PU4vqI,166
17
- liminal/connection/benchling_connection.py,sha256=nALLAA-hPIO2Eb_KhUL-nU3jOlMDSIrPMUgUyDKGRRw,2862
17
+ liminal/connection/benchling_connection.py,sha256=PLiaI4v9EcJDNBEO5ZF3jERuI6AYo8NAYpqPYLxVYdQ,3237
18
18
  liminal/connection/benchling_service.py,sha256=lEYCHF1U8nII8Rn3rMBPTffTFiVFjoFeNmX2Kq36-qE,7170
19
19
  liminal/dropdowns/api.py,sha256=n5oxi1EhkmpmPpNi1LOI4xcIQmk1C069XFaGP5XSBx8,6959
20
20
  liminal/dropdowns/compare.py,sha256=-UbCkeTKx3THwvjMTUubyYVXBkhmvyhEKzwrIzBkthY,7141
21
- liminal/dropdowns/generate_files.py,sha256=IqnBs-IyLsIZE0NUkdB99zd5EAF-1f9CPBeblz-GzJE,2041
21
+ liminal/dropdowns/generate_files.py,sha256=Y6biJOrt1XtWcTMoIV_eC2Yqwg6JYQxyF85U78s6M7U,2051
22
22
  liminal/dropdowns/operations.py,sha256=-TRIsxqnUtrIUjhrt5k_PdiBCDUXsXDzsOUmznJE-6Q,13516
23
23
  liminal/dropdowns/utils.py,sha256=1-H7bTszCUeqeRBpiYXjRjreDzhn1Fd1MFwIsrEI-o4,4109
24
24
  liminal/entity_schemas/api.py,sha256=Emn_Y95cAG9Wis6tpchw6QBVKQh4If86LOdgKk0Ndjw,3575
25
25
  liminal/entity_schemas/compare.py,sha256=t6tl67GWaMoNNcPxyLpCuNAlN3OWNqURTo3EUEMtETE,17549
26
26
  liminal/entity_schemas/entity_schema_models.py,sha256=v5A1ELaiuBnUSl1HkUNAeMuIRQeQnIKzfpFxmsiKWh0,8349
27
- liminal/entity_schemas/generate_files.py,sha256=u9SoDO9f4qL2nZaddln__2J0zJ3QMFBQhiUabn22aUY,9032
28
- liminal/entity_schemas/operations.py,sha256=jd6Wiq_rW0UIjiVqUACio_Lwbv3fGrtoyQRGBHtXJHo,26654
27
+ liminal/entity_schemas/generate_files.py,sha256=AwthMaPLG9DA7sb_mrQcDag3XxMOEZqTkj5DWFMEy98,9057
28
+ liminal/entity_schemas/operations.py,sha256=N58H8LP1fuRCjRecG6G43ZdAX7MEL2lxPLQPmc23Wlw,27119
29
29
  liminal/entity_schemas/tag_schema_models.py,sha256=DZQYzlxt3aEHbLy00qEyDZC_mRyi9I325ggkfcNgR1I,24153
30
30
  liminal/entity_schemas/utils.py,sha256=2ZHyLxnYITVEuyAWxNdsq5hcNSgvN7pN3-uUzyocYSk,6161
31
31
  liminal/enums/__init__.py,sha256=-szuqAwMED4ai0NaPVUfgihQJAJ27wPu_nDnj4cEgTk,518
@@ -42,9 +42,8 @@ liminal/mappers.py,sha256=TgPMQsLrESAI6D7KBl0UoBBpnxYgcgGOT7a2faWsuhY,9587
42
42
  liminal/migrate/components.py,sha256=2HuFp5KDNhofROMRI-BioUoA4CCjhQ_v_F0QmGJzUBU,3480
43
43
  liminal/migrate/revision.py,sha256=KppU0u-d0JsfPsXsmncxy9Q_XBJyf-o4e16wNZAJODM,7774
44
44
  liminal/migrate/revisions_timeline.py,sha256=G9VwxPrLhLqKOrIXyxrXyHpujc-72m7omsZjI5-0D0M,14520
45
- liminal/migrate/utils.py,sha256=HdSr3N2WN_1S-PLRGVWSMYl-4gIcP-Ph2wPycGi2cGg,3404
46
45
  liminal/orm/base.py,sha256=fFSpiNRYgK5UG7lbXdQGV8KgO8pwjMqt0pycM3rWJ2o,615
47
- liminal/orm/base_model.py,sha256=FFkrB-lMAAgp77BUnQDu39IxZxmhHu52CtCLeBZVNGA,15527
46
+ liminal/orm/base_model.py,sha256=goJY17riXGqAP3hobHqa-koe8_EijMZ_LgZSXgD69vc,15576
48
47
  liminal/orm/base_tables/registry_entity.py,sha256=4ET1cepTGjZ3AMFI5q-iMYxMObzXwuUDBD0jNNqCipE,2126
49
48
  liminal/orm/base_tables/schema.py,sha256=7_btCVSUJxjVdGcKVRKL8sKcNw7-_gazTpfEh1jru3o,921
50
49
  liminal/orm/base_tables/user.py,sha256=elRAHj7HgO3iVLK_pNCIwf_9Rl_9k6vkBgaYazoJSQc,818
@@ -55,18 +54,17 @@ liminal/orm/name_template_parts.py,sha256=iI4S9ZGvckQbYjhgFdn6xeJ3rS90lzCvjH0863
55
54
  liminal/orm/relationship.py,sha256=Zl4bMHbtDSPx1psGHYnojGGJpA8B8hwcPJdgjB1lmW0,2490
56
55
  liminal/orm/schema_properties.py,sha256=vqqjnxbh7AYh9ZvSmhCsl69BqSBPpQutNKImb-TBCGg,4167
57
56
  liminal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- liminal/tests/.DS_Store,sha256=0sTLf7flLKL2_3KGceYriAB8_gXTcYwn0c2RVSYmLZk,6148
59
57
  liminal/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
58
  liminal/tests/conftest.py,sha256=B463eOfe1uCHDJsUNvG-6tY8Qx8FJMByGDOtuyM87lA,17669
61
59
  liminal/tests/from benchling_sdk.py,sha256=CjRUHFB3iaa4rUPLGOqDiBq5EPKldm-Fd8aQQr92zF4,147
62
60
  liminal/tests/test_dropdown_compare.py,sha256=yHB0ovQlBLRu8-qYkqIPd8VtYEOmOft_93FQM86g_z8,8198
63
61
  liminal/tests/test_entity_schema_compare.py,sha256=-26Bu5eYIuHRswB5kYjGDo5Wed5LUWjm1e6IRI1Q-lE,18952
64
62
  liminal/unit_dictionary/utils.py,sha256=o3K06Yyt33iIUSMHPT8f1vSuUSgWjZLf51p78lx4SZs,1817
65
- liminal/utils.py,sha256=radRtRsZmCiNblMvxOX1DH0rcO5TR09kFlp6OONIPBU,2951
66
- liminal/validation/__init__.py,sha256=TVaHrSF3GnSd4mbZrPn8TBHscGWkAPKAUUPq7-symC8,5275
63
+ liminal/utils.py,sha256=ZiehcgE0We5i9Ry6tQO_f8QoQEOaiO4SFOQnFbq-29o,3068
64
+ liminal/validation/__init__.py,sha256=NsjzmivSRwGki1k9ykJgjtcYNcILR_PHSf6RkI1w2n0,5290
67
65
  liminal/validation/validation_severity.py,sha256=ib03PTZCQHcbBDc01v4gJF53YtA-ANY6QSFnhTV-FbU,259
68
- liminal_orm-3.0.1.dist-info/LICENSE.md,sha256=oVA877F_D1AV44dpjsv4f-4k690uNGApX1EtzOo3T8U,11353
69
- liminal_orm-3.0.1.dist-info/METADATA,sha256=gA_yNA-bEIUIe1nAJ6kZvF8fn-NT_Ov2sFbF-zngGsY,11032
70
- liminal_orm-3.0.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
71
- liminal_orm-3.0.1.dist-info/entry_points.txt,sha256=atIrU63rrzH81dWC2sjUbFLlc5FWMmYRdMxXEWexIZA,47
72
- liminal_orm-3.0.1.dist-info/RECORD,,
66
+ liminal_orm-3.1.1.dist-info/LICENSE.md,sha256=oVA877F_D1AV44dpjsv4f-4k690uNGApX1EtzOo3T8U,11353
67
+ liminal_orm-3.1.1.dist-info/METADATA,sha256=u4jC_Fbe5Idl6MDpUMbIauCIhmgFEQiXMZyNkUv_QmE,11032
68
+ liminal_orm-3.1.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
69
+ liminal_orm-3.1.1.dist-info/entry_points.txt,sha256=atIrU63rrzH81dWC2sjUbFLlc5FWMmYRdMxXEWexIZA,47
70
+ liminal_orm-3.1.1.dist-info/RECORD,,
liminal/.DS_Store DELETED
Binary file
liminal/tests/.DS_Store DELETED
Binary file