Skip to content

Commit

Permalink
Merge pull request #864 from tefra/fix-862
Browse files Browse the repository at this point in the history
Fix json binding with union fields
  • Loading branch information
tefra authored Nov 14, 2023
2 parents 075e9da + f4af825 commit 2668e1e
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 19 deletions.
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ exclude: tests/fixtures

repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.10.1
rev: v3.15.0
hooks:
- id: pyupgrade
args: [ --py38-plus ]
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.10.0
rev: v3.12.0
hooks:
- id: reorder-python-imports
- repo: https://github.com/ambv/black
rev: 23.7.0
rev: 23.11.0
hooks:
- id: black
- repo: https://github.com/PyCQA/autoflake
rev: v2.2.0
rev: v2.2.1
hooks:
- id: autoflake
- repo: https://github.com/PyCQA/flake8
Expand All @@ -30,7 +30,7 @@ repos:
args: [ "--suppress-none-returning" ]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand All @@ -41,7 +41,7 @@ repos:
- id: docformatter
args: [ "--in-place", "--pre-summary-newline" ]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
rev: v1.7.0
hooks:
- id: mypy
files: ^(xsdata/)
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/compound/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Root:
class Meta:
name = "root"

alpha_or_bravo: List[Union[Bravo, Alpha]] = field(
alpha_or_bravo: List[Union[Alpha, Bravo]] = field(
default_factory=list,
metadata={
"type": "Elements",
Expand Down
12 changes: 12 additions & 0 deletions tests/formats/dataclass/parsers/test_json.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import json
from dataclasses import asdict
from dataclasses import make_dataclass
from typing import List
from typing import Optional
from typing import Union
from xml.etree.ElementTree import QName

from tests import fixtures_dir
Expand Down Expand Up @@ -370,6 +373,15 @@ def test_bind_any_type_with_derived_dataclass(self):

self.assertEqual("Unable to locate xsi:type `notexists`", str(cm.exception))

def test_bind_text_with_unions(self):
Fixture = make_dataclass("Fixture", [("x", List[Union[int, float, str, bool]])])
values = ["foo", 12.2, "12.2", 12, "12", True, "false"]
data = json.dumps({"x": values})

result = self.parser.from_string(data, Fixture)
expected = ["foo", 12.2, 12.2, 12, 12, True, False]
self.assertEqual({"x": expected}, asdict(result))

def test_find_var(self):
meta = self.parser.context.build(TypeB)
xml_vars = meta.get_all_vars()
Expand Down
3 changes: 3 additions & 0 deletions xsdata/formats/dataclass/parsers/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from xsdata.exceptions import ParserError
from xsdata.formats.bindings import AbstractParser
from xsdata.formats.bindings import T
from xsdata.formats.converter import converter
from xsdata.formats.dataclass.context import XmlContext
from xsdata.formats.dataclass.models.elements import XmlMeta
from xsdata.formats.dataclass.models.elements import XmlVar
Expand Down Expand Up @@ -241,6 +242,8 @@ def bind_text(self, meta: XmlMeta, var: XmlVar, value: Any) -> Any:
# field can support any object return the value as it is
return value

value = converter.serialize(value)

# Convert value according to the field types
return ParserUtils.parse_value(
value=value,
Expand Down
26 changes: 14 additions & 12 deletions xsdata/formats/dataclass/serializers/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def end_tag(self, qname: str):
:param qname: Tag qualified name
"""
self.flush_start(True)
self.handler.endElementNS(split_qname(qname), None)
self.handler.endElementNS(split_qname(qname), "")

if self.tail:
self.handler.characters(self.tail)
Expand All @@ -239,20 +239,22 @@ def flush_start(self, is_nil: bool = True):
:param is_nil: If true add ``xsi:nil="true"`` to the element
attributes
"""
if self.pending_tag:
if not is_nil:
self.attrs.pop(XSI_NIL, None)
if not self.pending_tag:
return

for name in self.attrs.keys():
self.add_namespace(name[0])
if not is_nil:
self.attrs.pop(XSI_NIL, None)

self.reset_default_namespace()
self.start_namespaces()
for name in self.attrs.keys():
self.add_namespace(name[0])

self.handler.startElementNS(self.pending_tag, None, self.attrs)
self.attrs = {}
self.in_tail = False
self.pending_tag = None
self.reset_default_namespace()
self.start_namespaces()

self.handler.startElementNS(self.pending_tag, "", self.attrs) # type: ignore
self.attrs = {}
self.in_tail = False
self.pending_tag = None

def start_namespaces(self):
"""
Expand Down

0 comments on commit 2668e1e

Please sign in to comment.