Repository: tefra/xsdata

Issue:
Q: Optional for attributes in generated classes
This xml
```
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <el is_selected="true">
    </el>
  </soap:Body>
</soap:Envelope>
```
Produces this class
```

@attr.s
class El:
    class Meta:
        name = "el"
        namespace = ""

    is_selected: Optional[bool] = attr.ib(
        default=None,
        metadata={
            "type": "Attribute",
        }
    )
    value: str = attr.ib(
        default=""
    )

```

Can we achieve somehow that is_selected is not marked Optional?

It seems that 
https://xsdata.readthedocs.io/en/latest/faq/why-non-nullable-fields-are-marked-as-optional.html
mentions this problem, but changing the backend to attrs and uusing kw_only doesn't change the annotation

Discussion:
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=756)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=756&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=756&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=756&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=756&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=756) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=756&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=756&metric=new_duplicated_lines_density&view=list)


codecov[bot]: # [Codecov](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) Report
Base: **100.00**% // Head: **99.98**% // Decreases project coverage by **`-0.02%`** :warning:
> Coverage data is based on head [(`f7fff66`)](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) compared to base [(`7497f0a`)](https://codecov.io/gh/tefra/xsdata/commit/7497f0a9948c089895d207f8dcbb7511e8754380?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).
> Patch coverage: 100.00% of modified lines in pull request are covered.

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


```diff
@@             Coverage Diff             @@
##            master     #756      +/-   ##
===========================================
- Coverage   100.00%   99.98%   -0.02%     
===========================================
  Files          101      101              
  Lines         8839     8855      +16     
  Branches      1958     1964       +6     
===========================================
+ Hits          8839     8854      +15     
- Partials         0        1       +1     
```


| [Impacted Files](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) | Coverage Δ | |
|---|---|---|
| [xsdata/codegen/mappers/element.py](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vbWFwcGVycy9lbGVtZW50LnB5) | `100.00% <100.00%> (ø)` | |
| [xsdata/codegen/utils.py](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2NvZGVnZW4vdXRpbHMucHk=) | `100.00% <100.00%> (ø)` | |
| [xsdata/formats/dataclass/filters.py](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou#diff-eHNkYXRhL2Zvcm1hdHMvZGF0YWNsYXNzL2ZpbHRlcnMucHk=) | `99.72% <0.00%> (-0.28%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/tefra/xsdata/pull/756?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](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/codegen/mappers/element.py b/xsdata/codegen/mappers/element.py
index f631e4b0..41cae90a 100644
--- a/xsdata/codegen/mappers/element.py
+++ b/xsdata/codegen/mappers/element.py
@@ -137,7 +137,7 @@ class ElementMapper:
         attr = Attr(index=index, name=name, tag=tag, namespace=namespace)
         attr.types.append(attr_type)
         attr.restrictions.sequence = sequence
-        attr.restrictions.min_occurs = 0
+        attr.restrictions.min_occurs = 1
         attr.restrictions.max_occurs = 1
         cls.add_attribute(target, attr)
 
diff --git a/xsdata/codegen/utils.py b/xsdata/codegen/utils.py
index 52910117..db897e82 100644
--- a/xsdata/codegen/utils.py
+++ b/xsdata/codegen/utils.py
@@ -198,29 +198,48 @@ class ClassUtils:
 
     @classmethod
     def reduce_attributes(cls, classes: List[Class]) -> List[Attr]:
+        result = []
+        for attr in cls.sorted_attrs(classes):
+            added = False
+            optional = False
+            for obj in classes:
+                pos = collections.find(obj.attrs, attr)
+                if pos == -1:
+                    optional = True
+                elif not added:
+                    added = True
+                    result.append(obj.attrs.pop(pos))
+                else:
+                    cls.merge_attributes(result[-1], obj.attrs.pop(pos))
+
+            if optional:
+                result[-1].restrictions.min_occurs = 0
+
+        return result
+
+    @classmethod
+    def sorted_attrs(cls, classes: List[Class]) -> List[Attr]:
         attrs: List[Attr] = []
         classes.sort(key=lambda x: len(x.attrs), reverse=True)
 
         for obj in classes:
             i = 0
-            while obj.attrs:
-                pos = collections.find(attrs, obj.attrs[i])
+            obj_attrs = obj.attrs.copy()
+
+            while obj_attrs:
+                pos = collections.find(attrs, obj_attrs[i])
                 i += 1
 
                 if pos > -1:
-                    insert = obj.attrs[:i]
-                    del obj.attrs[:i]
-
-                    merge = insert.pop()
-                    cls.merge_attributes(attrs[pos], merge)
+                    insert = obj_attrs[: i - 1]
+                    del obj_attrs[:i]
                     while insert:
                         attrs.insert(pos, insert.pop())
 
                     i = 0
-                else:
-                    if i == len(obj.attrs):
-                        attrs.extend(obj.attrs)
-                        obj.attrs.clear()
+                elif i == len(obj_attrs):
+                    attrs.extend(obj_attrs)
+                    obj_attrs.clear()
 
         return attrs
 


Test patch:
diff --git a/tests/codegen/mappers/test_dict.py b/tests/codegen/mappers/test_dict.py
index 87ad1647..5108722e 100644
--- a/tests/codegen/mappers/test_dict.py
+++ b/tests/codegen/mappers/test_dict.py
@@ -71,7 +71,7 @@ class DictMapperTests(FactoryTestCase):
                 AttrTypeFactory.native(DataType.FLOAT, tag=Tag.ELEMENT),
             ],
         )
