dapper91 / pydantic-xml

python xml for humans
https://pydantic-xml.readthedocs.io
The Unlicense
141 stars 14 forks source link

Usage of type hints by creation of model objects in source code #152

Closed seyitalitek closed 2 months ago

seyitalitek commented 6 months ago

Hi,

In pydantic as stated in this intro https://docs.pydantic.dev/latest/why/#type-hints, type hints are used not only to derive validation logic for a foreign input but also for static analyse of code which creates the models directly in source code without a de-serialization.

But I couldn't see such a possibility in this library or did I miss something?

I would like to have such a possibility as in the example from the link above:

from typing import Annotated, Dict, List, Literal, Tuple

from annotated_types import Gt

from pydantic_xml import BaseXmlModel, attr

class Fruit(BaseXmlModel):
    name: str = attr()
    color: Literal["red", "green"] = attr()
    weight: Annotated[float, Gt(0)] = attr()
    bazam: Dict[str, List[Tuple[int, bool, float]]] = attr()

print(
    Fruit(
        # name="Apple", this should be recognized as an error by type checker
        color="red",
        weight=4.2,
        bazam={"foobar": [(1, True, 0.1)]},
    )
)

Thanks for your time.

dapper91 commented 6 months ago

@seyitalitek Hi,

Yes, it is possible to instansiate a model directly without de-serialization provided that the model can be correctly serialized to xml. In your example field bazam can't be serialized because in xml attributes are strings so that they can't be of Dict type. Without bazam field it works well:

>>> from typing import Annotated, Dict, List, Literal, Tuple
>>> from annotated_types import Gt
>>> from pydantic_xml import BaseXmlModel, attr
>>>
>>> class Fruit(BaseXmlModel):
...     name: str = attr()
...     color: Literal["red", "green"] = attr()
...     weight: Annotated[float, Gt(0)] = attr()
...     # bazam: Dict[str, List[Tuple[int, bool, float]]] = attr()
...
>>>
>>> print(
...     Fruit(
...         name="Apple",
...         color="red",
...         weight=4.2,
...         # bazam={"foobar": [(1, True, 0.1)]},
...     )
... )
name='Apple' color='red' weight=4.2
seyitalitek commented 6 months ago

Thanks for the answer. Maybe bazam was not a good example, sorry for that. I have taken it copy-paste from the example in pydantic website. I have recognized that we could create in this way. My question was about to be able to have static type checks by using this initialization.

If I don't provide name field, it will be a validation error in runtime. But in pydantic version, type checker recognizes that name field is missing. I would like to be sure if i miss-configure something or it is expected behavior in this version. 👍

dapper91 commented 5 months ago

@seyitalitek Hi,

Thanks, now I understand what you mean. What type-checker you use?

I researched how mypy plugin works, turned out that it analyzes what function was used to define a field and if it wasn't pydantic.fields.Field it ignores the field.

I added mypy plugin that fixes that problem.

wozniakty commented 3 months ago

Any chance you would be interested in doing a similar thing for pylance? It's not uncommon for python devs to use vscode with pylance type checking enabled, and the same kind of problem occurs.

Pydantic correctly sees the init param options, but pydantic-xml does not. This is a big blocker to this being as convenient as the pydantic package from which it takes its name.

dapper91 commented 2 months ago

@wozniakty Hi,

I added PEP-681 support (which pylance uses for type checking) in version 2.9.1. Please, check that pylance type checker works correctly.