diff --git a/eav/logic/slug.py b/eav/logic/slug.py index 89f0410..ffe7425 100644 --- a/eav/logic/slug.py +++ b/eav/logic/slug.py @@ -8,6 +8,7 @@ from django.utils.text import slugify SLUGFIELD_MAX_LENGTH: Final = 50 + def non_identifier_chars() -> dict[str, str]: """Generate a mapping of non-identifier characters to their Unicode representations. @@ -20,12 +21,12 @@ def non_identifier_chars() -> dict[str, str]: # Filter out characters that are valid in Python identifiers special_chars = [ - char for char in all_chars - if not char.isalnum() and char not in ["_", " "] + char for char in all_chars if not char.isalnum() and char not in ["_", " "] ] return {char: f"u{ord(char):04x}" for char in special_chars} + def generate_slug(value: str) -> str: """Generate a valid slug based on the given value. diff --git a/eav/models/attribute.py b/eav/models/attribute.py index b59af6c..1906b5c 100644 --- a/eav/models/attribute.py +++ b/eav/models/attribute.py @@ -306,10 +306,14 @@ class Attribute(models.Model): 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).") - }) + raise ValidationError( + { + 'slug': _( + "Slug must be a valid Python identifier (no spaces, " + "special characters, or leading digits)." + ) + } + ) def get_choices(self): """ diff --git a/tests/test_attributes.py b/tests/test_attributes.py index a14b3c6..2044256 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -136,7 +136,7 @@ class TestAttributeModel(django.TestCase): id=auto_field_strategy, datatype=just(Attribute.TYPE_TEXT), enum_group=just(None), - slug=just(None), # Let Attribute.save() handle + slug=just(None), # Let Attribute.save() handle ), ) @settings(deadline=None) @@ -169,7 +169,5 @@ class TestAttributeModel(django.TestCase): def test_attribute_create_with_invalid_slug(): with pytest.raises(ValidationError): Attribute.objects.create( - name="Test Attribute", - slug="123-invalid", - datatype=Attribute.TYPE_TEXT + name="Test Attribute", slug="123-invalid", datatype=Attribute.TYPE_TEXT ) diff --git a/tests/test_logic.py b/tests/test_logic.py index db26567..7ed06e7 100644 --- a/tests/test_logic.py +++ b/tests/test_logic.py @@ -32,28 +32,33 @@ def test_generate_slug_uniqueness() -> None: generated_slugs: dict[str, str] = {} for input_str in inputs: slug = generate_slug(input_str) - assert slug not in generated_slugs.values(), \ - f"Duplicate slug '{slug}' generated for input '{input_str}'" + assert ( + slug not in generated_slugs.values() + ), f"Duplicate slug '{slug}' generated for input '{input_str}'" generated_slugs[input_str] = slug - assert len(generated_slugs) == len(inputs), \ - "Number of unique slugs doesn't match number of inputs" + assert len(generated_slugs) == len( + inputs + ), "Number of unique slugs doesn't match number of inputs" -@pytest.mark.parametrize("input_str", [ - "01 age", - "? age", - "age 😊", - "class", - "def function", - "2nd place", - "@username", - "user-name", - "first.last", - "snake_case", - "CamelCase", - " " # Empty -]) +@pytest.mark.parametrize( + "input_str", + [ + "01 age", + "? age", + "age 😊", + "class", + "def function", + "2nd place", + "@username", + "user-name", + "first.last", + "snake_case", + "CamelCase", + " ", # Empty + ], +) def test_generate_slug_valid_identifier(input_str: str) -> None: """Test that generate_slug() produces valid Python identifiers.