Esempio n. 1
0
    def test_copy_attributes(self, mock_clone_attribute,
                             mock_copy_inner_classes):
        mock_clone_attribute.side_effect = lambda x, y, z: x.clone()
        target = ClassFactory.create(attrs=[
            AttrFactory.create(name="foo:a"),
            AttrFactory.create(name="b")
        ])
        source = ClassFactory.create(attrs=[
            AttrFactory.create(name="c", index=sys.maxsize),
            AttrFactory.create(name="a"),
            AttrFactory.create(name="boo:b"),
            AttrFactory.create(name="d"),
        ])
        extension = ExtensionFactory.create(type=AttrTypeFactory.create(
            name="foo:foo"))
        target.extensions.append(extension)

        ClassUtils.copy_attributes(source, target, extension)

        self.assertEqual(["foo:a", "b", "d", "c"],
                         [attr.name for attr in target.attrs])
        mock_copy_inner_classes.assert_called_once_with(source, target)
        mock_clone_attribute.assert_has_calls([
            mock.call(source.attrs[0], extension.restrictions, "foo"),
            mock.call(source.attrs[3], extension.restrictions, "foo"),
        ])
Esempio n. 2
0
    def test_copy_group_attributes(self, mock_clone_attribute, mock_copy_inner_classes):
        mock_clone_attribute.side_effect = lambda x, y: x.clone()
        source = ClassFactory.elements(2)
        source.inner.append(ClassFactory.create())
        target = ClassFactory.elements(3)
        attrs = list(target.attrs)
        attrs[1].name = "bar"

        ClassUtils.copy_group_attributes(source, target, target.attrs[1])

        self.assertEqual(4, len(target.attrs))
        self.assertEqual(source.attrs[0], target.attrs[1])
        self.assertEqual(source.attrs[1], target.attrs[2])
        mock_copy_inner_classes.assert_has_calls(
            [
                mock.call(source, target, source.attrs[0]),
                mock.call(source, target, source.attrs[1]),
            ]
        )
        mock_clone_attribute.assert_has_calls(
            [
                mock.call(source.attrs[0], attrs[1].restrictions),
                mock.call(source.attrs[1], attrs[1].restrictions),
            ]
        )
Esempio n. 3
0
    def process_simple_dependency(cls, source: Class, target: Class,
                                  attr: Attr, attr_type: AttrType):
        """
        Replace the given attribute type with the types of the single field
        source class.

        Ignore enumerations and gracefully handle dump types with no attributes.

        :raises: AnalyzerValueError if the source class has more than one attributes
        """
        if source.is_enumeration:
            return

        total = len(source.attrs)
        if total == 0:
            cls.reset_attribute_type(attr_type)
        elif total == 1:
            source_attr = source.attrs[0]
            index = attr.types.index(attr_type)
            attr.types.pop(index)

            for source_attr_type in source_attr.types:
                clone_type = source_attr_type.clone()
                attr.types.insert(index, clone_type)
                index += 1

            restrictions = source_attr.restrictions.clone()
            restrictions.merge(attr.restrictions)
            attr.restrictions = restrictions
            ClassUtils.copy_inner_classes(source, target)
        else:
            raise AnalyzerValueError(
                f"{source.type.__name__} with more than one attribute: `{source.name}`"
            )
Esempio n. 4
0
    def test_merge_attributes(self):
        target = ClassFactory.create(
            attrs=[
                AttrFactory.element(name="a", index=10),
                AttrFactory.element(name="b", index=1),
                AttrFactory.element(name="c", index=2),
                AttrFactory.attribute(name="id", index=0),
            ]
        )

        source = target.clone()

        target.attrs[0].restrictions.min_occurs = 2
        target.attrs[0].restrictions.max_occurs = 3

        source.attrs[1].restrictions.min_occurs = 3
        source.attrs[1].restrictions.max_occurs = 4
        source.attrs[3].restrictions.min_occurs = 3
        source.attrs[3].restrictions.max_occurs = 4
        source.attrs.append(AttrFactory.enumeration(name="d", index=4))

        ClassUtils.merge_attributes(target, source)

        names = ["id", "b", "c", "d", "a"]
        min_occurs = [0, 0, 0, None, 0]
        max_occurs = [4, 4, 1, None, 3]

        self.assertEqual(names, [x.name for x in target.attrs])
        self.assertEqual(min_occurs, [x.restrictions.min_occurs for x in target.attrs])
        self.assertEqual(max_occurs, [x.restrictions.max_occurs for x in target.attrs])
Esempio n. 5
0
    def copy_attribute_properties(cls, source: Class, target: Class,
                                  attr: Attr, attr_type: AttrType):
        """
        Replace the given attribute type with the types of the single field
        source class.

        Ignore enumerations and gracefully handle dump types with no attributes.

        :raises: AnalyzerValueError if the source class has more than one attributes
        """
        source_attr = source.attrs[0]
        index = attr.types.index(attr_type)
        attr.types.pop(index)

        for source_attr_type in source_attr.types:
            clone_type = source_attr_type.clone()
            attr.types.insert(index, clone_type)
            index += 1

            ClassUtils.copy_inner_class(source, target, attr, clone_type)

        restrictions = source_attr.restrictions.clone()
        restrictions.merge(attr.restrictions)
        attr.restrictions = restrictions
        attr.help = attr.help or source_attr.help

        if source.nillable:
            restrictions.nillable = True
Esempio n. 6
0
    def test_copy_inner_class_with_missing_inner(self):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = AttrTypeFactory.create(forward=True, qname=target.qname)

        with self.assertRaises(CodeGenerationError):
            ClassUtils.copy_inner_class(source, target, attr, attr_type)
Esempio n. 7
0
    def test_copy_inner_class_skip_non_forward_reference(self):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = AttrTypeFactory.create()
        ClassUtils.copy_inner_class(source, target, attr, attr_type)

        self.assertFalse(attr_type.circular)
        self.assertEqual(0, len(target.inner))
Esempio n. 8
0
    def test_copy_inner_class_check_circular_reference(self):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = AttrTypeFactory.create(forward=True, qname=target.qname)
        source.inner.append(target)

        ClassUtils.copy_inner_class(source, target, attr, attr_type)
        self.assertTrue(attr_type.circular)
        self.assertEqual(0, len(target.inner))
Esempio n. 9
0
    def test_copy_extensions(self):
        target = ClassFactory.create(extensions=ExtensionFactory.list(1))
        source = ClassFactory.create(extensions=ExtensionFactory.list(2))
        link_extension = ExtensionFactory.create()
        link_extension.restrictions.max_occurs = 2

        ClassUtils.copy_extensions(source, target, link_extension)

        self.assertEqual(3, len(target.extensions))
        self.assertEqual(2, target.extensions[1].restrictions.max_occurs)
        self.assertEqual(2, target.extensions[2].restrictions.max_occurs)
Esempio n. 10
0
    def test_find_inner(self):
        obj = ClassFactory.create(qname="{a}parent")
        first = ClassFactory.create(qname="{a}a")
        second = ClassFactory.create(qname="{c}c")
        third = ClassFactory.enumeration(2, qname="{d}d")
        obj.inner.extend((first, second, third))

        with self.assertRaises(CodeGenerationError) as cm:
            self.assertIsNone(ClassUtils.find_inner(obj, "nope"))

        self.assertEqual("Missing inner class {a}parent.nope", str(cm.exception))
        self.assertEqual(first, ClassUtils.find_inner(obj, "{a}a"))
        self.assertEqual(second, ClassUtils.find_inner(obj, "{c}c"))
        self.assertEqual(third, ClassUtils.find_inner(obj, "{d}d"))
Esempio n. 11
0
    def test_copy_inner_classes(self, mock_copy_inner_class):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create(types=AttrTypeFactory.list(3))

        ClassUtils.copy_inner_classes(source, target, attr)

        mock_copy_inner_class.assert_has_calls(
            [
                mock.call(source, target, attr, attr.types[0]),
                mock.call(source, target, attr, attr.types[1]),
                mock.call(source, target, attr, attr.types[2]),
            ]
        )
Esempio n. 12
0
    def test_copy_inner_class(self):
        source = ClassFactory.create()
        inner = ClassFactory.create(qname="a", module="b", package="c")
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = AttrTypeFactory.create(forward=True, qname=inner.qname)

        source.inner.append(inner)
        ClassUtils.copy_inner_class(source, target, attr, attr_type)

        self.assertEqual(1, len(target.inner))
        self.assertIsNot(inner, target.inner[0])
        self.assertEqual(target.package, target.inner[0].package)
        self.assertEqual(target.module, target.inner[0].module)
        self.assertEqual(inner.qname, target.inner[0].qname)
Esempio n. 13
0
    def process_complex_extension(cls, source: Class, target: Class, ext: Extension):
        """
        Complex flatten extension handler for primary classes eg ComplexType,
        Element.

        Compare source and target classes and either remove the
        extension completely, copy all source attributes to the target
        class or leave the extension alone.
        """
        if cls.should_remove_extension(source, target):
            target.extensions.remove(ext)
        elif cls.should_flatten_extension(source, target):
            ClassUtils.copy_attributes(source, target, ext)
        else:
            ext.type.reference = id(source)
            logger.debug("Ignore extension: %s", ext.type.name)
Esempio n. 14
0
    def process_complex_extension(cls, source: Class, target: Class,
                                  ext: Extension):
        """
        Complex flatten extension handler for primary classes eg ComplexType,
        Element.

        Compare source and target classes and either remove the
        extension completely, copy all source attributes to the target
        class or leave the extension alone.
        """
        res = cls.compare_attributes(source, target)
        if res == cls.REMOVE_EXTENSION:
            target.extensions.remove(ext)
        elif res == cls.FLATTEN_EXTENSION:
            ClassUtils.copy_attributes(source, target, ext)
        else:
            logger.debug("Ignore extension: %s", ext.type.name)
Esempio n. 15
0
    def map(cls, element: AnyElement) -> List[Class]:
        """Map schema children elements to classes."""

        assert element.qname is not None

        target_namespace, module = split_qname(element.qname)
        target = cls.build_class(element, target_namespace)

        return list(ClassUtils.flatten(target, module))
Esempio n. 16
0
    def validate_type_overrides(cls, source: Class, target: Class) -> bool:
        """Validate every override is using a subset of the parent attr
        types."""
        for attr in target.attrs:
            src_attr = ClassUtils.find_attr(source, attr.name)
            if src_attr and any(tp not in src_attr.types for tp in attr.types):
                return False

        return True
Esempio n. 17
0
    def process_attribute(self, target: Class, attr: Attr):
        """
        Find the source class the attribute refers to and copy its attributes
        to the target class.

        :raises AnalyzerValueError: if source class is not found.
        """
        qname = attr.types[0].qname  # group attributes have one type only.
        source = self.container.find(qname,
                                     condition=lambda x: x.type in
                                     (AttributeGroup, Group))

        if not source:
            raise AnalyzerValueError(f"Group attribute not found: `{qname}`")

        if source is target:
            target.attrs.remove(attr)
        else:
            ClassUtils.copy_group_attributes(source, target, attr)
Esempio n. 18
0
    def process_simple_extension(cls, source: Class, target: Class, ext: Extension):
        """
        Simple flatten extension handler for common classes eg SimpleType,
        Restriction.

        Steps:
            1. If target is source: drop the extension.
            2. If source is enumeration and target isn't create default value attribute.
            3. If both source and target are enumerations copy all attributes.
            4. If both source and target are not enumerations copy all attributes.
            5. If target is enumeration: drop the extension.
        """
        if source is target:
            target.extensions.remove(ext)
        elif source.is_enumeration and not target.is_enumeration:
            cls.add_default_attribute(target, ext)
        elif source.is_enumeration == target.is_enumeration:
            ClassUtils.copy_attributes(source, target, ext)
        else:  # this is an enumeration
            target.extensions.remove(ext)
Esempio n. 19
0
    def process_complex_extension(cls, source: Class, target: Class,
                                  ext: Extension):
        """
        Complex flatten extension handler for primary classes eg ComplexType,
        Element.

        Drop extension when:
            - source includes all target attributes
        Copy all attributes when:
            - source includes some of the target attributes
            - source has suffix attribute and target has at least one attribute
            - target has at least one suffix attribute
            - source is marked as strict type
        """
        res = cls.compare_attributes(source, target)
        if res == cls.INCLUDES_ALL:
            target.extensions.remove(ext)
        elif (res == cls.INCLUDES_SOME or source.strict_type
              or (source.has_suffix_attr and len(target.attrs) > 0)
              or target.has_suffix_attr):
            ClassUtils.copy_attributes(source, target, ext)
Esempio n. 20
0
    def test_copy_inner_classes(self):
        source = ClassFactory.create(
            inner=ClassFactory.list(2, package="a", module="b"))
        target = ClassFactory.create()

        ClassUtils.copy_inner_classes(source, target)  # All good copy all
        self.assertEqual(2, len(target.inner))

        ClassUtils.copy_inner_classes(source,
                                      target)  # Inner classes exist skip
        self.assertEqual(2, len(target.inner))

        source.inner.append(target)

        attr = AttrFactory.create(types=[
            AttrTypeFactory.create(name=target.name, forward=True),
            AttrTypeFactory.create(name=target.name, forward=False),
            AttrTypeFactory.create(name="foobar"),
        ])
        target.attrs.append(attr)

        ClassUtils.copy_inner_classes(source,
                                      target)  # Inner class matches target
        self.assertEqual(2, len(target.inner))

        for inner in target.inner:
            self.assertEqual(target.package, inner.package)
            self.assertEqual(target.module, inner.module)

        self.assertTrue(attr.types[0].circular)
        self.assertFalse(attr.types[1].circular)
        self.assertFalse(attr.types[2].circular)
Esempio n. 21
0
    def process_xml_documents(self, uris: List[str]):
        """Process a list of xml resources."""

        classes = []
        parser = TreeParser()
        for uri in uris:
            input_stream = self.load_resource(uri)
            if input_stream:
                logger.info("Parsing document %s", os.path.basename(uri))
                any_element: AnyElement = parser.from_bytes(input_stream)
                classes.extend(ElementMapper.map(any_element))

        dirname = os.path.dirname(uris[0]) if uris else ""
        self.class_map[dirname] = ClassUtils.reduce(classes)
Esempio n. 22
0
    def process_json_documents(self, uris: List[str]):
        """Process a list of json resources."""

        classes = []
        for uri in uris:
            input_stream = self.load_resource(uri)
            if input_stream:
                data = json.load(io.BytesIO(input_stream))
                logger.info("Parsing document %s", os.path.basename(uri))
                name = self.config.output.package.split(".")[-1]
                classes.extend(DictMapper.map(data, name))

        dirname = os.path.dirname(uris[0]) if uris else ""
        self.class_map[dirname] = ClassUtils.reduce(classes)
Esempio n. 23
0
    def test_clone_attribute(self):
        attr = AttrFactory.create(
            restrictions=Restrictions(length=1),
            types=[
                AttrTypeFactory.create(qname="x"),
                AttrTypeFactory.create(qname="y"),
                AttrTypeFactory.xs_int(),
            ],
        )
        restrictions = Restrictions(length=2)

        clone = ClassUtils.clone_attribute(attr, restrictions)

        self.assertEqual(2, clone.restrictions.length)
        self.assertIsNot(attr, clone)
