From db2014540ba34bfbb9bb02527d84ad4a6b33bb43 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 24 Jun 2021 16:49:13 +0300 Subject: [PATCH 1/2] Set xs:attribute default base to xs:string --- tests/models/xsd/test_attribute.py | 6 ++++++ xsdata/models/xsd.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/tests/models/xsd/test_attribute.py b/tests/models/xsd/test_attribute.py index 44260a49e..76ee769fd 100644 --- a/tests/models/xsd/test_attribute.py +++ b/tests/models/xsd/test_attribute.py @@ -1,6 +1,7 @@ from unittest import TestCase from xsdata.exceptions import SchemaValueError +from xsdata.models.enums import Namespace from xsdata.models.enums import UseType from xsdata.models.xsd import Attribute from xsdata.models.xsd import Length @@ -64,7 +65,12 @@ def test_get_restrictions(self): def test_property_bases(self): obj = Attribute() + obj.ns_map["xs"] = Namespace.XS.uri + self.assertEqual(["xs:string"], list(obj.bases)) + + obj.simple_type = SimpleType() self.assertEqual([], list(obj.bases)) obj.type = "foo" + obj.simple_type = None self.assertEqual(["foo"], list(obj.bases)) diff --git a/xsdata/models/xsd.py b/xsdata/models/xsd.py index 297786604..1574fe1d7 100644 --- a/xsdata/models/xsd.py +++ b/xsdata/models/xsd.py @@ -315,6 +315,8 @@ class Attribute(AnnotationBase): def bases(self) -> Iterator[str]: if self.type: yield self.type + elif not self.has_children: + yield DataType.STRING.prefixed(self.xs_prefix) @property def is_attribute(self) -> bool: From 717f6724f570517071c70d489350abb3ce78e5ad Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 24 Jun 2021 16:50:28 +0300 Subject: [PATCH 2/2] AttributeTypeHandler: allow bare types --- tests/codegen/handlers/test_attribute_type.py | 33 +++++++++++-------- xsdata/codegen/handlers/attribute_type.py | 8 +++-- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/tests/codegen/handlers/test_attribute_type.py b/tests/codegen/handlers/test_attribute_type.py index 1081e91a8..56d066425 100644 --- a/tests/codegen/handlers/test_attribute_type.py +++ b/tests/codegen/handlers/test_attribute_type.py @@ -119,19 +119,6 @@ def test_process_dependency_type_with_absent_type( self.processor.process_dependency_type(target, attr, attr_type) mock_reset_attribute_type.assert_called_once_with(attr_type, True) - @mock.patch.object(AttributeTypeHandler, "reset_attribute_type") - @mock.patch.object(AttributeTypeHandler, "find_dependency") - def test_process_dependency_type_with_dummy_type( - self, mock_find_dependency, mock_reset_attribute_type - ): - mock_find_dependency.return_value = ClassFactory.create(tag=Tag.ELEMENT) - target = ClassFactory.create() - attr = AttrFactory.create() - attr_type = attr.types[0] - - self.processor.process_dependency_type(target, attr, attr_type) - mock_reset_attribute_type.assert_called_once_with(attr_type, False) - @mock.patch.object(AttributeTypeHandler, "copy_attribute_properties") @mock.patch.object(AttributeTypeHandler, "find_dependency") def test_process_dependency_type_with_simple_type( @@ -260,7 +247,7 @@ def test_copy_attribute_properties_from_nillable_source(self): self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) self.assertTrue(attr.restrictions.nillable) - def test_copy_attribute_properties_to_attribute_target(self): + def test_copy_attribute_properties_to_attribute_target_preserve_occurrences(self): source = ClassFactory.elements(1, nillable=True) target = ClassFactory.create(attrs=AttrFactory.list(1, tag=Tag.ATTRIBUTE)) attr = target.attrs[0] @@ -274,6 +261,24 @@ def test_copy_attribute_properties_to_attribute_target(self): self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) self.assertFalse(attr.is_optional) + def test_copy_attribute_properties_set_default_value_if_none(self): + target = ClassFactory.create(attrs=AttrFactory.list(1, tag=Tag.ATTRIBUTE)) + attr = target.attrs[0] + + source = ClassFactory.elements(1) + source.attrs[0].default = "foo" + source.attrs[0].fixed = True + + self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) + self.assertEqual("foo", attr.default) + self.assertTrue("foo", attr.fixed) + + source.attrs[0].default = "bar" + source.attrs[0].fixed = False + self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) + self.assertEqual("foo", attr.default) + self.assertTrue("foo", attr.fixed) + @mock.patch.object(AttributeTypeHandler, "is_circular_dependency") def test_set_circular_flag(self, mock_is_circular_dependency): source = ClassFactory.create() diff --git a/xsdata/codegen/handlers/attribute_type.py b/xsdata/codegen/handlers/attribute_type.py index cf1047c5c..4e914b94b 100644 --- a/xsdata/codegen/handlers/attribute_type.py +++ b/xsdata/codegen/handlers/attribute_type.py @@ -110,15 +110,15 @@ def process_dependency_type(self, target: Class, attr: Attr, attr_type: AttrType Process an attributes type that depends on any global type. Strategies: - 1. Reset absent or dummy attribute types with a warning + 1. Reset absent types with a warning 2. Copy attribute properties from a simple type 3. Copy format restriction from an enumeration 4. Set circular flag for the rest """ source = self.find_dependency(attr_type, attr.tag) - if not source or (not source.attrs and not source.extensions): - logger.warning("Reset dummy type: %s", attr_type.name) + if not source: + logger.warning("Reset absent type: %s", attr_type.name) use_str = not source or not source.is_complex self.reset_attribute_type(attr_type, use_str) elif source.is_simple_type: @@ -167,6 +167,8 @@ def copy_attribute_properties( attr.restrictions = restrictions attr.help = attr.help or source_attr.help + attr.fixed = attr.fixed or source_attr.fixed + attr.default = attr.default or source_attr.default def set_circular_flag(self, source: Class, target: Class, attr_type: AttrType): """Update circular reference flag."""