diff --git a/field_friend/automations/field.py b/field_friend/automations/field.py index a4df4704..6026aa0d 100644 --- a/field_friend/automations/field.py +++ b/field_friend/automations/field.py @@ -1,4 +1,5 @@ import math +import uuid from dataclasses import dataclass from typing import Any, Self @@ -161,15 +162,36 @@ def shapely_polygon(self) -> shapely.geometry.Polygon: @classmethod def args_from_dict(cls, data: dict[str, Any]) -> dict: - return data + # Ensure all required fields exist with defaults + defaults: dict[str, Any] = { + 'id': str(uuid.uuid4()), + 'name': 'Field', + 'first_row_start': None, + 'first_row_end': None, + 'row_spacing': 1, + 'row_count': 1, + 'outline_buffer_width': 1, + 'row_support_points': [], + 'bed_count': 1, + 'bed_spacing': 1 + } + for key in defaults: + if key in data: + defaults[key] = data[key] + return defaults @classmethod def from_dict(cls, data: dict[str, Any]) -> Self: - data['first_row_start'] = GeoPoint(lat=data['first_row_start']['lat'], long=data['first_row_start']['long']) - data['first_row_end'] = GeoPoint(lat=data['first_row_end']['lat'], long=data['first_row_end']['long']) + data['first_row_start'] = GeoPoint(lat=data['first_row_start']['lat'], + long=data['first_row_start']['long']) if data.get('first_row_start') else GeoPoint(lat=0, long=0) + data['first_row_end'] = GeoPoint(lat=data['first_row_end']['lat'], + long=data['first_row_end']['long']) if data.get('first_row_end') else GeoPoint(lat=1, long=1) data['row_support_points'] = [rosys.persistence.from_dict( - RowSupportPoint, sp) for sp in data['row_support_points']] if 'row_support_points' in data else [] + RowSupportPoint, sp) for sp in data['row_support_points']] if data.get('row_support_points') else [] field_data = cls(**cls.args_from_dict(data)) + # if id is None, set it to a random uuid + if field_data.id is None: + field_data.id = str(uuid.uuid4()) return field_data def get_buffered_area(self, rows: list[Row], buffer_width: float) -> list[GeoPoint]: diff --git a/tests/old_field_provider_persistence.json b/tests/old_field_provider_persistence.json index a1909a8f..f615649b 100644 --- a/tests/old_field_provider_persistence.json +++ b/tests/old_field_provider_persistence.json @@ -11,7 +11,9 @@ "row_spacing": 0.5, "row_count": 10, "outline_buffer_width": 2, - "row_support_points": [] + "row_support_points": [], + "bed_count": 1, + "bed_spacing": 0.5 } } } diff --git a/tests/old_field_provider_persistence_with_errors.json b/tests/old_field_provider_persistence_with_errors.json new file mode 100644 index 00000000..f9dfac2f --- /dev/null +++ b/tests/old_field_provider_persistence_with_errors.json @@ -0,0 +1,19 @@ +{ + "fields": { + "eb24db0f-d48e-4a88-b23a-4833cda55483": { + "id": "eb24db0f-d48e-4a88-b23a-4833cda55483", + "name": "field_1", + "first_row_start": { + "lat": 51.98333789813455, + "long": 7.434242765994318 + }, + "first_row_end": { "lat": 51.98334192260392, "long": 7.434293309874038 }, + "row_spacing": 0.5, + "row_count": 10, + "not_existing_value": true, + "row_support_points": [], + "bed_count": 1, + "bed_spacing": 0.5 + } + } +} diff --git a/tests/test_field_provider.py b/tests/test_field_provider.py index 292c6a31..6841f7b2 100644 --- a/tests/test_field_provider.py +++ b/tests/test_field_provider.py @@ -11,7 +11,7 @@ from field_friend.localization import GeoPoint -def test_loading_from_old_persistence(system: System): +def test_loading_from_persistence(system: System): system.field_provider.restore(json.loads(Path('tests/old_field_provider_persistence.json').read_text())) assert len(system.field_provider.fields) == 1 field = system.field_provider.fields[0] @@ -27,6 +27,25 @@ def test_loading_from_old_persistence(system: System): assert field.first_row_end == GeoPoint(lat=51.98334192260392, long=7.434293309874038) +def test_loading_from_persistence_with_errors(system: System): + system.field_provider.restore(json.loads(Path('tests/old_field_provider_persistence_with_errors.json').read_text())) + assert len(system.field_provider.fields) == 1 + field = system.field_provider.fields[0] + # should set outline_buffer_width to default value because it is missing in the persistence data + assert field.outline_buffer_width == 1 + # should not write the not_existing_value to the field + assert not hasattr(field, 'not_existing_value') + assert field.row_count == 10 + assert field.row_spacing == 0.5 + assert len(field.outline) == 5 + assert len(field.rows) == 10 + assert len(field.row_support_points) == 0 + for row in field.rows: + assert len(row.points) == 2 + assert field.first_row_start == FIELD_FIRST_ROW_START + assert field.first_row_end == GeoPoint(lat=51.98334192260392, long=7.434293309874038) + + def test_field_outline(system: System, field: Field): field = system.field_provider.fields[0] outline = field.outline