Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider adding a class_name_generator option #1115

Open
loopj opened this issue Jan 28, 2025 · 1 comment
Open

Consider adding a class_name_generator option #1115

loopj opened this issue Jan 28, 2025 · 1 comment

Comments

@loopj
Copy link

loopj commented Jan 28, 2025

Currently, we have support for configuring an element_name_generator and attribute_name_generator function in models metadata or in XmlContext.

This is fantastic for reducing boilerplate when generating element names based on field names of a class.

In the following examples, I'm using PEP8 style field names (snake_case) and PEP8 style class names (PascalCase), and generating XML which uses PascalCase for element names.

xml_context = XmlContext(element_name_generator=pascal_case)
serializer = XmlSerializer(context=xml_context)

@dataclass
class Something:
    my_field: int

serializer.render(Something(my_field=123))

This generates the expected XML:

<Something>
    <MyField>123</MyField>
</Something>

Since element_name_generator is also used for generating the local_name of a class when none is explicitly provided, that causes some interesting behavior:

xml_context = XmlContext(element_name_generator=pascal_case)
serializer = XmlSerializer(context=xml_context)

@dataclass
class IPAddress:
    val: str

serializer.render(IPAddress(val="192.168.1.1"))

In this case, the (already pascal case) class name is being run through the pascal_case element_name_generator, which is clobbering the case of the class from IPAddress to Ipaddress:

<Ipaddress>
    <Val>192.168.1.1</Val>
</Ipaddress>

I'm aware that this can be solved by specifying explicit names in either the field metadata or the class metadata, but I think it would be nice to have a way to specify a class_name_generator in the XmlContext to avoid this issue.

For example:

context = XmlContext(
    element_name_generator=pascal_case,
    class_name_generator=return_input,
)

serializer = XmlSerializer(context=context)

Under the hood we could have class_name_generator default to element_name_generator if not explicitly provided, to maintain the current behavior.

Let me know what you think, and I can try to whip up a PR if you're interested in supporting this.

@loopj
Copy link
Author

loopj commented Jan 28, 2025

For reference, my current workaround is to define the following:

def preserving_pascal_case(name: str) -> str:
    """Convert a field/class name to PascalCase, preserving existing PascalCase names."""
    if "_" in name or name.islower():
        return pascal_case(name)
    else:
        return name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant