Fix Object TTL schema export to match server json#1958
Fix Object TTL schema export to match server json#1958dudanogueira wants to merge 2 commits intoweaviate:mainfrom
Conversation
There was a problem hiding this comment.
Orca Security Scan Summary
| Status | Check | Issues by priority | |
|---|---|---|---|
| Infrastructure as Code | View in Orca | ||
| SAST | View in Orca | ||
| Secrets | View in Orca | ||
| Vulnerabilities | View in Orca |
There was a problem hiding this comment.
Pull request overview
This PR fixes schema export/import round-tripping for collections configured with Object TTL by aligning the Python client’s exported TTL config dictionary with the Weaviate server’s expected JSON shape (Fixes #1957).
Changes:
- Implement
_ObjectTTLConfig.to_dict()to emitdefaultTtland the correct internal timestamp fields fordeleteOn(_creationTimeUnix/_lastUpdateTimeUnix). - Update unit tests to reflect the corrected TTL serialization and add a small deserialization→serialization round-trip test.
- Add an integration test validating TTL config export via
export_config()for multipledeleteOnmodes.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
weaviate/collections/classes/config.py |
Adds custom to_dict() for _ObjectTTLConfig to match server JSON (defaultTtl, internal deleteOn values). |
test/collection/test_config.py |
Updates expected TTL dict keys/values and adds a round-trip unit test for TTL config parsing + serialization. |
integration/test_collection_config.py |
Adds an integration test to validate TTL config export behavior from the server. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def to_dict(self) -> dict: | ||
| delete_on = self.delete_on | ||
| if delete_on == "creationTime": | ||
| delete_on = "_creationTimeUnix" | ||
| elif delete_on == "updateTime": | ||
| delete_on = "_lastUpdateTimeUnix" | ||
|
|
There was a problem hiding this comment.
The deleteOn value mapping (creationTime/updateTime <-> _creationTimeUnix/_lastUpdateTimeUnix) is now duplicated here and in config_methods._get_object_ttl_config. To reduce the chance of the two drifting over time, consider centralizing this mapping (e.g., module-level constants or a small helper used by both serialization and deserialization).
| def test_object_ttl_roundtrip_from_dict( | ||
| collection_factory: CollectionFactory, client_factory: ClientFactory | ||
| ) -> None: | ||
| dummy = collection_factory("dummy") | ||
| if dummy._connection._weaviate_version.is_lower_than(1, 35, 0): | ||
| pytest.skip("object ttl is not supported in Weaviate versions lower than 1.35.0") | ||
|
|
||
| client = client_factory() | ||
|
|
||
| # (schema_to_create, expected_object_ttl_config_dict) | ||
| test_cases = [ | ||
| # deleteOn: _creationTimeUnix | ||
| ( | ||
| { | ||
| "class": "CollectionTTLRoundtripCreation", | ||
| "objectTtlConfig": { | ||
| "enabled": True, | ||
| "defaultTtl": 60, | ||
| "deleteOn": "_creationTimeUnix", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| }, | ||
| { | ||
| "enabled": True, | ||
| "defaultTtl": 60, | ||
| "deleteOn": "_creationTimeUnix", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| ), | ||
| # deleteOn: _lastUpdateTimeUnix | ||
| ( | ||
| { | ||
| "class": "CollectionTTLRoundtripUpdate", | ||
| "objectTtlConfig": { | ||
| "enabled": True, | ||
| "defaultTtl": 3600, | ||
| "deleteOn": "_lastUpdateTimeUnix", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| }, | ||
| { | ||
| "enabled": True, | ||
| "defaultTtl": 3600, | ||
| "deleteOn": "_lastUpdateTimeUnix", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| ), | ||
| # deleteOn: custom date property | ||
| ( | ||
| { | ||
| "class": "CollectionTTLRoundtripDateProp", | ||
| "properties": [ | ||
| { | ||
| "name": "reference_date", | ||
| "dataType": ["date"], | ||
| } | ||
| ], | ||
| "objectTtlConfig": { | ||
| "enabled": True, | ||
| "defaultTtl": 123, | ||
| "deleteOn": "reference_date", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| }, | ||
| { | ||
| "enabled": True, | ||
| "defaultTtl": 123, | ||
| "deleteOn": "reference_date", | ||
| "filterExpiredObjects": True, | ||
| }, | ||
| ), | ||
| ] | ||
|
|
||
| for schema, expected_ttl_dict in test_cases: | ||
| name = schema["class"] | ||
| client.collections.delete(name) | ||
| try: | ||
| client.collections.create_from_dict(schema) | ||
| config = client.collections.export_config(name) | ||
| assert config.object_ttl_config is not None, f"object_ttl_config is None for {name}" | ||
| assert config.object_ttl_config.to_dict() == expected_ttl_dict, ( | ||
| f"Round-trip mismatch for {name}: " | ||
| f"got {config.object_ttl_config.to_dict()}, expected {expected_ttl_dict}" | ||
| ) |
There was a problem hiding this comment.
This integration test asserts object_ttl_config.to_dict() but doesn’t exercise the actual failure mode from #1957 (exporting a full collection schema dict and re-importing it). Consider extending this test to export via collection.config.get().to_dict() (or client.collections.export_config(...).to_dict()), then call create_from_dict() with the exported dict and assert it succeeds. That would directly guard against regressions in schema round-tripping.
Fixes #1957