Repository: tefra/xsdata
Pull request #1035 (2024-05-09 15:57:07)

fix: Derived element json serialization
## 📒 Description

This broke with the new more strict typing analyze process, let's add it back

Resolves #xxxx

## 🔗 What I've Done

> Write a description of the steps taken to resolve the issue

## 💬 Comments

> A place to write any comments to the reviewer.

## 🛫 Checklist

- [ ] Updated docs
- [ ] Added unit-tests
- [ ] [Sample tests](https://github.com/tefra/xsdata-samples) pass
- [ ] [W3C tests](https://github.com/tefra/xsdata-w3c-tests) pass


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tefra/xsdata/pull/1035?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`874a6d2`)](https://app.codecov.io/gh/tefra/xsdata/commit/874a6d2940db8c54a127b60858f3307c0d7a761a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) to head [(`1254135`)](https://app.codecov.io/gh/tefra/xsdata/pull/1035?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main     #1035   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          115       115           
  Lines         9265      9267    +2     
  Branches      2190      2191    +1     
=========================================
+ Hits          9265      9267    +2     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tefra/xsdata/pull/1035?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).


Patch:
diff --git a/xsdata/formats/dataclass/models/generics.py b/xsdata/formats/dataclass/models/generics.py
index a4092660..af1f7b4f 100644
--- a/xsdata/formats/dataclass/models/generics.py
+++ b/xsdata/formats/dataclass/models/generics.py
@@ -33,7 +33,7 @@ class AnyElement:
 class DerivedElement(Generic[T]):
     """Generic model wrapper for type substituted elements.
 
-    Example: eg. <b xsi:type="a">...</b>
+    Example: e.g. <b xsi:type="a">...</b>
 
     Args:
         qname: The element's qualified name
diff --git a/xsdata/formats/dataclass/typing.py b/xsdata/formats/dataclass/typing.py
index 542aaf13..b8b54fea 100644
--- a/xsdata/formats/dataclass/typing.py
+++ b/xsdata/formats/dataclass/typing.py
@@ -6,6 +6,7 @@ from typing import (
     Optional,
     Tuple,
     Type,
+    TypeVar,
     Union,
 )
 
@@ -151,6 +152,11 @@ def evaluate_attributes(annotation: Any, **_: Any) -> Result:
 
 def evaluate_element(annotation: Any, tokens: bool = False) -> Result:
     """Validate annotations for a xml element."""
+
+    # Only the derived element value field is allowed a typevar
+    if isinstance(annotation, TypeVar) and annotation.__bound__ is object:
+        annotation = object
+
     types = (annotation,)
     origin = get_origin(annotation)
     args = get_args(annotation)


Test patch:
diff --git a/tests/formats/dataclass/serializers/test_dict.py b/tests/formats/dataclass/serializers/test_dict.py
index d8767406..8b177bbf 100644
--- a/tests/formats/dataclass/serializers/test_dict.py
+++ b/tests/formats/dataclass/serializers/test_dict.py
@@ -3,6 +3,7 @@ from unittest.case import TestCase
 from tests.fixtures.books import BookForm, Books
 from tests.fixtures.datatypes import Telephone
 from tests.fixtures.wrapper import Wrapper
+from xsdata.formats.dataclass.models.generics import AnyElement, DerivedElement
 from xsdata.formats.dataclass.serializers import DictEncoder, DictFactory
 from xsdata.models.datatype import XmlDate
 from xsdata.models.xsd import Attribute
@@ -107,3 +108,23 @@ class DictEncoderTests(TestCase):
         expected = expected[:-1]
         actual = [name for name, value in self.encoder.next_value(book)]
         self.assertEqual(expected, actual)
+
+    def test_generics(self):
+        self.obj = AnyElement(
+            children=[
+                AnyElement(qname="foo", text="bar"),
+                DerivedElement(qname="bar", value="1"),
+                DerivedElement(qname="bar", value=2),
+            ]
+        )
+        result = self.encoder.encode(self.obj)
+        expected = {
+            "attributes": {},
+            "children": [
+                {"attributes": {}, "children": [], "qname": "foo", "text": "bar"},
+                {"qname": "bar", "value": "1"},
+                {"qname": "bar", "value": 2},
+            ],
+        }
+
+        self.assertEqual(expected, result)