Repository: tefra/xsdata
Pull request #1007 (2024-04-01 17:40:03)

Pydantic v2 related fixes
## 📒 Description

> Write a brief description of your PR.

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


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=1007) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=1007&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=1007&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=1007&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=1007&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=1007)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tefra/xsdata/pull/1007?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 [(`1a2cfea`)](https://app.codecov.io/gh/tefra/xsdata/commit/1a2cfeacfb876a95f8e976b92688eb6461406ab5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) to head [(`cedc57e`)](https://app.codecov.io/gh/tefra/xsdata/pull/1007?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     #1007   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          117       117           
  Lines         9186      9189    +3     
  Branches      2180      2181    +1     
=========================================
+ Hits          9186      9189    +3     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tefra/xsdata/pull/1007?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).

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=1007) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=1007&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=1007&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=1007&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=1007&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=1007)



Patch:
diff --git a/xsdata/codegen/mappers/dict.py b/xsdata/codegen/mappers/dict.py
index 3f5b5cf5..a62be0ba 100644
--- a/xsdata/codegen/mappers/dict.py
+++ b/xsdata/codegen/mappers/dict.py
@@ -71,4 +71,4 @@ class DictMapper(RawDocumentMapper):
             else:
                 attr_type = cls.build_attr_type(name, value)
 
-            cls.build_attr(target, name, attr_type)
+            cls.build_attr(target, name, attr_type, value=value)
diff --git a/xsdata/codegen/mappers/mixins.py b/xsdata/codegen/mappers/mixins.py
index 59c1d773..d05002e6 100644
--- a/xsdata/codegen/mappers/mixins.py
+++ b/xsdata/codegen/mappers/mixins.py
@@ -7,6 +7,8 @@ from xsdata.models.enums import DataType, QNames, Tag
 from xsdata.utils import collections
 from xsdata.utils.namespaces import split_qname
 
+_UNSET = object()
+
 
 class RawDocumentMapper:
     """Mixin class for raw json/xml documents."""
@@ -20,6 +22,7 @@ class RawDocumentMapper:
         parent_namespace: Optional[str] = None,
         tag: str = Tag.ELEMENT,
         sequence: int = 0,
+        value: Any = _UNSET,
     ):
         """Build an attr for the given class instance.
 
@@ -30,6 +33,7 @@ class RawDocumentMapper:
             parent_namespace: The parent namespace
             tag: The attr tag
             sequence: The attr sequence number
+            value: The attr sample value
         """
         namespace, name = split_qname(qname)
         namespace = cls.select_namespace(namespace, parent_namespace, tag)
@@ -43,6 +47,10 @@ class RawDocumentMapper:
 
         attr.restrictions.min_occurs = 1
         attr.restrictions.max_occurs = 1
+
+        if value is None:
+            attr.restrictions.min_occurs = 0
+
         cls.add_attribute(target, attr)
 
     @classmethod
diff --git a/xsdata/utils/text.py b/xsdata/utils/text.py
index bb8e9a0b..58cb7c66 100644
--- a/xsdata/utils/text.py
+++ b/xsdata/utils/text.py
@@ -57,6 +57,7 @@ stop_words = {
     "str",
     "try",
     "type",
+    "validate",
     "while",
     "with",
     "yield",


Test patch:
diff --git a/tests/codegen/mappers/test_dict.py b/tests/codegen/mappers/test_dict.py
index f0d5fda4..f82726c5 100644
--- a/tests/codegen/mappers/test_dict.py
+++ b/tests/codegen/mappers/test_dict.py
@@ -89,13 +89,13 @@ class DictMapperTests(FactoryTestCase):
                 AttrTypeFactory.native(DataType.ANY_SIMPLE_TYPE, tag=Tag.ELEMENT),
             ],
         )
-        restrictions = Restrictions(min_occurs=1, max_occurs=sys.maxsize)
+        restrictions = Restrictions(min_occurs=0, max_occurs=sys.maxsize)
         self.assertEqual(expected, target.attrs[0])
         self.assertEqual(restrictions, target.attrs[0].restrictions)
 
     def test_build_class_attribute_from_dict(self):
         target = ClassFactory.create()
-        data = {"sub1": 1, "sub2": "value"}
+        data = {"sub1": 1, "sub2": "value", "sub3": None}
         DictMapper.build_class_attribute(target, "a", data)
 
         expected = AttrFactory.create(
@@ -113,9 +113,14 @@ class DictMapperTests(FactoryTestCase):
             attrs=[
                 AttrFactory.native(DataType.SHORT, name="sub1"),
                 AttrFactory.native(DataType.STRING, name="sub2"),
+                AttrFactory.native(DataType.STRING, name="sub3"),
             ],
         )
 
         self.assertEqual(expected, target.attrs[0])
         self.assertEqual(expected_inner, target.inner[0])
         self.assertEqual(1, len(target.inner))
+
+        self.assertFalse(target.inner[0].attrs[0].restrictions.is_optional)
+        self.assertFalse(target.inner[0].attrs[1].restrictions.is_optional)
+        self.assertTrue(target.inner[0].attrs[2].restrictions.is_optional)