Skip to content

Commit

Permalink
feat: Use unicodedata.name on non-alphanumeric attr names (#993)
Browse files Browse the repository at this point in the history
  • Loading branch information
tefra authored Mar 23, 2024
1 parent 6820aa1 commit e652e08
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repos:
- id: end-of-file-fixer
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.3
rev: v0.3.4
hooks:
- id: ruff
args: [ --fix, --show-fixes]
Expand Down
3 changes: 2 additions & 1 deletion tests/codegen/handlers/test_create_compound_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ def test_build_attr_choice(self):

actual = self.processor.build_attr_choice(attr)

self.assertEqual(attr.local_name, actual.name)
self.assertEqual(attr.name, actual.name)
self.assertEqual(attr.local_name, actual.local_name)
self.assertEqual(attr.namespace, actual.namespace)
self.assertIsNone(actual.default)
self.assertEqual(attr.tag, actual.tag)
Expand Down
9 changes: 9 additions & 0 deletions tests/codegen/models/test_attr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@


class AttrTests(FactoryTestCase):
def test__post__init__(self):
attr = AttrFactory.create(name="$")
self.assertEqual("$", attr.local_name)
self.assertEqual("DOLLAR SIGN", attr.name)

attr = AttrFactory.create(local_name="$", name="dollar")
self.assertEqual("$", attr.local_name)
self.assertEqual("dollar", attr.name)

def test__eq__(self):
attr = AttrFactory.element()
clone = attr.clone()
Expand Down
4 changes: 0 additions & 4 deletions tests/codegen/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,6 @@ def test_rename_duplicate_attributes(self):
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),
AttrFactory.create(name="%", tag=Tag.ENUMERATION),
AttrFactory.create(name="$", tag=Tag.ENUMERATION),
]
target = ClassFactory.create(attrs=attrs)

Expand All @@ -346,8 +344,6 @@ def test_rename_duplicate_attributes(self):
"g[A]_2",
"g_a_3",
"g_a_1",
"%",
"$_1",
]
self.assertEqual(expected, [x.name for x in attrs])

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/annotations/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
class unit(Enum):
M = "m"
KG = "kg"
VALUE = "%"
PERCENT_SIGN = "%"
NA = "NA"
5 changes: 3 additions & 2 deletions tests/formats/dataclass/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ def test_field_choices(self):
attr = AttrFactory.create(
choices=[
AttrFactory.element(
name="$",
namespace="foo",
types=[type_float],
restrictions=Restrictions(max_exclusive="10"),
Expand All @@ -530,8 +531,8 @@ def test_field_choices(self):

actual = self.filters.field_choices(attr, "foo", ["a", "b"])
expected = (
{"name": "attr_B", "type": "Type[float]", "max_exclusive": 10.0},
{"name": "attr_C", "namespace": "bar", "type": "Type[str]"},
{"name": "$", "type": "Type[float]", "max_exclusive": 10.0},
{"name": "attr_B", "namespace": "bar", "type": "Type[str]"},
{
"namespace": "##other",
"wildcard": True,
Expand Down
3 changes: 2 additions & 1 deletion xsdata/codegen/handlers/create_compound_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ def build_attr_choice(cls, attr: Attr) -> Attr:
restrictions.sequence = None

return Attr(
name=attr.local_name,
name=attr.name,
local_name=attr.local_name,
namespace=attr.namespace,
types=[x.clone() for x in attr.types],
tag=attr.tag,
Expand Down
12 changes: 9 additions & 3 deletions xsdata/codegen/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import copy
import operator
import sys
import unicodedata
from dataclasses import asdict, dataclass, field, fields, replace
from enum import IntEnum
from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, TypeVar
Expand Down Expand Up @@ -271,6 +272,7 @@ class Attr(CodegenModel):
tag: The xml tag that produced this attr
name: The final attr name
local_name: The original attr name
wrapper: The wrapper element name
index: The index position of this attr in the class
default: The default value
fixed: Specifies if the default value is fixed
Expand All @@ -286,7 +288,7 @@ class Attr(CodegenModel):

tag: str
name: str = field(compare=False)
local_name: str = field(init=False)
local_name: str = field(default="")
wrapper: Optional[str] = field(default=None)
index: int = field(compare=False, default_factory=int)
default: Optional[str] = field(default=None, compare=False)
Expand All @@ -301,8 +303,12 @@ class Attr(CodegenModel):
substitution: Optional[str] = field(default=None, compare=False)

def __post_init__(self):
"""Set the original attr name on init."""
self.local_name = self.name
"""Post init processing."""
if not self.local_name:
self.local_name = self.name

if text.alnum(self.name) == "":
self.name = "_".join(unicodedata.name(char) for char in self.name)

@property
def key(self) -> str:
Expand Down
7 changes: 5 additions & 2 deletions xsdata/formats/dataclass/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,10 @@ def field_metadata(
return self.filter_metadata(metadata)

def field_choices(
self, attr: Attr, parent_namespace: Optional[str], parents: List[str]
self,
attr: Attr,
parent_namespace: Optional[str],
parents: List[str],
) -> Optional[Tuple]:
"""Return a tuple of field metadata if the attr has choices."""
if not attr.choices:
Expand All @@ -471,7 +474,7 @@ def field_choices(
)

metadata = {
"name": choice.name,
"name": choice.local_name,
"wildcard": choice.is_wildcard,
"type": self.choice_type(choice, parents),
"namespace": namespace,
Expand Down

0 comments on commit e652e08

Please sign in to comment.