From 5f14ccc5c260cf8e8fd8ec8865b00d20b1f10e19 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Fri, 23 Jun 2023 19:52:26 +0500 Subject: [PATCH 1/4] code snippets reformatted. --- docs/source/pages/data-binding/elements.rst | 2 +- examples/snippets/model_mode_ordered.py | 6 +++++- examples/snippets/model_mode_strict.py | 6 +++++- examples/snippets/model_mode_unordered.py | 6 +++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/source/pages/data-binding/elements.rst b/docs/source/pages/data-binding/elements.rst index 4418bbf..dc25046 100644 --- a/docs/source/pages/data-binding/elements.rst +++ b/docs/source/pages/data-binding/elements.rst @@ -276,7 +276,7 @@ This mode is used when element order matters but unexpected (or irrelevant) elem .. code-block:: python - class Model(BaseXmlModel): + class Model(BaseXmlModel, search_mode='ordered'): field1: Optional[str] = element(tag='element1') field2: str = element(tag='element2') field3: str = element(tag='element1') diff --git a/examples/snippets/model_mode_ordered.py b/examples/snippets/model_mode_ordered.py index 3d47399..4c58788 100644 --- a/examples/snippets/model_mode_ordered.py +++ b/examples/snippets/model_mode_ordered.py @@ -2,7 +2,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='ordered'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='ordered', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] diff --git a/examples/snippets/model_mode_strict.py b/examples/snippets/model_mode_strict.py index 35dd5e2..c964416 100644 --- a/examples/snippets/model_mode_strict.py +++ b/examples/snippets/model_mode_strict.py @@ -4,7 +4,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='strict'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='strict', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] diff --git a/examples/snippets/model_mode_unordered.py b/examples/snippets/model_mode_unordered.py index e737af0..5ac23f8 100644 --- a/examples/snippets/model_mode_unordered.py +++ b/examples/snippets/model_mode_unordered.py @@ -2,7 +2,11 @@ # [model-start] -class Company(BaseXmlModel, tag='Company', search_mode='unordered'): +class Company( + BaseXmlModel, + tag='Company', + search_mode='unordered', +): founded: str = element(tag='Founded') website: str = element(tag='WebSite') # [model-end] From cf61e5ca0e35e2f06b5e165f45b3137b0b210346 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Fri, 23 Jun 2023 19:54:20 +0500 Subject: [PATCH 2/4] typos fixed. --- docs/source/pages/data-binding/elements.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/source/pages/data-binding/elements.rst b/docs/source/pages/data-binding/elements.rst index dc25046..20cf482 100644 --- a/docs/source/pages/data-binding/elements.rst +++ b/docs/source/pages/data-binding/elements.rst @@ -195,9 +195,9 @@ A model supports several element search strategies (modes). Each strategy has it Strict (default) ................ -An element to which a field will be bound is searched sequentially one by one (without skipping unknown elements). +The element to which a field will be bound is searched sequentially one by one (without skipping unknown elements). If the tag of a next element doesn't match the field tag that field is considered unbound. -This mode is used when strong document validation is required. If you parse a very large document it is the best +This mode is used when strong document validation is required. If you parse a large document it is the best choice because it works in predictable time since it doesn't require any look-ahead operations. .. grid:: 2 @@ -237,9 +237,9 @@ choice because it works in predictable time since it doesn't require any look-ah Ordered ....... -An element to which a field will be bound is searched sequentially skipping unknown elements. +The element to which a field will be bound is searched sequentially skipping unknown elements. If the tag of a next element doesn't match the field tag that element is skipped and the search continues. -This mode is used when element order matters but unexpected (or irrelevant) elements could appear in a document. +This mode is used when the elements order matters but unexpected (or irrelevant) elements could appear in a document. .. grid:: 2 :gutter: 2 @@ -297,10 +297,11 @@ This mode is used when element order matters but unexpected (or irrelevant) elem Unordered ......... -An element to which a field will be bound is searched in random order. -This mode is used when element order doesn't matter. -The time complexity of this strategy is worst case is -``O(F*E)`` where ``F`` - is the number of fields, ``E`` - the number of sub-elements. +The element to which a field will be bound is searched among all sub-elements in any order. +This mode is used when the elements order doesn't matter. +The time complexity of this strategy in worst case is +``O(F*E)`` where ``F`` - is the number of fields, ``E`` - the number of sub-elements so that it is not suitable +for large documents. .. grid:: 2 :gutter: 2 From 508040696ef3788f3f7d81db61af6a84a6569fd7 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Fri, 23 Jun 2023 19:55:00 +0500 Subject: [PATCH 3/4] docstrings fixed. --- pydantic_xml/model.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pydantic_xml/model.py b/pydantic_xml/model.py index 3512752..d76a025 100644 --- a/pydantic_xml/model.py +++ b/pydantic_xml/model.py @@ -144,7 +144,8 @@ def nsmap(self) -> Optional[NsMap]: def attr(**kwargs: Any) -> Any: """ Marks a pydantic field as an xml attribute. - Method parameters are identical to :py:class:`pydantic_xml.XmlAttributeInfo`. + + :param kwargs: see :py:class:`pydantic_xml.XmlAttributeInfo` """ return XmlAttributeInfo(**kwargs) @@ -153,7 +154,8 @@ def attr(**kwargs: Any) -> Any: def element(**kwargs: Any) -> Any: """ Marks a pydantic field as an xml element. - Method parameters are identical to :py:class:`pydantic_xml.XmlElementInfo`. + + :param kwargs: see :py:class:`pydantic_xml.XmlElementInfo` """ return XmlElementInfo(**kwargs) @@ -162,7 +164,9 @@ def element(**kwargs: Any) -> Any: def wrapped(*args: Any, **kwargs: Any) -> Any: """ Marks a pydantic field as a wrapped xml entity. - Method parameters are identical to :py:class:`pydantic_xml.XmlWrapperInfo`. + + :param args: see :py:class:`pydantic_xml.XmlWrapperInfo` + :param kwargs: see :py:class:`pydantic_xml.XmlWrapperInfo` """ return XmlWrapperInfo(*args, **kwargs) From c11b1ea3bd43c06a5976023ae58f0958d164da8d Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Fri, 23 Jun 2023 19:56:03 +0500 Subject: [PATCH 4/4] None type encoding paragraph added. --- docs/source/pages/misc.rst | 53 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/source/pages/misc.rst b/docs/source/pages/misc.rst index ded7861..0ca3899 100644 --- a/docs/source/pages/misc.rst +++ b/docs/source/pages/misc.rst @@ -1,8 +1,12 @@ .. _misc: +Encoding +~~~~~~~~ + + Custom type encoding -~~~~~~~~~~~~~~~~~~~~ +____________________ ``pydantic-xml`` uses ``pydantic`` default encoder to encode fields data during xml serialization. To alter the default behaviour ``pydantic`` provides a mechanism to `customize `_ @@ -11,7 +15,7 @@ The api is similar to the json one: .. code-block:: python - class Model: + class Model(BaseXmlModel): class Config: xml_encoders = { bytes: base64.b64encode, @@ -40,6 +44,51 @@ The following example illustrate how to encode :py:class:`bytes` typed fields as :language: xml +None type encoding +__________________ + +Since xml format doesn't support ``null`` type natively it is not obvious how to encode ``None`` fields +(ignore it, encode it as an empty string or mark it as ``xsi:nil``) the library doesn't implement +``None`` type encoding by default. + +You can define your own encoding format for the model: + +.. code-block:: python + + from typing import Optional + from pydantic_xml import BaseXmlModel, element + + + class Company(BaseXmlModel): + class Config: + xml_encoders = { + type(None): lambda o: '', # encodes None field as an empty string + } + + title: Optional[str] = element() + + + company = Company() + assert company.to_xml() == b'</Company>' + + +or drop ``None`` fields at all: + +.. code-block:: python + + from typing import Optional + from pydantic_xml import BaseXmlModel, element + + + class Company(BaseXmlModel): + title: Optional[str] = element() + + + company = Company() + assert company.to_xml(skip_empty=True) == b'<Company />' + + + Default namespace ~~~~~~~~~~~~~~~~~