-        restrictions = Restrictions(min_occurs=0, max_occurs=sys.maxsize)
+        restrictions = Restrictions(min_occurs=1, max_occurs=sys.maxsize)
         self.assertEqual(expected, target.attrs[0])
         self.assertEqual(restrictions, target.attrs[0].restrictions)
 
@@ -88,7 +88,7 @@ class DictMapperTests(FactoryTestCase):
                 AttrTypeFactory.native(DataType.ANY_SIMPLE_TYPE, tag=Tag.ELEMENT),
             ],
         )
-        restrictions = Restrictions(min_occurs=0, max_occurs=sys.maxsize)
+        restrictions = Restrictions(min_occurs=1, max_occurs=sys.maxsize)
         self.assertEqual(expected, target.attrs[0])
         self.assertEqual(restrictions, target.attrs[0].restrictions)
 
diff --git a/tests/codegen/mappers/test_element.py b/tests/codegen/mappers/test_element.py
index 42bf8722..7188cc1f 100644
--- a/tests/codegen/mappers/test_element.py
+++ b/tests/codegen/mappers/test_element.py
@@ -72,6 +72,9 @@ class ElementMapperTests(FactoryTestCase):
             ],
         )
         self.assertEqual(expected, actual)
+        for attr in actual.attrs:
+            self.assertEqual(1, attr.restrictions.min_occurs)
+            self.assertEqual(1, attr.restrictions.max_occurs)
 
     def test_build_class_complex_type(self):
         element = AnyElement(
diff --git a/tests/codegen/test_utils.py b/tests/codegen/test_utils.py
index 8d5dcdd1..822998f8 100644
--- a/tests/codegen/test_utils.py
+++ b/tests/codegen/test_utils.py
@@ -277,23 +277,23 @@ class ClassUtilsTests(FactoryTestCase):
         self.assertEqual(["attr_E", "attr_F"], [x.name for x in result[1].attrs])
 
     def test_reduce_attributes(self):
-        attrs = AttrFactory.list(5, prefix="")
-
-        class_a = ClassFactory.create()
-        class_a.attrs = [x.clone() for x in attrs[:2]]
-
-        class_b = ClassFactory.create()
-        class_b.attrs = [x.clone() for x in attrs[2:4]]
-
-        class_c = ClassFactory.create()
-        class_c.attrs = [x.clone() for x in attrs[3:]]
-
-        class_d = ClassFactory.create()
-        class_d.attrs.append(attrs[0].clone())
-        class_d.attrs.append(attrs[4].clone())
-
-        result = ClassUtils.reduce_attributes([class_a, class_b, class_c, class_d])
-        self.assertEqual(["B", "C", "D", "E", "F"], [x.name for x in result])
+        restrictions = Restrictions(min_occurs=1, max_occurs=1)
+        attr_a = AttrFactory.create(name="a", restrictions=restrictions.clone())
+        attr_b = AttrFactory.create(name="b", restrictions=restrictions.clone())
+        attr_c = AttrFactory.create(name="c", restrictions=restrictions.clone())
+        attr_d = AttrFactory.create(name="d", restrictions=restrictions.clone())
+
+        first = ClassFactory.create(qname="alphabet", attrs=[attr_b, attr_c, attr_d])
+        second = ClassFactory.create(qname="alphabet", attrs=[attr_a, attr_b])
+
+        result = ClassUtils.reduce_attributes([first, second])
+        expected_names = ["a", "b", "c", "d"]
+        self.assertEqual(expected_names, [x.name for x in result])
+
+        self.assertEqual(0, result[0].restrictions.min_occurs)
+        self.assertEqual(1, result[1].restrictions.min_occurs)
+        self.assertEqual(0, result[2].restrictions.min_occurs)
+        self.assertEqual(0, result[3].restrictions.min_occurs)
 
     def test_merge_attributes(self):
         a = AttrFactory.native(DataType.INT, name="a")
diff --git a/tests/fixtures/artists/metadata.py b/tests/fixtures/artists/metadata.py
index 69db6743..d23e73f5 100644
--- a/tests/fixtures/artists/metadata.py
+++ b/tests/fixtures/artists/metadata.py
@@ -22,6 +22,7 @@ class Alias:
         metadata={
             "name": "sort-name",
             "type": "Attribute",
+            "required": True,
         }
     )
     type: Optional[str] = field(
@@ -44,7 +45,10 @@ class Alias:
         }
     )
     value: str = field(
-        default=""
+        default="",
+        metadata={
+            "required": True,
+        }
     )
 
 
