diff --git a/tests/codegen/handlers/test_validate_attributes_overrides.py b/tests/codegen/handlers/test_validate_attributes_overrides.py index 6dcd4aa1..0c7d96e4 100644 --- a/tests/codegen/handlers/test_validate_attributes_overrides.py +++ b/tests/codegen/handlers/test_validate_attributes_overrides.py @@ -170,11 +170,29 @@ def test_validate_override(self): self.processor.validate_override(target, attr_a, attr_b) self.assertEqual(sys.maxsize, attr_b.restrictions.max_occurs) + # Parent is list, source is not + target.attrs = [attr_a] + attr_a.restrictions.min_occurs = 0 + attr_a.restrictions.max_occurs = 1 + attr_b.restrictions.min_occurs = 0 + attr_b.restrictions.max_occurs = 2 + self.processor.validate_override(target, attr_a, attr_b) + self.assertEqual(2, attr_b.restrictions.max_occurs) + + # Source is list, parent is prohibited + target.attrs = [attr_a] + attr_a.restrictions.min_occurs = None + attr_a.restrictions.max_occurs = 10 + attr_b.restrictions.min_occurs = 0 + attr_b.restrictions.max_occurs = 0 + self.processor.validate_override(target, attr_a, attr_b) + self.assertEqual(0, attr_b.restrictions.max_occurs) + self.assertIn(attr_a, target.attrs) + # Parent is any type, source isn't, skip attr_a = AttrFactory.native(DataType.STRING) attr_b = AttrFactory.native(DataType.ANY_SIMPLE_TYPE) target = ClassFactory.create(attrs=[attr_a]) - self.processor.validate_override(target, attr_a.clone(), attr_b) self.assertEqual(attr_a, target.attrs[0]) diff --git a/xsdata/codegen/handlers/validate_attributes_overrides.py b/xsdata/codegen/handlers/validate_attributes_overrides.py index dd675bda..24c48646 100644 --- a/xsdata/codegen/handlers/validate_attributes_overrides.py +++ b/xsdata/codegen/handlers/validate_attributes_overrides.py @@ -127,27 +127,45 @@ def validate_override(cls, target: Class, child_attr: Attr, parent_attr: Attr): if parent_attr.is_any_type and not child_attr.is_any_type: return - if child_attr.is_list and not parent_attr.is_list: + if ( + child_attr.is_list + and not parent_attr.is_list + and not parent_attr.is_prohibited + ) or ( + not child_attr.is_list + and not child_attr.is_prohibited + and parent_attr.is_list + ): # Hack much??? idk but Optional[str] can't override List[str] - parent_attr.restrictions.max_occurs = sys.maxsize + msg = "Converting {} field `{}::{}` to a list to match {} class `{}`" assert parent_attr.parent is not None - logger.warning( - "Converting parent field `%s::%s` to a list to match child class `%s`", - parent_attr.parent, - parent_attr.name, - target.name, - ) + + if child_attr.is_list: + parent_attr.restrictions.max_occurs = sys.maxsize + log_message = msg.format( + "parent", + parent_attr.parent, + parent_attr.name, + "child", + target.qname, + ) + else: + child_attr.restrictions.max_occurs = parent_attr.restrictions.max_occurs + log_message = msg.format( + "child", + target.name, + child_attr.name, + "parent", + parent_attr.parent, + ) + logger.warning(log_message) if ( child_attr.default == parent_attr.default and _bool_eq(child_attr.fixed, parent_attr.fixed) and _bool_eq(child_attr.mixed, parent_attr.mixed) - and _bool_eq( - child_attr.restrictions.tokens, parent_attr.restrictions.tokens - ) - and _bool_eq( - child_attr.restrictions.nillable, parent_attr.restrictions.nillable - ) + and _bool_eq(child_attr.is_tokens, parent_attr.is_tokens) + and _bool_eq(child_attr.is_nillable, parent_attr.is_nillable) and _bool_eq(child_attr.is_prohibited, parent_attr.is_prohibited) and _bool_eq(child_attr.is_optional, parent_attr.is_optional) ): diff --git a/xsdata/codegen/mixins.py b/xsdata/codegen/mixins.py index 5a242c9f..11dcd5ea 100644 --- a/xsdata/codegen/mixins.py +++ b/xsdata/codegen/mixins.py @@ -153,12 +153,12 @@ def base_attrs(self, target: Class) -> List[Attr]: assert base is not None - attrs.extend(self.base_attrs(base)) - for attr in base.attrs: attr.parent = base.qname attrs.append(attr) + attrs.extend(self.base_attrs(base)) + return attrs @abc.abstractmethod