liminal-orm 5.0.0__tar.gz → 5.1.2__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.
Files changed (298) hide show
  1. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.gitignore +3 -1
  2. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/PKG-INFO +4 -4
  3. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/README.md +1 -1
  4. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/base_operation.py +4 -4
  5. liminal_orm-5.1.2/liminal/base/compare_operation.py +19 -0
  6. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/properties/base_field_properties.py +5 -2
  7. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/properties/base_schema_properties.py +5 -0
  8. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/cli/cli.py +70 -2
  9. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/cli/controller.py +66 -0
  10. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/dropdowns/generate_files.py +5 -4
  11. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/compare.py +94 -37
  12. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/entity_schema_models.py +26 -13
  13. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/generate_files.py +11 -6
  14. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/operations.py +7 -7
  15. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/utils.py +1 -1
  16. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/column.py +6 -2
  17. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/schema_properties.py +33 -34
  18. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/results_schemas/generate_files.py +12 -7
  19. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/results_schemas/models/results_schema_model.py +2 -1
  20. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/results_schemas/utils.py +19 -17
  21. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/conftest.py +106 -0
  22. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/test_entity_schema_compare.py +235 -2
  23. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/utils.py +32 -7
  24. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/pyproject.toml +3 -3
  25. liminal_orm-5.1.2/skills/liminal/SKILL.md +411 -0
  26. liminal_orm-5.0.0/liminal/base/compare_operation.py +0 -13
  27. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/__init__.py +0 -0
  28. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_dropdown.py +0 -0
  29. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_operation.py +0 -0
  30. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_validation_filters.py +0 -0
  31. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/compare_operation.py +0 -0
  32. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/name_template_parts.py +0 -0
  33. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_field_properties.py +0 -0
  34. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_name_template.py +0 -0
  35. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_schema_properties.py +0 -0
  36. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/str_enum.py +0 -0
  37. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/cli.py +0 -0
  38. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/controller.py +0 -0
  39. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/live_test_dropdown_migration.py +0 -0
  40. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/live_test_entity_schema_migration.py +0 -0
  41. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/utils.py +0 -0
  42. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/__init__.py +0 -0
  43. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/benchling_connection.py +0 -0
  44. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/benchling_service.py +0 -0
  45. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/api.py +0 -0
  46. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/compare.py +0 -0
  47. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/generate_files.py +0 -0
  48. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/operations.py +0 -0
  49. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/utils.py +0 -0
  50. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/api.py +0 -0
  51. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/compare.py +0 -0
  52. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/entity_schema_models.py +0 -0
  53. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/generate_files.py +0 -0
  54. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/operations.py +0 -0
  55. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/tag_schema_models.py +0 -0
  56. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/utils.py +0 -0
  57. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/__init__.py +0 -0
  58. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_api_field_type.py +0 -0
  59. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_entity_type.py +0 -0
  60. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_field_type.py +0 -0
  61. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_folder_item_type.py +0 -0
  62. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_naming_strategy.py +0 -0
  63. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_sequence_type.py +0 -0
  64. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/name_template_part_type.py +0 -0
  65. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/sequence_constraint.py +0 -0
  66. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/external/__init__.py +0 -0
  67. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/mappers.py +0 -0
  68. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/components.py +0 -0
  69. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/revision.py +0 -0
  70. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/revisions_timeline.py +0 -0
  71. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base.py +0 -0
  72. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_model.py +0 -0
  73. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_results_model.py +0 -0
  74. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/registry_entity.py +0 -0
  75. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/schema.py +0 -0
  76. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/user.py +0 -0
  77. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/column.py +0 -0
  78. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/mixins.py +0 -0
  79. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/name_template.py +0 -0
  80. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/name_template_parts.py +0 -0
  81. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/relationship.py +0 -0
  82. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/results_schema_properties.py +0 -0
  83. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/schema_properties.py +0 -0
  84. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/py.typed +0 -0
  85. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/generate_files.py +0 -0
  86. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/models/results_schema_model.py +0 -0
  87. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/utils.py +0 -0
  88. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/__init__.py +0 -0
  89. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/conftest.py +0 -0
  90. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/from benchling_sdk.py +0 -0
  91. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_benchling_service.py +0 -0
  92. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_dataframe_compatibility.py +0 -0
  93. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_dropdown_compare.py +0 -0
  94. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_entity_schema_compare.py +0 -0
  95. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/unit_dictionary/utils.py +0 -0
  96. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/utils.py +0 -0
  97. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/validation/__init__.py +0 -0
  98. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/validation/validation_severity.py +0 -0
  99. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/__init__.py +0 -0
  100. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/base_dropdown.py +0 -0
  101. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/base_operation.py +0 -0
  102. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/base_validation_filters.py +0 -0
  103. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/compare_operation.py +0 -0
  104. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/name_template_parts.py +0 -0
  105. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/properties/base_field_properties.py +0 -0
  106. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/properties/base_name_template.py +0 -0
  107. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/properties/base_schema_properties.py +0 -0
  108. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/base/str_enum.py +0 -0
  109. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/cli/cli.py +0 -0
  110. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/cli/controller.py +0 -0
  111. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/cli/live_test_dropdown_migration.py +0 -0
  112. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/cli/live_test_entity_schema_migration.py +0 -0
  113. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/cli/utils.py +0 -0
  114. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/connection/__init__.py +0 -0
  115. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/connection/benchling_connection.py +0 -0
  116. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/connection/benchling_service.py +0 -0
  117. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/dropdowns/api.py +0 -0
  118. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/dropdowns/compare.py +0 -0
  119. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/dropdowns/generate_files.py +0 -0
  120. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/dropdowns/operations.py +0 -0
  121. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/dropdowns/utils.py +0 -0
  122. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/api.py +0 -0
  123. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/compare.py +0 -0
  124. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/entity_schema_models.py +0 -0
  125. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/generate_files.py +0 -0
  126. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/operations.py +0 -0
  127. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/tag_schema_models.py +0 -0
  128. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/entity_schemas/utils.py +0 -0
  129. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/__init__.py +0 -0
  130. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_api_field_type.py +0 -0
  131. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_entity_type.py +0 -0
  132. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_field_type.py +0 -0
  133. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_folder_item_type.py +0 -0
  134. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_naming_strategy.py +0 -0
  135. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/benchling_sequence_type.py +0 -0
  136. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/name_template_part_type.py +0 -0
  137. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/enums/sequence_constraint.py +0 -0
  138. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/external/__init__.py +0 -0
  139. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/mappers.py +0 -0
  140. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/migrate/components.py +0 -0
  141. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/migrate/revision.py +0 -0
  142. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/migrate/revisions_timeline.py +0 -0
  143. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base.py +0 -0
  144. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base_model.py +0 -0
  145. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base_results_model.py +0 -0
  146. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base_tables/registry_entity.py +0 -0
  147. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base_tables/schema.py +0 -0
  148. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/base_tables/user.py +0 -0
  149. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/column.py +0 -0
  150. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/mixins.py +0 -0
  151. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/name_template.py +0 -0
  152. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/name_template_parts.py +0 -0
  153. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/relationship.py +0 -0
  154. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/results_schema_properties.py +0 -0
  155. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/orm/schema_properties.py +0 -0
  156. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/py.typed +0 -0
  157. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/results_schemas/generate_files.py +0 -0
  158. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/results_schemas/models/results_schema_model.py +0 -0
  159. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/results_schemas/utils.py +0 -0
  160. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/__init__.py +0 -0
  161. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/conftest.py +0 -0
  162. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/from benchling_sdk.py +0 -0
  163. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/test_benchling_service.py +0 -0
  164. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/test_dataframe_compatibility.py +0 -0
  165. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/test_dropdown_compare.py +0 -0
  166. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/tests/test_entity_schema_compare.py +0 -0
  167. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/unit_dictionary/utils.py +0 -0
  168. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/utils.py +0 -0
  169. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/validation/__init__.py +0 -0
  170. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/arvZabAJhner6mVH/liminal/validation/validation_severity.py +0 -0
  171. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/__init__.py +0 -0
  172. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_dropdown.py +0 -0
  173. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_operation.py +0 -0
  174. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/base_validation_filters.py +0 -0
  175. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/compare_operation.py +0 -0
  176. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/name_template_parts.py +0 -0
  177. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_field_properties.py +0 -0
  178. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_name_template.py +0 -0
  179. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/properties/base_schema_properties.py +0 -0
  180. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/base/str_enum.py +0 -0
  181. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/cli.py +0 -0
  182. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/controller.py +0 -0
  183. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/live_test_dropdown_migration.py +0 -0
  184. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/live_test_entity_schema_migration.py +0 -0
  185. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/cli/utils.py +0 -0
  186. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/__init__.py +0 -0
  187. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/benchling_connection.py +0 -0
  188. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/connection/benchling_service.py +0 -0
  189. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/api.py +0 -0
  190. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/compare.py +0 -0
  191. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/generate_files.py +0 -0
  192. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/operations.py +0 -0
  193. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/dropdowns/utils.py +0 -0
  194. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/api.py +0 -0
  195. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/compare.py +0 -0
  196. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/entity_schema_models.py +0 -0
  197. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/generate_files.py +0 -0
  198. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/operations.py +0 -0
  199. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/tag_schema_models.py +0 -0
  200. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/entity_schemas/utils.py +0 -0
  201. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/__init__.py +0 -0
  202. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_api_field_type.py +0 -0
  203. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_entity_type.py +0 -0
  204. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_field_type.py +0 -0
  205. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_folder_item_type.py +0 -0
  206. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_naming_strategy.py +0 -0
  207. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/benchling_sequence_type.py +0 -0
  208. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/name_template_part_type.py +0 -0
  209. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/enums/sequence_constraint.py +0 -0
  210. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/external/__init__.py +0 -0
  211. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/mappers.py +0 -0
  212. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/components.py +0 -0
  213. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/revision.py +0 -0
  214. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/migrate/revisions_timeline.py +0 -0
  215. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base.py +0 -0
  216. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_model.py +0 -0
  217. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_results_model.py +0 -0
  218. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/registry_entity.py +0 -0
  219. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/schema.py +0 -0
  220. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/base_tables/user.py +0 -0
  221. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/column.py +0 -0
  222. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/mixins.py +0 -0
  223. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/name_template.py +0 -0
  224. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/name_template_parts.py +0 -0
  225. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/relationship.py +0 -0
  226. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/results_schema_properties.py +0 -0
  227. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/orm/schema_properties.py +0 -0
  228. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/py.typed +0 -0
  229. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/generate_files.py +0 -0
  230. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/models/results_schema_model.py +0 -0
  231. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/results_schemas/utils.py +0 -0
  232. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/__init__.py +0 -0
  233. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/conftest.py +0 -0
  234. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/from benchling_sdk.py +0 -0
  235. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_benchling_service.py +0 -0
  236. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_dataframe_compatibility.py +0 -0
  237. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_dropdown_compare.py +0 -0
  238. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/tests/test_entity_schema_compare.py +0 -0
  239. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/unit_dictionary/utils.py +0 -0
  240. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/utils.py +0 -0
  241. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/validation/__init__.py +0 -0
  242. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/.uv-cache/archive-v0/eXa8KUkHhZHOAuoK/liminal/validation/validation_severity.py +0 -0
  243. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/LICENSE.md +0 -0
  244. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/__init__.py +0 -0
  245. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/base_dropdown.py +0 -0
  246. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/base_validation_filters.py +0 -0
  247. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/name_template_parts.py +0 -0
  248. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/properties/base_name_template.py +0 -0
  249. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/base/str_enum.py +0 -0
  250. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/cli/live_test_dropdown_migration.py +0 -0
  251. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/cli/live_test_entity_schema_migration.py +0 -0
  252. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/cli/utils.py +0 -0
  253. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/connection/__init__.py +0 -0
  254. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/connection/benchling_connection.py +0 -0
  255. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/connection/benchling_service.py +0 -0
  256. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/dropdowns/api.py +0 -0
  257. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/dropdowns/compare.py +0 -0
  258. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/dropdowns/operations.py +0 -0
  259. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/dropdowns/utils.py +0 -0
  260. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/api.py +0 -0
  261. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/entity_schemas/test_entity_dataframe_compatibility.py +0 -0
  262. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/__init__.py +0 -0
  263. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_entity_schema_endpoint_type.py +0 -0
  264. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_entity_type.py +0 -0
  265. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_entity_type_name.py +0 -0
  266. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_field_definition_input_type.py +0 -0
  267. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_field_definition_type.py +0 -0
  268. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_field_type.py +0 -0
  269. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_link_definition_type.py +0 -0
  270. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/benchling_naming_strategy.py +0 -0
  271. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/name_template_part_type.py +0 -0
  272. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/enums/sequence_constraint.py +0 -0
  273. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/external/__init__.py +0 -0
  274. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/mappers.py +0 -0
  275. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/migrate/components.py +0 -0
  276. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/migrate/revision.py +0 -0
  277. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/migrate/revisions_timeline.py +0 -0
  278. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base.py +0 -0
  279. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base_model.py +0 -0
  280. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base_results_model.py +0 -0
  281. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base_tables/registry_entity.py +0 -0
  282. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base_tables/schema.py +0 -0
  283. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/base_tables/user.py +0 -0
  284. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/mixins.py +0 -0
  285. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/name_template.py +0 -0
  286. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/name_template_parts.py +0 -0
  287. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/relationship.py +0 -0
  288. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/orm/results_schema_properties.py +0 -0
  289. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/py.typed +0 -0
  290. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/results_schemas/api.py +0 -0
  291. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/results_schemas/test_results_dataframe_compatibility.py +0 -0
  292. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/__init__.py +0 -0
  293. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/from benchling_sdk.py +0 -0
  294. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/test_benchling_service.py +0 -0
  295. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/tests/test_dropdown_compare.py +0 -0
  296. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/unit_dictionary/utils.py +0 -0
  297. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/validation/__init__.py +0 -0
  298. {liminal_orm-5.0.0 → liminal_orm-5.1.2}/liminal/validation/validation_severity.py +0 -0
