From 512f179508f9ea9f59f75bda8795d9df15ba6fe3 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 31 Aug 2024 20:58:49 -0700 Subject: [PATCH] feat(attribute): add slug validation for Python identifier compliance Implement custom validation for Attribute model's slug field to ensure it's a valid Python identifier. Add corresponding test case. --- eav/models/attribute.py | 20 ++++++++++++++++++++ tests/test_attributes.py | 18 ++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/eav/models/attribute.py b/eav/models/attribute.py index 9eefeb6..b59af6c 100644 --- a/eav/models/attribute.py +++ b/eav/models/attribute.py @@ -291,6 +291,26 @@ class Attribute(models.Model): _('You can only assign a choice group to multiple choice attributes'), ) + def clean_fields(self, exclude=None): + """Perform field-specific validation on the model's fields. + + This method extends the default field cleaning process to include + custom validation for the slug field. + + Args: + exclude (list): Fields to exclude from cleaning. + + Raises: + ValidationError: If the slug is not a valid Python identifier. + """ + super().clean_fields(exclude=exclude) + + if not self.slug.isidentifier(): + raise ValidationError({ + 'slug': _("Slug must be a valid Python identifier (no spaces, " + "special characters, or leading digits).") + }) + def get_choices(self): """ Returns a query set of :class:`EnumValue` objects for this attribute. diff --git a/tests/test_attributes.py b/tests/test_attributes.py index 1347eb2..d17a8f5 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -1,12 +1,13 @@ -import uuid import string +import uuid +import pytest +from django.conf import settings as django_settings from django.core.exceptions import ValidationError from django.test import TestCase from hypothesis import given, settings -from hypothesis.extra import django -from django.conf import settings as django_settings from hypothesis import strategies as st +from hypothesis.extra import django from hypothesis.strategies import just import eav @@ -15,7 +16,6 @@ from eav.models import Attribute, Value from eav.registry import EavConfig from test_project.models import Doctor, Encounter, Patient, RegisterTestModel - if django_settings.EAV2_PRIMARY_KEY_FIELD == "django.db.models.UUIDField": auto_field_strategy = st.builds(uuid.uuid4, version=4, max_length=32) elif django_settings.EAV2_PRIMARY_KEY_FIELD == "django.db.models.CharField": @@ -162,3 +162,13 @@ class TestAttributeModel(django.TestCase): ) assert isinstance(instance, Attribute) + + +@pytest.mark.django_db +def test_attribute_create_with_invalid_slug(): + with pytest.raises(ValidationError): + Attribute.objects.create( + name="Test Attribute", + slug="123-invalid", + datatype=Attribute.TYPE_TEXT + )