Repository: tefra/xsdata

Issue:
Generation raises and index out of range when not all includes are provided
```
wget https://data.ndovloket.nl/docs/infoplus/RIT/ndov-ri-cdm-rit-v2.10.xsd
xsdata generate -p ritinfo ndov-ri-cdm-rit-v2.10.xsd
```
notice:
```
    self.copy_attribute_properties(source, target, attr, attr_type)
  File "/mnt/storage/home/skinkie/Sources/references/venv/lib/python3.11/site-packages/xsdata/codegen/handlers/process_attributes_types.py", line 233, in copy_attribute_properties
    source_attr = source.attrs[0]
                  ~~~~~~~~~~~~^^^
```
Add the required dependency:
```
wget https://data.ndovloket.nl/docs/infoplus/RIT/ndov-ri-cdm-common-v2.5.xsd
```
Generation works.

Expected change, raise some issue about missing files to prevent the error from happening?

Discussion:

Patch:
diff --git a/docs/codegen/download_schemas.md b/docs/codegen/download_schemas.md
index 13bdef73..6453a057 100644
--- a/docs/codegen/download_schemas.md
+++ b/docs/codegen/download_schemas.md
@@ -1,8 +1,28 @@
 # Download Schemas
 
 Generating from remote resources is not a great idea, the cli includes a command to
-download schemas and wsdl locally.
+download schemas and wsdl locally. The command will download any included schemas
+recursively.
 
 ```console exec="1" source="console"
 $ xsdata download --help
 ```
+
+**Example**
+
+```console
+❯ xsdata download https://www.w3.org/Math/XMLSchema/mathml3/mathml3.xsd -o ~/schemas
+========= xsdata v24.6.1 / Python 3.11.8 / Platform linux =========
+
+Setting base path to https:/www.w3.org/Math/XMLSchema/mathml3
+Fetching https://www.w3.org/Math/XMLSchema/mathml3/mathml3.xsd
+Fetching https://www.w3.org/Math/XMLSchema/mathml3/mathml3-content.xsd
+Fetching https://www.w3.org/Math/XMLSchema/mathml3/mathml3-strict-content.xsd
+Writing /home/chris/schemas/mathml3-strict-content.xsd
+Writing /home/chris/schemas/mathml3-content.xsd
+Fetching https://www.w3.org/Math/XMLSchema/mathml3/mathml3-presentation.xsd
+Writing /home/chris/schemas/mathml3-presentation.xsd
+Fetching https://www.w3.org/Math/XMLSchema/mathml3/mathml3-common.xsd
+Writing /home/chris/schemas/mathml3-common.xsd
+Writing /home/chris/schemas/mathml3.xsd
+```
diff --git a/xsdata/codegen/handlers/process_attributes_types.py b/xsdata/codegen/handlers/process_attributes_types.py
index bf290db4..ba98bbb2 100644
--- a/xsdata/codegen/handlers/process_attributes_types.py
+++ b/xsdata/codegen/handlers/process_attributes_types.py
@@ -187,7 +187,7 @@ class ProcessAttributeTypes(RelativeHandlerInterface):
         source = self.find_dependency(attr_type, attr.tag)
         if not source:
             logger.warning("Reset absent type: %s", attr_type.name)
-            self.reset_attribute_type(attr_type, True)
+            self.reset_attribute_type(attr_type)
         elif source.is_enumeration:
             attr.restrictions.min_length = None
             attr.restrictions.max_length = None
@@ -230,6 +230,11 @@ class ProcessAttributeTypes(RelativeHandlerInterface):
         Raises:
             AnalyzerValueError: if the source class has more than one attributes
         """
+        if not source.attrs:
+            logger.warning("Reset absent simple type: %s", attr_type.name)
+            cls.reset_attribute_type(attr_type)
+            return
+
         source_attr = source.attrs[0]
         index = attr.types.index(attr_type)
         attr.types.pop(index)
@@ -257,17 +262,16 @@ class ProcessAttributeTypes(RelativeHandlerInterface):
         attr.default = attr.default or source_attr.default
 
     @classmethod
-    def reset_attribute_type(cls, attr_type: AttrType, use_str: bool = True):
-        """Reset the attribute type to string or any simple type.
+    def reset_attribute_type(cls, attr_type: AttrType):
+        """Reset the attribute type to string.
 
         The method will also unset the circular/forward flags, as native
         types only depend on python builtin types.
 
         Args:
             attr_type: The attr type instance to reset
-            use_str: Whether to use xs:string or xs:anySimpleType
         """
-        attr_type.qname = str(DataType.STRING if use_str else DataType.ANY_SIMPLE_TYPE)
+        attr_type.qname = str(DataType.STRING)
         attr_type.native = True
         attr_type.circular = False
         attr_type.forward = False


Test patch:
diff --git a/tests/codegen/handlers/test_process_attributes_types.py b/tests/codegen/handlers/test_process_attributes_types.py
index bfb47e25..b7b96178 100644
--- a/tests/codegen/handlers/test_process_attributes_types.py
+++ b/tests/codegen/handlers/test_process_attributes_types.py
@@ -145,7 +145,7 @@ class ProcessAttributeTypesTests(FactoryTestCase):
         attr_type = attr.types[0]
 
         self.processor.process_dependency_type(target, attr, attr_type)
-        mock_reset_attribute_type.assert_called_once_with(attr_type, True)
+        mock_reset_attribute_type.assert_called_once_with(attr_type)
 
     @mock.patch.object(ProcessAttributeTypes, "copy_attribute_properties")
     @mock.patch.object(ProcessAttributeTypes, "find_dependency")
@@ -299,6 +299,18 @@ class ProcessAttributeTypesTests(FactoryTestCase):
             ]
         )
 
+    @mock.patch.object(ProcessAttributeTypes, "reset_attribute_type")
+    def test_copy_attribute_properties_from_empty_source(
+        self, mock_reset_attribute_type
+    ):
+        source = ClassFactory.create()
+        target = ClassFactory.elements(1)
+        attr = target.attrs[0]
+
+        self.processor.copy_attribute_properties(source, target, attr, attr.types[0])
+
+        mock_reset_attribute_type.assert_called_once_with(attr.types[0])
+
     def test_copy_attribute_properties_from_nillable_source(self):
         source = ClassFactory.elements(1, nillable=True)
         target = ClassFactory.elements(1)