Esempio n. 24
0
    def test_reduce(self, mock_merge_attributes):
        first = ClassFactory.elements(2)
        second = first.clone()
        second.attrs.append(AttrFactory.create())
        third = second.clone()
        third.attrs.append(AttrFactory.create())
        fourth = ClassFactory.create()

        actual = ClassUtils.reduce([first, second, third, fourth])

        self.assertEqual([third, fourth], list(actual))
        mock_merge_attributes.assert_has_calls(
            [
                mock.call(third, first),
                mock.call(third, second),
            ]
        )
Esempio n. 25
0
    def test_clone_attribute(self):
        attr = AttrFactory.create(
            restrictions=RestrictionsFactory.create(length=1),
            types=[
                AttrTypeFactory.create(name="foo:x"),
                AttrTypeFactory.create(name="y"),
                AttrTypeFactory.xs_int(),
            ],
        )
        restrictions = RestrictionsFactory.create(length=2)
        prefix = "foo"

        clone = ClassUtils.clone_attribute(attr, restrictions, prefix)

        self.assertEqual(["foo:x", "foo:y", "integer"],
                         [x.name for x in clone.types])
        self.assertEqual(2, clone.restrictions.length)
        self.assertIsNot(attr, clone)
Esempio n. 26
0
    def process_attribute(self, target: Class, attr: Attr):
        """
        Check if the given attribute matches any substitution class in order to
        clone it's attributes to the target class.

        The cloned attributes are placed below the attribute the are
        supposed to substitute.
        """
        index = target.attrs.index(attr)
        assert self.substitutions is not None

        for attr_type in attr.types:
            for substitution in self.substitutions.get(attr_type.qname, []):
                clone = ClassUtils.clone_attribute(substitution,
                                                   attr.restrictions)

                pos = collections.find(target.attrs, clone)
                index = pos + 1 if pos > -1 else index
                target.attrs.insert(index, clone)

                self.process_attribute(target, clone)
Esempio n. 27
0
    def test_flatten(self):
        target = ClassFactory.create(
            qname="{xsdata}root", attrs=AttrFactory.list(3), inner=ClassFactory.list(2)
        )

        for attr in target.attrs:
            attr.types.extend([x.clone() for x in attr.types])
            for tp in attr.types:
                tp.forward = True

        result = ClassUtils.flatten(target, "xsdata")
        actual = list(result)

        self.assertIsInstance(result, Generator)
        self.assertEqual(3, len(actual))

        for obj in actual:
            self.assertEqual("xsdata", obj.module)

        for attr in target.attrs:
            self.assertEqual(1, len(attr.types))
            self.assertFalse(attr.types[0].forward)
Esempio n. 28
0
    def merge_redefined_type(cls, source: Class, target: Class):
        """
        Copy any attributes and extensions to redefined types from the original
        definitions.

        Redefined inheritance is optional search for self references in
        extensions and attribute groups.
        """
        circular_extension = cls.find_circular_extension(target)
        circular_group = cls.find_circular_group(target)

        if circular_extension:
            ClassUtils.copy_attributes(source, target, circular_extension)
            ClassUtils.copy_extensions(source, target, circular_extension)

        if circular_group:
            ClassUtils.copy_group_attributes(source, target, circular_group)
Esempio n. 29
0
    def map(cls, data: Dict, name: str) -> List[Class]:
        """Convert a dictionary to a list of codegen classes."""

        target = cls.build_class(data, name)
        return list(ClassUtils.flatten(target, name))
Esempio n. 30
0
    def find_inner(self, source: Class, qname: str) -> Class:
        inner = ClassUtils.find_inner(source, qname)
        if inner.status == Status.RAW:
            self.process_class(inner)

        return inner