dapper91 / pydantic-xml

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

Feature request: optional parameters to pass to `parse_obj` #82

Closed bjones1 closed 1 year ago

bjones1 commented 1 year ago

For some models, I'd like to be able to store some metadata (for example, the path to the XML file) in the model. I'd like a way to specify this during model creation/validation. Something like:

from pathlib import Path
from typing import List
from pydantic_xml import BaseXmlModel, element

class Company(BaseXmlModel, tag="Company"):
    xml_path: Path
    website: List[str] = element()

path = Path("test.xml")
################### See extra xml_path argument here.
company = Company.from_xml(path.read_bytes(), xml_path=path)
print(company)
dapper91 commented 1 year ago

@bjones1 Hi

Maybe I am wrong, but it seems to me that since xml_path contains meta-information it should not be a part of the model fields. In your example xml_path is bound to the element text which is not right I suppose.

For that purposes pydantic supports private attributes:

class Company(BaseXmlModel, tag="Company"):
    _xml_path: Path = PrivateAttr()
    website: List[str] = element()

Also pydantic supports validation context which allows you to pass some meta-data to the validators.

So it seems to me that your problem could be solved without extra arguments, like this:

from pathlib import Path
from typing import List, Self
from pydantic import model_validator, PrivateAttr, ValidationInfo
from pydantic_xml import BaseXmlModel, element

class Company(BaseXmlModel, tag="Company"):
    _xml_path: Path = PrivateAttr()
    website: List[str] = element()

    @model_validator(mode='after')
    def set_metadata(cls, obj: Self, info: ValidationInfo) -> Self:
        obj._xml_path = info.context['xml_path']
        return obj

path = Path("test.xml")
company = Company.from_xml(path.read_bytes(), context=dict(xml_path=path))
print(company)
bjones1 commented 1 year ago

This is very helpful, thanks! I wasn't aware of validation context; this looks like a great way to do what I need. I'd already been storing data using private attributes. Let me play a bit with this and make sure it all works the way I expect.

bjones1 commented 1 year ago

This works great for me! Thanks. FYI, here's my implementation: https://github.com/PreTeXtBook/pretext-cli/pull/595.

I'm assuming I need pydantic-xml 2.2.2?

Thanks again!

dapper91 commented 1 year ago

I'm assuming I need pydantic-xml 2.2.2?

No, that should work prior to 2.2.2.

bjones1 commented 1 year ago

OK, thanks!