Skip to content

Commit

Permalink
feat: Make rename duplicate attributes reusable
Browse files Browse the repository at this point in the history
  • Loading branch information
tefra committed Mar 21, 2024
1 parent 7490c77 commit beac0ab
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 54 deletions.
49 changes: 9 additions & 40 deletions tests/codegen/handlers/test_rename_duplicate_attributes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from unittest import mock

from xsdata.codegen.handlers import RenameDuplicateAttributes
from xsdata.models.enums import Tag
from xsdata.utils.testing import AttrFactory, ClassFactory, FactoryTestCase
from xsdata.codegen.utils import ClassUtils
from xsdata.utils.testing import ClassFactory, FactoryTestCase


class RenameDuplicateAttributesTests(FactoryTestCase):
Expand All @@ -9,42 +11,9 @@ def setUp(self):

self.processor = RenameDuplicateAttributes()

def test_process(self):
attrs = [
AttrFactory.create(name="a", tag=Tag.ELEMENT),
AttrFactory.create(name="a", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="b", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="c", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="c", tag=Tag.ELEMENT),
AttrFactory.create(name="d", tag=Tag.ELEMENT),
AttrFactory.create(name="d", tag=Tag.ELEMENT),
AttrFactory.create(name="e", tag=Tag.ELEMENT, namespace="b"),
AttrFactory.create(name="e", tag=Tag.ELEMENT),
AttrFactory.create(name="f", tag=Tag.ELEMENT),
AttrFactory.create(name="f", tag=Tag.ELEMENT, namespace="a"),
AttrFactory.create(name="gA", tag=Tag.ENUMERATION),
AttrFactory.create(name="g[A]", tag=Tag.ENUMERATION),
AttrFactory.create(name="g_a", tag=Tag.ENUMERATION),
AttrFactory.create(name="g_a_1", tag=Tag.ENUMERATION),
]
target = ClassFactory.create(attrs=attrs)

@mock.patch.object(ClassUtils, "rename_duplicate_attributes")
def test_process(self, mock_rename_duplicate_attributes):
target = ClassFactory.create()
self.processor.process(target)
expected = [
"a",
"a_Attribute",
"b",
"c_Attribute",
"c",
"d_Element",
"d",
"b_e",
"e",
"f",
"a_f",
"gA",
"g[A]_2",
"g_a_3",
"g_a_1",
]
self.assertEqual(expected, [x.name for x in attrs])

mock_rename_duplicate_attributes.assert_called_once_with(target)
40 changes: 40 additions & 0 deletions tests/codegen/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,46 @@ def test_merge_attributes(self):
self.assertEqual(4, c.restrictions.max_occurs)
self.assertEqual(1, c.restrictions.sequence)

def test_rename_duplicate_attributes(self):
attrs = [
AttrFactory.create(name="a", tag=Tag.ELEMENT),
AttrFactory.create(name="a", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="b", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="c", tag=Tag.ATTRIBUTE),
AttrFactory.create(name="c", tag=Tag.ELEMENT),
AttrFactory.create(name="d", tag=Tag.ELEMENT),
AttrFactory.create(name="d", tag=Tag.ELEMENT),
AttrFactory.create(name="e", tag=Tag.ELEMENT, namespace="b"),
AttrFactory.create(name="e", tag=Tag.ELEMENT),
AttrFactory.create(name="f", tag=Tag.ELEMENT),
AttrFactory.create(name="f", tag=Tag.ELEMENT, namespace="a"),
AttrFactory.create(name="gA", tag=Tag.ENUMERATION),
AttrFactory.create(name="g[A]", tag=Tag.ENUMERATION),
AttrFactory.create(name="g_a", tag=Tag.ENUMERATION),
AttrFactory.create(name="g_a_1", tag=Tag.ENUMERATION),
]
target = ClassFactory.create(attrs=attrs)

ClassUtils.rename_duplicate_attributes(target)
expected = [
"a",
"a_Attribute",
"b",
"c_Attribute",
"c",
"d_Element",
"d",
"b_e",
"e",
"f",
"a_f",
"gA",
"g[A]_2",
"g_a_3",
"g_a_1",
]
self.assertEqual(expected, [x.name for x in attrs])

def test_rename_attribute_by_preference(self):
one = AttrFactory.create(name="a", tag=Tag.ELEMENT)
two = AttrFactory.create(name="a", tag=Tag.ATTRIBUTE)
Expand Down
16 changes: 2 additions & 14 deletions xsdata/codegen/handlers/rename_duplicate_attributes.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from xsdata.codegen.mixins import HandlerInterface
from xsdata.codegen.models import Attr, Class
from xsdata.codegen.models import Class
from xsdata.codegen.utils import ClassUtils
from xsdata.utils.collections import group_by
from xsdata.utils.constants import DEFAULT_ATTR_NAME


class RenameDuplicateAttributes(HandlerInterface):
Expand All @@ -16,14 +14,4 @@ def process(self, target: Class):
Args:
target: The target class instance
"""
grouped = group_by(target.attrs, key=self._attr_unique_slug)
for items in grouped.values():
total = len(items)
if total == 2 and not items[0].is_enumeration:
ClassUtils.rename_attribute_by_preference(*items)
elif total > 1:
ClassUtils.rename_attributes_by_index(target.attrs, items)

@staticmethod
def _attr_unique_slug(attr: Attr) -> str:
return attr.slug or DEFAULT_ATTR_NAME
ClassUtils.rename_duplicate_attributes(target)
11 changes: 11 additions & 0 deletions xsdata/codegen/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,17 @@ def merge_attributes(cls, target: Attr, source: Attr):
if source.restrictions.sequence is not None:
target.restrictions.sequence = source.restrictions.sequence

@classmethod
def rename_duplicate_attributes(cls, target: Class):
"""Find and rename attributes with the same slug."""
grouped = collections.group_by(target.attrs, key=get_slug)
for items in grouped.values():
total = len(items)
if total == 2 and not items[0].is_enumeration:
cls.rename_attribute_by_preference(*items)
elif total > 1:
cls.rename_attributes_by_index(target.attrs, items)

@classmethod
def rename_attribute_by_preference(cls, a: Attr, b: Attr):
"""Decide and rename one of the two given attributes.
Expand Down

0 comments on commit beac0ab

Please sign in to comment.