@@ -58,12 +62,14 @@ class BeginArea:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     name: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     sort_name: Optional[str] = field(
@@ -71,6 +77,7 @@ class BeginArea:
         metadata={
             "name": "sort-name",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -85,10 +92,14 @@ class Gender:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     value: str = field(
-        default=""
+        default="",
+        metadata={
+            "required": True,
+        }
     )
 
 
@@ -102,6 +113,7 @@ class IpiList:
         default_factory=list,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
 
@@ -116,6 +128,7 @@ class IsniList:
         default_factory=list,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
 
@@ -131,6 +144,7 @@ class Iso31661CodeList:
         metadata={
             "name": "iso-3166-1-code",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -146,6 +160,7 @@ class Iso31662CodeList:
         metadata={
             "name": "iso-3166-2-code",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -160,6 +175,7 @@ class LifeSpan:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     end: Optional[XmlDate] = field(
@@ -186,12 +202,14 @@ class AliasList:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     alias: List[Alias] = field(
         default_factory=list,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
 
@@ -206,12 +224,14 @@ class Area:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     name: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     sort_name: Optional[str] = field(
@@ -219,6 +239,7 @@ class Area:
         metadata={
             "name": "sort-name",
             "type": "Element",
+            "required": True,
         }
     )
     iso_3166_1_code_list: Optional[Iso31661CodeList] = field(
@@ -226,6 +247,7 @@ class Area:
         metadata={
             "name": "iso-3166-1-code-list",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -240,12 +262,14 @@ class EndArea:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     name: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     sort_name: Optional[str] = field(
@@ -253,6 +277,7 @@ class EndArea:
         metadata={
             "name": "sort-name",
             "type": "Element",
+            "required": True,
         }
     )
     iso_3166_2_code_list: Optional[Iso31662CodeList] = field(
@@ -260,6 +285,7 @@ class EndArea:
         metadata={
             "name": "iso-3166-2-code-list",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -274,12 +300,14 @@ class Artist:
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     type: Optional[str] = field(
         default=None,
         metadata={
             "type": "Attribute",
+            "required": True,
         }
     )
     type_id: Optional[str] = field(
@@ -287,12 +315,14 @@ class Artist:
         metadata={
             "name": "type-id",
             "type": "Attribute",
+            "required": True,
         }
     )
     name: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     sort_name: Optional[str] = field(
@@ -300,6 +330,7 @@ class Artist:
         metadata={
             "name": "sort-name",
             "type": "Element",
+            "required": True,
         }
     )
     disambiguation: Optional[str] = field(
@@ -326,6 +357,7 @@ class Artist:
         metadata={
             "name": "isni-list",
             "type": "Element",
+            "required": True,
         }
     )
     gender: Optional[Gender] = field(
@@ -338,12 +370,14 @@ class Artist:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     area: Optional[Area] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     begin_area: Optional[BeginArea] = field(
@@ -351,6 +385,7 @@ class Artist:
         metadata={
             "name": "begin-area",
             "type": "Element",
+            "required": True,
         }
     )
     end_area: Optional[EndArea] = field(
@@ -365,6 +400,7 @@ class Artist:
         metadata={
             "name": "life-span",
             "type": "Element",
+            "required": True,
         }
     )
     alias_list: Optional[AliasList] = field(
@@ -372,6 +408,7 @@ class Artist:
         metadata={
             "name": "alias-list",
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -386,5 +423,6 @@ class Metadata:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
diff --git a/tests/fixtures/series/series.py b/tests/fixtures/series/series.py
index 252fa5ca..3b397388 100644
--- a/tests/fixtures/series/series.py
+++ b/tests/fixtures/series/series.py
@@ -12,12 +12,14 @@ class Country:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     code: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     timezone: Optional[str] = field(
@@ -37,6 +39,7 @@ class Externals:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     thetvdb: Optional[int] = field(
@@ -49,6 +52,7 @@ class Externals:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -62,12 +66,14 @@ class Image:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     original: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -81,6 +87,7 @@ class Previousepisode:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -94,6 +101,7 @@ class Rating:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -107,12 +115,14 @@ class Schedule:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     days: List[str] = field(
         default_factory=list,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
 
@@ -126,6 +136,7 @@ class Self:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -140,12 +151,14 @@ class Links:
         metadata={
             "name": "self",
             "type": "Element",
+            "required": True,
         }
     )
     previousepisode: Optional[Previousepisode] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -165,12 +178,14 @@ class Network:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     country: Optional[Country] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -184,6 +199,7 @@ class Series:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     url: Optional[str] = field(
@@ -196,42 +212,49 @@ class Series:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     type: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     language: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     genres: List[str] = field(
         default_factory=list,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
     status: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     runtime: Optional[int] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     premiered: Optional[XmlDate] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     official_site: Optional[str] = field(
@@ -239,18 +262,21 @@ class Series:
         metadata={
             "name": "officialSite",
             "type": "Element",
+            "required": True,
         }
     )
     schedule: Optional[Schedule] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     rating: Optional[Rating] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     weight: Optional[int] = field(
@@ -263,6 +289,7 @@ class Series:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     web_channel: Optional[object] = field(
@@ -276,6 +303,7 @@ class Series:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     image: Optional[Image] = field(
@@ -288,12 +316,14 @@ class Series:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     updated: Optional[int] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     links: Optional[Links] = field(
diff --git a/tests/fixtures/stripe/models/balance.py b/tests/fixtures/stripe/models/balance.py
index 6cb4e543..3a2dbf60 100644
--- a/tests/fixtures/stripe/models/balance.py
+++ b/tests/fixtures/stripe/models/balance.py
@@ -11,12 +11,14 @@ class ConnectReserved:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     currency: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -30,12 +32,14 @@ class SourceTypes:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     card: Optional[int] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -49,18 +53,21 @@ class Available:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     currency: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     source_types: Optional[SourceTypes] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -74,18 +81,21 @@ class Pending:
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     currency: Optional[str] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     source_types: Optional[SourceTypes] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
 
@@ -100,29 +110,34 @@ class Balance:
         metadata={
             "name": "object",
             "type": "Element",
+            "required": True,
         }
     )
     available: Tuple[Available, ...] = field(
         default_factory=tuple,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
     connect_reserved: Tuple[ConnectReserved, ...] = field(
         default_factory=tuple,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )
     livemode: Optional[bool] = field(
         default=None,
         metadata={
             "type": "Element",
+            "required": True,
         }
     )
     pending: Tuple[Pending, ...] = field(
         default_factory=tuple,
         metadata={
             "type": "Element",
+            "min_occurs": 1,
         }
     )