@@ -19,4 +19,6 @@ site/
19
19
  # for local testing
20
20
  test_liminal/
21
21
 
22
- .history
22
+ .history/
23
+ .cursor/
24
+ .envrc
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: liminal-orm
3
- Version: 5.0.0
3
+ Version: 5.1.2
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
  Project-URL: Homepage, https://github.com/dynotx/liminal-orm
6
6
  Project-URL: Repository, https://github.com/dynotx/liminal-orm
7
7
  Project-URL: Documentation, https://dynotx.github.io/liminal-orm/
8
8
  Project-URL: Bug Tracker, https://github.com/dynotx/liminal-orm/issues
9
- Author-email: DynoTx Open Source <opensource@dynotx.com>
9
+ Author: DynoTx Open Source
10
10
  License-File: LICENSE.md
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
@@ -21,8 +21,8 @@ Requires-Dist: numpy<2,>=1.26; python_version == '3.12'
21
21
  Requires-Dist: numpy<3,>=2.1; python_version == '3.13'
22
22
  Requires-Dist: pandas<3,>=1.5.3; python_version == '3.10'
23
23
  Requires-Dist: pandas<4,>=1.5.3; python_version == '3.11'
24
+ Requires-Dist: pandas<4,>=2.1.1; python_version == '3.12'
24
25
  Requires-Dist: pandas<4,>=2.2.3; python_version == '3.13'
