From 2dee3d08e41e02fc1c1f6d9c777f7b1800c7457c Mon Sep 17 00:00:00 2001 From: Alastair Weakley Date: Thu, 27 Jun 2024 16:52:22 +1000 Subject: [PATCH 1/2] WIP adding checks for edtf field aliases #62 --- edtf/fields.py | 42 +++++++++++++++++++++ edtf_django_tests/edtf_integration/tests.py | 35 +++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/edtf/fields.py b/edtf/fields.py index 7dba5d4..9cf6b27 100644 --- a/edtf/fields.py +++ b/edtf/fields.py @@ -1,5 +1,6 @@ import pickle +from django.core import checks from django.core.exceptions import FieldDoesNotExist from django.db import models from django.db.models import signals @@ -188,3 +189,44 @@ def contribute_to_class(self, cls, name, **kwargs): # Only run post-initialization values update on non-abstract models if not cls._meta.abstract: signals.post_init.connect(self.update_values, sender=cls) + + def check(self, **kwargs): + errors = super().check(**kwargs) + + for field_alias in [ + "direct_input_field", + "lower_fuzzy_field", + "lower_strict_field", + "natural_text_field", + "upper_fuzzy_field", + "upper_strict_field", + ]: + errors.extend(self._check_field(field_alias)) + + return errors + + def _check_field(self, field_alias): + field_name = getattr(self, field_alias, None) + + # Check if the alias value has been provided in the field definition + if not field_name: + return [ + checks.Error( + f"You must specify a '{field_alias}' for EDTFField", + hint=None, + obj=self, + ) + ] + + # Check if the field that is referenced actually exists + try: + self.model._meta.get_field(field_name) + except FieldDoesNotExist: + return [ + checks.Error( + f"'{self.name}' refers to a non-existent '{field_alias}' field: '{field_name}'", + hint=None, + obj=self, + ) + ] + return [] diff --git a/edtf_django_tests/edtf_integration/tests.py b/edtf_django_tests/edtf_integration/tests.py index 493d0d2..da5bb83 100644 --- a/edtf_django_tests/edtf_integration/tests.py +++ b/edtf_django_tests/edtf_integration/tests.py @@ -122,3 +122,38 @@ def test_comparison(self): self.event2.date_edtf, "2019-11 is less than 2021-05-06", ) + + def test_field_related_field_specification(self): + edtf_field_on_model = TestEvent._meta.get_field("date_edtf") + required_fields = ( + "direct_input_field", + "lower_fuzzy_field", + "lower_strict_field", + "natural_text_field", + "upper_fuzzy_field", + "upper_strict_field", + ) + for field_alias in required_fields: + # Remove the alias from the edtf_field + orig_value = getattr(edtf_field_on_model, field_alias) + setattr(edtf_field_on_model, field_alias, None) + errors = edtf_field_on_model.check() + self.assertEqual(len(errors), 1) + self.assertTrue(field_alias in errors[0].msg) + # Replace the field so later tests can still work + setattr(edtf_field_on_model, field_alias, orig_value) + + # TODO: this is not working yet + # # Remove the field from the model + # referenced_field_name = getattr(edtf_field_on_model, field_alias) + # orig_fields = TestEvent._meta.local_fields + # TestEvent._meta.local_fields = [ # type: ignore + # field + # for field in TestEvent._meta.local_fields + # if field.name != referenced_field_name + # ] + # errors = TestEvent._meta.get_field("date_edtf").check() + # self.assertEqual(len(errors), 1) + # self.assertTrue(referenced_field_name in errors[0].msg) + # # Replace the field so later tests can still work + # TestEvent._meta.local_fields = orig_fields From 1a5ebd53e0f78c17f4e037569a089a082cf6b8fb Mon Sep 17 00:00:00 2001 From: Alastair Weakley Date: Thu, 27 Jun 2024 21:35:53 +1000 Subject: [PATCH 2/2] Tests for aliases that point to non-existent fields #62 --- edtf/fields.py | 2 ++ edtf_django_tests/edtf_integration/tests.py | 28 +++++++++------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/edtf/fields.py b/edtf/fields.py index 9cf6b27..07a9744 100644 --- a/edtf/fields.py +++ b/edtf/fields.py @@ -215,6 +215,7 @@ def _check_field(self, field_alias): f"You must specify a '{field_alias}' for EDTFField", hint=None, obj=self, + id="python-edtf.EDTF01", ) ] @@ -227,6 +228,7 @@ def _check_field(self, field_alias): f"'{self.name}' refers to a non-existent '{field_alias}' field: '{field_name}'", hint=None, obj=self, + id="python-edtf.EDTF02", ) ] return [] diff --git a/edtf_django_tests/edtf_integration/tests.py b/edtf_django_tests/edtf_integration/tests.py index da5bb83..aa1bf34 100644 --- a/edtf_django_tests/edtf_integration/tests.py +++ b/edtf_django_tests/edtf_integration/tests.py @@ -140,20 +140,16 @@ def test_field_related_field_specification(self): errors = edtf_field_on_model.check() self.assertEqual(len(errors), 1) self.assertTrue(field_alias in errors[0].msg) - # Replace the field so later tests can still work - setattr(edtf_field_on_model, field_alias, orig_value) + # Should be an 'alias not specified' error + self.assertEqual(errors[0].id, "python-edtf.EDTF01") + + # Point the alias to a non-existent field + setattr(edtf_field_on_model, field_alias, "fake") + errors = edtf_field_on_model.check() + self.assertEqual(len(errors), 1) + self.assertTrue(field_alias in errors[0].msg) + # Should be a 'non-eixstent field' error + self.assertEqual(errors[0].id, "python-edtf.EDTF02") - # TODO: this is not working yet - # # Remove the field from the model - # referenced_field_name = getattr(edtf_field_on_model, field_alias) - # orig_fields = TestEvent._meta.local_fields - # TestEvent._meta.local_fields = [ # type: ignore - # field - # for field in TestEvent._meta.local_fields - # if field.name != referenced_field_name - # ] - # errors = TestEvent._meta.get_field("date_edtf").check() - # self.assertEqual(len(errors), 1) - # self.assertTrue(referenced_field_name in errors[0].msg) - # # Replace the field so later tests can still work - # TestEvent._meta.local_fields = orig_fields + # Repair the field so later tests can still work + setattr(edtf_field_on_model, field_alias, orig_value)