pydantic-xml icon indicating copy to clipboard operation
pydantic-xml copied to clipboard

alias and AliasChoices not working on element

Open giftig opened this issue 7 months ago • 1 comments

Hi, I've been following the documentation and noticed that aliases are specifically said to be supported, but I'm not able to get either alias or AliasChoices working with pydantic_xml. Here's a simple example of a failing test:

import pytest

from pydantic import AliasChoices, ConfigDict, field_validator
from pydantic_xml import BaseXmlModel, element, wrapped


class Company(BaseXmlModel, tag="company"):
    model_config = ConfigDict(
        validate_by_name=True,
        validate_by_alias=True,
    )
    name: str = element("name", alias="nm", validation_alias=AliasChoices("name", "nm", "n"))


DOC_NAME = """
<company>
  <name>My company</name>
</company>
"""

DOC_NM = """
<company>
  <nm>My company</nm>
</company>
"""

DOC_N = """
<company>
  <n>My company</n>
</company>
"""

@pytest.mark.parametrize("doc", [DOC_NAME, DOC_NM, DOC_N])
def test_alias_choices(doc: str) -> None:
    expected = Company.model_construct(name="My company")
    actual = Company.from_xml(doc)

    assert actual == expected

The tests for both nm and n fail, despite the former being specified as both an alias and in alias choices:

E           pydantic_core._pydantic_core.ValidationError: 1 validation error for Company
E           name
E             [line -1]: Field required [type=missing, input_value={}, input_type=dict]

.venv/lib/python3.12/site-packages/pydantic_xml/serializers/factories/model.py:225: ValidationError
=================================================================================== short test summary info ===================================================================================
FAILED tests/parsing/test_pydantic_bug.py::test_alias_choices[\n<company>\n  <nm>My company</nm>\n</company>\n] - pydantic_core._pydantic_core.ValidationError: 1 validation error for Company
FAILED tests/parsing/test_pydantic_bug.py::test_alias_choices[\n<company>\n  <n>My company</n>\n</company>\n] - pydantic_core._pydantic_core.ValidationError: 1 validation error for Company

I'm trying to solve a use case where the content of an element always fits my model, but the actual name of that element has a version number in it so I have 10+ choices for what the tag might be named. Since I can't get AliasChoices working I might have to work around it with either a very messy Union type or several individual optional fields and a property to select the one that's defined, but neither of those options are ideal.

Any ideas how to make this work?

giftig avatar May 21 '25 08:05 giftig

In the end for my usecase I used a union type; it helps that analysing my input data some more, I only actually care about 3 of those 10+ different tag names and they're also subtly different schema-wise, albeit 90% the same. So I used a common superclass and created versioned subclasses to match the ones I care about. That seems like a reasonable solution for my problem, without having to get into aliases.

I've definitely seen weird data choices like encoding information into XML tag names in the past though, so it would definitely be useful to have AliasChoices working to allow multiple tag names, and/or possibly something like the ability to take the first (or nth) subelement and not care what the tag name is.

giftig avatar May 22 '25 17:05 giftig