25
- Requires-Dist: pandas<4,>=2.2; python_version == '3.12'
26
26
  Requires-Dist: psycopg2-binary<3,>=2.9.10
27
27
  Requires-Dist: pydantic<=2.13,>=2
28
28
  Requires-Dist: rich<14,>=13.9.2
@@ -136,7 +136,7 @@ Liminal ORM is distributed under the [Apache License, Version 2.0](./LICENSE.md)
136
136
  ## [Direct Contact](#direct-contact)
137
137
 
138
138
  - Liminal Community Slack group: [Join here](https://join.slack.com/t/liminalorm/shared_invite/zt-3fu79tf06-oqL1000p8BAOG6B3yOOXNA)
139
- - Email: <opensource@dynotx.com>
139
+ - Email: <ndamania00@gmail.com>
140
140
  - LinkedIn: [Nirmit Damania](https://www.linkedin.com/in/nirmit-damania/)
141
141
 
142
142
  ## [Acknowledgements](#acknowledgements)
@@ -103,7 +103,7 @@ Liminal ORM is distributed under the [Apache License, Version 2.0](./LICENSE.md)
103
103
  ## [Direct Contact](#direct-contact)
104
104
 
105
105
  - Liminal Community Slack group: [Join here](https://join.slack.com/t/liminalorm/shared_invite/zt-3fu79tf06-oqL1000p8BAOG6B3yOOXNA)
106
- - Email: <opensource@dynotx.com>
106
+ - Email: <ndamania00@gmail.com>
107
107
  - LinkedIn: [Nirmit Damania](https://www.linkedin.com/in/nirmit-damania/)
108
108
 
109
109
  ## [Acknowledgements](#acknowledgements)
@@ -16,10 +16,10 @@ Order of operations based on order class var:
16
16
  9. CreateEntitySchema
17
17
  10. UnarchiveEntitySchema
18
18
  11. CreateEntitySchemaField
19
- 12. UpdateEntitySchemaNameTemplate
20
- 13. UpdateEntitySchema
21
- 14. UnarchiveEntitySchemaField
22
- 15. UpdateEntitySchemaField
19
+ 12. UpdateEntitySchema
20
+ 13. UnarchiveEntitySchemaField
21
+ 14. UpdateEntitySchemaField
22
+ 15. UpdateEntitySchemaNameTemplate
23
23
  16. ArchiveEntitySchemaField
24
24
  17. ReorderEntitySchemaFields
25
25
  18. ArchiveEntitySchema
@@ -0,0 +1,19 @@
1
+ from pydantic import BaseModel, ConfigDict
2
+
3
+ from liminal.base.base_operation import BaseOperation
4
+
5
+
6
+ class CompareOperation(BaseModel):
7
+ op: BaseOperation
8
+ reverse_op: BaseOperation
9
+ # Overrides op.order when this operation must run at a different point than its type's default.
10
+ order_override: int | None = None
11
+
12
+ model_config = ConfigDict(arbitrary_types_allowed=True)
13
+
14
+ @property
15
+ def sort_order(self) -> int:
16
+ return self.op.order if self.order_override is None else self.order_override
17
+
18
+ def __lt__(self, other: "CompareOperation") -> bool:
19
+ return self.sort_order < other.sort_order
@@ -65,8 +65,6 @@ class BaseFieldProperties(BaseModel):
65
65
  non_multi_types = BenchlingFieldType.get_non_multi_select_types()
66
66
  if field_type in non_multi_types:
67
67
  unsupported.add("is_multi")
68
- if not (has_entity_link and field_type == BenchlingFieldType.ENTITY_LINK):
69
- unsupported.add("parent_link")
70
68
  if field_type not in BenchlingFieldType.get_number_field_types():
71
69
  unsupported.add("unit_name")
72
70
  if field_type != BenchlingFieldType.DECIMAL:
@@ -96,6 +94,11 @@ class BaseFieldProperties(BaseModel):
96
94
  self.__pydantic_fields_set__.remove("unit_name")
97
95
  return self
98
96
 
97
+ def unset_parent_link(self) -> BaseFieldProperties:
98
+ if "parent_link" in self.__pydantic_fields_set__:
99
+ self.__pydantic_fields_set__.remove("parent_link")
100
+ return self
101
+
99
102
  def set_type(self, new_type: BenchlingFieldType) -> BaseFieldProperties:
100
103
  self.type = new_type
101
104
  return self
@@ -105,6 +105,11 @@ class BaseSchemaProperties(BaseModel):
105
105
  self.naming_strategies = value
106
106
  return self
107
107
 
108
+ def unset_naming_strategies(self) -> BaseSchemaProperties:
109
+ if "naming_strategies" in self.__pydantic_fields_set__:
110
+ self.__pydantic_fields_set__.remove("naming_strategies")
111
+ return self
112
+
108
113
  def merge(self, new_props: BaseSchemaProperties) -> dict[str, Any]:
109
114
  """Creates a diff between the current schema properties and the new schema properties.
110
115
  Sets value to None if the values are equal, otherwise sets the value to the new value.
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env python
2
+ import json
2
3
  from pathlib import Path
4
+ import sys
3
5
  from typing import Any
4
6
 
5
7
  import typer
@@ -8,6 +10,7 @@ from typer.core import TyperGroup
8
10
 
9
11
  from liminal.cli.controller import (
10
12
  autogenerate_revision_file,
13
+ diff_benchling_tenant,
11
14
  downgrade_benchling_tenant,
12
15
  generate_all_files,
13
16
  upgrade_benchling_tenant,
@@ -120,7 +123,7 @@ def generate_files(
120
123
  benchling_connection = read_local_liminal_dir(LIMINAL_DIR_PATH, benchling_tenant)
121
124
  benchling_service = BenchlingService(benchling_connection)
122
125
  if not write_path.exists():
123
- write_path.mkdir()
126
+ write_path.mkdir(parents=True)
124
127
  print(f"[green]Created directory: {write_path}")
125
128
  if not entity_schemas_flag and not dropdowns_flag and not results_schemas_flag:
126
129
  entity_schemas_flag = True
@@ -176,6 +179,71 @@ def head(
176
179
  print(f"[blue]{revision_timeline.get_latest_revision().id}: (head)[/blue]")
177
180
 
178
181
 
182
+ @app.command(
183
+ name="diff",
184
+ help="Compares the locally defined dropdowns and entity schemas to the given Benchling tenant. Exit codes: 0=in sync, 1=error, 2=differences found.",
185
+ )
186
+ def diff(
187
+ benchling_tenant: str = typer.Argument(
188
+ ..., help="Benchling tenant (or alias) to connect to."
189
+ ),
190
+ dropdowns_flag: bool = typer.Option(
191
+ False,
192
+ "-d",
193
+ "--dropdowns",
194
+ help="Only compare dropdowns.",
195
+ ),
196
+ entity_schemas_flag: bool = typer.Option(
197
+ False,
198
+ "-es",
199
+ "--entity-schemas",
200
+ help="Only compare entity schemas.",
201
+ ),
202
+ json_output: bool = typer.Option(
203
+ False,
204
+ "--json",
205
+ help="Write a machine-readable comparison report to stdout.",
206
+ ),
207
+ ) -> None:
208
+ benchling_connection = read_local_liminal_dir(LIMINAL_DIR_PATH, benchling_tenant)
209
+ benchling_service = BenchlingService(benchling_connection)
210
+ if not dropdowns_flag and not entity_schemas_flag:
211
+ dropdowns_flag = True
212
+ entity_schemas_flag = True
213
+ report = diff_benchling_tenant(
214
+ benchling_service, dropdowns_flag, entity_schemas_flag
215
+ )
216
+ if json_output:
217
+ typer.echo(json.dumps(report, sort_keys=True))
218
+ else:
219
+ for key, label in (
220
+ ("dropdowns", "Dropdowns"),
221
+ ("entity_schemas", "Entity schemas"),
222
+ ):
223
+ section = report[key]
224
+ if not section["compared"]:
225
+ continue
226
+ if section["in_sync"]:
227
+ print(f"[bold green]{label} are in sync for {report['tenant']} tenant.")
228
+ continue
229
+ print(
230
+ f"[bold yellow]{label}: {len(section['differences'])} difference(s) for {report['tenant']} tenant."
231
+ )
232
+ for index, difference in enumerate(section["differences"], start=1):
233
+ print(f" {index}. {difference['description']}")
234
+
235
+ if report["in_sync"]:
236
+ print(
237
+ f"[bold green]No differences found. {report['tenant']} is in sync with code."
238
+ )
239
+ else:
240
+ print(
241
+ f"[bold yellow]{report['total_differences']} total difference(s) found between code and {report['tenant']}. Run `liminal revision {report['tenant']} '<description>'` to generate a revision file that resolves them."
242
+ )
243
+ if not report["in_sync"]:
244
+ raise typer.Exit(code=2)
245
+
246
+
179
247
  @app.command(
180
248
  name="revision",
181
249
  help="Generates a revision file with a list of operations to bring the given Benchling tenant up to date with the locally defined schemas. Writes revision file to liminal/versions/.",
@@ -327,5 +395,5 @@ def live_test(
327
395
  )
328
396
 
329
397
 
330
- print("Starting Liminal CLI...")
398
+ print("Starting Liminal CLI...", file=sys.stderr)
331
399
  app()
@@ -1,9 +1,13 @@
1
1
  from pathlib import Path
2
+ from typing import Any
2
3
 
3
4
  from rich import print
4
5
 
6
+ from liminal.base.compare_operation import CompareOperation
5
7
  from liminal.connection.benchling_service import BenchlingService
8
+ from liminal.dropdowns.compare import compare_dropdowns
6
9
  from liminal.dropdowns.generate_files import generate_all_dropdown_files
10
+ from liminal.entity_schemas.compare import compare_entity_schemas
7
11
  from liminal.entity_schemas.generate_files import generate_all_entity_schema_files
8
12
  from liminal.migrate.components import execute_operations, get_full_migration_operations
9
13
  from liminal.migrate.revisions_timeline import RevisionsTimeline
@@ -45,6 +49,68 @@ def generate_all_files(
45
49
  generate_all_results_schema_files(benchling_service, write_path, overwrite)
46
50
 
47
51
 
52
+ def diff_benchling_tenant(
53
+ benchling_service: BenchlingService,
54
+ dropdowns_flag: bool = True,
55
+ entity_schemas_flag: bool = True,
56
+ ) -> dict[str, Any]:
57
+ """Compares locally defined schemas to a Benchling tenant.
58
+
59
+ This is read-only and does not make any changes to the Benchling tenant or
60
+ write any files.
61
+
62
+ Parameters
63
+ ----------
64
+ benchling_service : BenchlingService
65
+ The Benchling service object that is connected to a specified Benchling tenant.
66
+ dropdowns_flag : bool
67
+ Whether to compare dropdowns.
68
+ entity_schemas_flag : bool
69
+ Whether to compare entity schemas.
70
+
71
+ Returns
72
+ -------
73
+ dict[str, Any]
74
+ A machine-readable report of the comparison.
75
+ """
76
+ tenant = benchling_service.benchling_tenant
77
+ sections: dict[str, dict[str, list[CompareOperation]] | None] = {
78
+ "dropdowns": None,
79
+ "entity_schemas": None,
80
+ }
81
+ if dropdowns_flag:
82
+ sections["dropdowns"] = compare_dropdowns(benchling_service)
83
+ if entity_schemas_flag:
84
+ sections["entity_schemas"] = compare_entity_schemas(benchling_service)
85
+
86
+ report: dict[str, Any] = {"tenant": tenant, "total_differences": 0}
87
+ for section_name, comparison in sections.items():
88
+ compared = comparison is not None
89
+ differences = [
90
+ {
91
+ "name": name,
92
+ "operation": compare_op.op.__class__.__name__,
93
+ "description": compare_op.op.describe(),
94
+ }
95
+ for name, compare_op in sorted(
96
+ (
97
+ (name, compare_op)
98
+ for name, compare_ops in (comparison or {}).items()
99
+ for compare_op in compare_ops
100
+ ),
101
+ key=lambda difference: difference[1],
102
+ )
103
+ ]
104
+ report[section_name] = {
105
+ "compared": compared,
106
+ "in_sync": len(differences) == 0 if compared else None,
107
+ "differences": differences,
108
+ }
109
+ report["total_differences"] += len(differences)
110
+ report["in_sync"] = report["total_differences"] == 0
111
+ return report
112
+
113
+
48
114
  def autogenerate_revision_file(
49
115
  benchling_service: BenchlingService,
50
116
  revisions_timeline: RevisionsTimeline,
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import shutil
2
3
  from pathlib import Path
3
4
 
@@ -5,7 +6,7 @@ from rich import print
5
6
 
6
7
  from liminal.connection import BenchlingService
7
8
  from liminal.dropdowns.utils import get_benchling_dropdowns_dict
8
- from liminal.utils import to_pascal_case, to_snake_case
9
+ from liminal.utils import to_module_name, to_pascal_case
9
10
 
10
11
 
11
12
  def generate_all_dropdown_files(
@@ -36,17 +37,17 @@ def generate_all_dropdown_files(
36
37
  num_files_written = 0
37
38
  for dropdown_name, dropdown_options in dropdowns.items():
38
39
  dropdown_values = [option.name for option in dropdown_options.options]
39
- options_list = str(dropdown_values).replace("'", '"')
40
+ options_list = json.dumps(dropdown_values, ensure_ascii=False)
40
41
  classname = to_pascal_case(dropdown_name)
41
42
  dropdown_content = f"""
42
43
  from liminal.base.base_dropdown import BaseDropdown
43
44
 
44
45
 
45
46
  class {classname}(BaseDropdown):
46
- __benchling_name__ = "{dropdown_name}"
47
+ __benchling_name__ = {json.dumps(dropdown_name, ensure_ascii=False)}
47
48
  __allowed_values__ = {options_list}
48
49
  """
49
- filename = to_snake_case(dropdown_name) + ".py"
50
+ filename = to_module_name(dropdown_name) + ".py"
50
51
  if overwrite or not (write_path / filename).exists():
51
52
  with open(write_path / filename, "w") as file:
52
53
  file.write(dropdown_content)
@@ -26,6 +26,9 @@ from liminal.utils import to_snake_case
26
26
 
27
27
  LOGGER = logging.getLogger(__name__)
28
28
 
29
+ # Template based naming strategies need the name template, so the order is overridden to be set right after it.
30
+ NAME_TEMPLATE_NAMING_STRATEGY_ORDER = UpdateEntitySchemaNameTemplate.order + 1
31
+
29
32
 
30
33
  def compare_entity_schemas(
31
34
  benchling_service: BenchlingService, schema_names: set[str] | None = None
@@ -237,26 +240,50 @@ def compare_entity_schemas(
237
240
  )
238
241
  )
239
242
  if benchling_schema_props != model.__schema_properties__:
240
- ops.append(
241
- CompareOperation(
242
- op=UpdateEntitySchema(
243
- model.__schema_properties__.warehouse_name,
244
- BaseSchemaProperties(
245
- **benchling_schema_props.merge(
246
- model.__schema_properties__
247
- )
243
+ new_schema_props = BaseSchemaProperties(
244
+ **benchling_schema_props.merge(model.__schema_properties__)
245
+ )
246
+ rollback_schema_props = BaseSchemaProperties(
247
+ **model.__schema_properties__.merge(benchling_schema_props)
248
+ )
249
+ model_strategies = (
250
+ model.__schema_properties__.naming_strategies or set()
251
+ )
252
+ benchling_strategies = benchling_schema_props.naming_strategies or set()
253
+ # A template based naming strategy needs the name template, which runs after UpdateEntitySchema.
254
+ # So when one is being added, set all the naming strategies in their own operation after the template.
255
+ if any(
256
+ BenchlingNamingStrategy.is_template_based(s)
257
+ for s in model_strategies - benchling_strategies
258
+ ):
259
+ new_schema_props.unset_naming_strategies()
260
+ rollback_schema_props.unset_naming_strategies()
261
+ ops.append(
262
+ CompareOperation(
263
+ op=UpdateEntitySchema(
264
+ model_wh_name,
265
+ BaseSchemaProperties(
266
+ naming_strategies=model_strategies
267
+ ),
248
268
  ),
249
- ),
250
- reverse_op=UpdateEntitySchema(
251
- model.__schema_properties__.warehouse_name,
252
- BaseSchemaProperties(
253
- **model.__schema_properties__.merge(
254
- benchling_schema_props
255
- )
269
+ reverse_op=UpdateEntitySchema(
270
+ model_wh_name,
271
+ BaseSchemaProperties(
272
+ naming_strategies=benchling_strategies
273
+ ),
274
+ ),
275
+ order_override=NAME_TEMPLATE_NAMING_STRATEGY_ORDER,
276
+ )
277
+ )
278
+ if new_schema_props.model_dump(exclude_unset=True) != {}:
279
+ ops.append(
280
+ CompareOperation(
281
+ op=UpdateEntitySchema(model_wh_name, new_schema_props),
282
+ reverse_op=UpdateEntitySchema(
283
+ model_wh_name, rollback_schema_props
256
284
  ),
257
285
  ),
258
- ),
259
- )
286
+ )
260
287
  if benchling_name_template != model.__name_template__:
261
288
  ops.append(
262
289
  CompareOperation(
@@ -300,8 +327,24 @@ def compare_entity_schemas(
300
327
  for p in field_props
301
328
  if (p.unit_name and p.warehouse_name)
302
329
  }
330
+ # A link field is created without a target, and Benchling only accepts
331
+ # parent_link on a field that has one, so it is set with the target.
332
+ parent_links_to_update = {
333
+ p.warehouse_name
334
+ for p in field_props
335
+ if (p.parent_link and p.entity_link and p.warehouse_name)
336
+ }
303
337
  field_props = [
304
- f.unset_tooltip().unset_entity_link().unset_unit_name()
338
+ f.unset_tooltip()
339
+ .unset_entity_link()
340
+ .unset_unit_name()
341
+ .unset_parent_link()
342
+ for f in field_props
343
+ ]
344
+ field_props = [
345
+ f.unset_parent_link()
346
+ if f.warehouse_name in parent_links_to_update
347
+ else f
305
348
  for f in field_props
306
349
  ]
307
350
  field_props = [
@@ -337,32 +380,20 @@ def compare_entity_schemas(
337
380
  )
338
381
  )
339
382
  # Benchling api does not allow for setting a custom warehouse_name.
340
- # Benchling api also does not allow for setting the name template.
341
383
  # Because of this, we need to run a separate UpdateEntitySchema to set the warehouse_name if it is different from the snakecase version of the model name.
342
- # We also need to set the template based naming_strategies separately, since the name template must first be set.
343
- new_schema_props = BaseSchemaProperties()
344
- rollback_schema_props = BaseSchemaProperties()
384
+ # Later operations on this schema use the model's warehouse_name.
345
385
  if model_wh_name != benchling_given_wh_name:
346
- new_schema_props.warehouse_name = model_wh_name
347
- rollback_schema_props.warehouse_name = benchling_given_wh_name
348
- if (
349
- model.__schema_properties__.naming_strategies
350
- - standard_naming_strategies
351
- ):
352
- new_schema_props.naming_strategies = (
353
- model.__schema_properties__.naming_strategies
354
- )
355
- rollback_schema_props.naming_strategies = standard_naming_strategies
356
- if new_schema_props.model_dump(exclude_unset=True) != {}:
357
386
  ops.append(
358
387
  CompareOperation(
359
388
  op=UpdateEntitySchema(
360
389
  benchling_given_wh_name,
361
- new_schema_props,
390
+ BaseSchemaProperties(warehouse_name=model_wh_name),
362
391
  ),
363
392
  reverse_op=UpdateEntitySchema(
364
393
  model_wh_name,
365
- rollback_schema_props,
394
+ BaseSchemaProperties(
395
+ warehouse_name=benchling_given_wh_name
396
+ ),
366
397
  ),
367
398
  )
368
399
  )
@@ -382,6 +413,9 @@ def compare_entity_schemas(
382
413
  )
383
414
  rollback_field_props.entity_link = None
384
415
  rollback_field_props.type = BenchlingFieldType.ENTITY_LINK
416
+ if wh_field_name in parent_links_to_update:
417
+ new_field_props.parent_link = True
418
+ rollback_field_props.parent_link = False
385
419
  if tooltip_value := tooltips_to_update.get(wh_field_name):
386
420
  new_field_props.tooltip = tooltip_value
387
421
  rollback_field_props.tooltip = None
@@ -403,11 +437,12 @@ def compare_entity_schemas(
403
437
  )
404
438
  # Benchling api also does not allow for setting the name template when Creating an Entity Schema, since it is a different endpoint.
405
439
  # Because of this, we need to run a separate UpdateEntitySchemaNameTemplate using the name template endpoint to set the name template on the newly created Entity Schema.
440
+ # The name template update runs after the field updates above, since a part can need a link target or parent link set there.
406
441
  if benchling_given_name_template != model.__name_template__:
407
442
  ops.append(
408
443
  CompareOperation(
409
444
  op=UpdateEntitySchemaNameTemplate(
410
- benchling_given_wh_name,
445
+ model_wh_name,
411
446
  BaseNameTemplate(
412
447
  **benchling_given_name_template.merge(
413
448
  model.__name_template__
@@ -415,7 +450,7 @@ def compare_entity_schemas(
415
450
  ),
416
451
  ),
417
452
  reverse_op=UpdateEntitySchemaNameTemplate(
418
- benchling_given_wh_name,
453
+ model_wh_name,
419
454
  BaseNameTemplate(
420
455
  **model.__name_template__.merge(
421
456
  benchling_given_name_template
@@ -424,6 +459,28 @@ def compare_entity_schemas(
424
459
  ),
425
460
  )
426
461
  )
462
+ # Template based naming_strategies need the name template, so they are set right after it.
463
+ if (
464
+ model.__schema_properties__.naming_strategies
465
+ - standard_naming_strategies
466
+ ):
467
+ ops.append(
468
+ CompareOperation(
469
+ op=UpdateEntitySchema(
470
+ model_wh_name,
471
+ BaseSchemaProperties(
472
+ naming_strategies=model.__schema_properties__.naming_strategies
473
+ ),
474
+ ),
475
+ reverse_op=UpdateEntitySchema(
476
+ model_wh_name,
477
+ BaseSchemaProperties(
478
+ naming_strategies=standard_naming_strategies
479
+ ),
480
+ ),
481
+ order_override=NAME_TEMPLATE_NAMING_STRATEGY_ORDER,
482
+ )
483
+ )
427
484
 
428
485
  model_operations[model.__schema_properties__.warehouse_name] = ops
429
486
  running_benchling_schema_names = [
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from functools import lru_cache
4
5
  from typing import Any
5
6
 
@@ -129,18 +130,26 @@ class EntitySchemaFieldModel(BaseModel):
129
130
  self.description = (
130
131
  update_props.tooltip if "tooltip" in update_diff_names else self.description
131
132
  )
132
- if "entity_link" in update_diff_names and update_props.entity_link:
133
- if benchling_service is None:
134
- raise ValueError(
135
- "Benchling SDK must be provided to update entity link field."
133
+ if "entity_link" in update_diff_names:
134
+ if update_props.entity_link is None:
135
+ self.linkDefinition = None
136
+ # Without a target schema the field is a generic entity link, not e.g. a CustomEntityLinkFieldDefinition.
137
+ if BenchlingFieldDefinitionType.is_entity_link(self.typename):
138
+ self.typename = (
139
+ BenchlingFieldDefinitionType.ANY_ENTITY_LINK_FIELD_DEFINITION
140
+ )
141
+ else:
142
+ if benchling_service is None:
143
+ raise ValueError(
144
+ "Benchling SDK must be provided to update entity link field."
145
+ )
146
+ linked_schema = EntitySchemaModel.get_one_cached(
147
+ benchling_service, update_props.entity_link
148
+ )
149
+ self.linkDefinition = FieldLinkDefinitionModel(
150
+ id=linked_schema.id,
151
+ typename=BenchlingLinkDefinitionType(linked_schema.typename.value),
136
152
  )
137
- linked_schema = EntitySchemaModel.get_one_cached(
138
- benchling_service, update_props.entity_link
139
- )
140
- self.linkDefinition = FieldLinkDefinitionModel(
141
- id=linked_schema.id,
142
- typename=BenchlingLinkDefinitionType(linked_schema.typename.value),
143
- )
144
153
  if "type" in update_diff_names and update_props.type:
145
154
  linked_schema_type = (
146
155
  BenchlingEntityTypeName(self.linkDefinition.typename.value)
@@ -484,7 +493,8 @@ class EntitySchemaModel(BaseModel):
484
493
  availableRegistrationNamingOptions: list[BenchlingNamingStrategy] | None = None
485
494
  constraint: EntitySchemaConstraintModel | None = None
486
495
  nameTemplate: NameTemplateModel | None = None
487
- containerNameTemplate: NameTemplateModel | None = None
496
+ # TODO(#263): Add coverage for containerNameTemplate.
497
+ containerNameTemplate: dict[str, Any] | None = None
488
498
  showResidues: bool | None = None
489
499
  typedIconId: str | None = None
490
500
  allowMeasuredIngredients: bool | None = None
@@ -519,7 +529,10 @@ class EntitySchemaModel(BaseModel):
519
529
  try:
520
530
  filtered_schemas.append(cls.model_validate(schema))
521
531
  except Exception as e:
522
- print(f"Error validating schema {schema['systemName']}: {e}")
532
+ warnings.warn(
533
+ f"Skipping schema {schema['systemName']}: failed validation: {e}",
534
+ stacklevel=2,
535
+ )
523
536
  return filtered_schemas
524
537
 
525
538
  @classmethod