Esempio n. 1
0
    def test_next_node_when_given_qname_matches_dataclass_var(
            self, mock_ctx_fetch, mock_element_xsi_type):
        ele = Element("a")
        ctx = XmlContext()
        cfg = ParserConfig()
        var = XmlElement(name="a",
                         qname=QName("a"),
                         types=[Foo],
                         dataclass=True)
        meta = XmlMeta(
            name="foo",
            clazz=None,
            qname=QName("foo"),
            source_qname=QName("foo"),
            nillable=False,
            vars=[var],
        )
        xsi_type = QName("foo")
        namespace = meta.qname.namespace
        mock_ctx_fetch.return_value = replace(meta)
        mock_element_xsi_type.return_value = xsi_type
        node = ElementNode(position=0, meta=meta, config=cfg)

        actual = node.next_node(ele, 10, ctx)
        self.assertIsInstance(actual, ElementNode)
        self.assertEqual(10, actual.position)
        self.assertIs(mock_ctx_fetch.return_value, actual.meta)
        mock_ctx_fetch.assert_called_once_with(var.clazz, namespace, xsi_type)
Esempio n. 2
0
    def build(self, clazz: Type, parent_ns: Optional[str] = None) -> XmlMeta:
        """Fetch from cache or build the metadata object for the given class
        and parent namespace."""

        if clazz not in self.cache:

            # Ensure the given type is a dataclass.
            if not is_dataclass(clazz):
                raise XmlContextError(f"Object {clazz} is not a dataclass.")

            # Fetch the dataclass meta settings and make sure we don't inherit
            # the parent class meta.
            meta = getattr(clazz, "Meta", None)
            if meta and meta.__qualname__ != f"{clazz.__name__}.Meta":
                meta = None

            name = getattr(meta, "name", self.name_generator(clazz.__name__))
            nillable = getattr(meta, "nillable", False)
            namespace = getattr(meta, "namespace", parent_ns)
            module = sys.modules[clazz.__module__]
            source_namespace = getattr(module, "__NAMESPACE__", None)

            self.cache[clazz] = XmlMeta(
                name=name,
                clazz=clazz,
                qname=QName(namespace, name),
                source_qname=QName(source_namespace, name),
                nillable=nillable,
                vars=list(self.get_type_hints(clazz, namespace)),
            )
        return self.cache[clazz]
Esempio n. 3
0
    def build(self, clazz: Type, parent_ns: Optional[str] = None) -> XmlMeta:
        """
        Fetch from cache or build the binding metadata for the given class and
        parent namespace.

        :param clazz: A dataclass type
        :param parent_ns: The inherited parent namespace
        """

        if clazz not in self.cache:

            # Ensure the given type is a dataclass.
            if not is_dataclass(clazz):
                raise XmlContextError(f"Object {clazz} is not a dataclass.")

            # Fetch the dataclass meta settings and make sure we don't inherit
            # the parent class meta.
            meta = clazz.Meta if "Meta" in clazz.__dict__ else None
            name = getattr(meta, "name", None) or self.local_name(
                clazz.__name__)
            nillable = getattr(meta, "nillable", False)
            namespace = getattr(meta, "namespace", parent_ns)
            module = sys.modules[clazz.__module__]
            source_namespace = getattr(module, "__NAMESPACE__", None)

            self.cache[clazz] = XmlMeta(
                clazz=clazz,
                qname=build_qname(namespace, name),
                source_qname=build_qname(source_namespace, name),
                nillable=nillable,
                vars=list(self.get_type_hints(clazz, namespace)),
            )
        return self.cache[clazz]
Esempio n. 4
0
 def test_fetch(self, mock_build, mock_find_subclass):
     meta = XmlMeta(
         clazz=ItemsType,
         qname="ItemsType",
         source_qname="ItemsType",
         nillable=False,
     )
     mock_build.return_value = meta
     actual = self.ctx.fetch(ItemsType, "foo")
     self.assertEqual(meta, actual)
     self.assertEqual(0, mock_find_subclass.call_count)
     mock_build.assert_called_once_with(ItemsType, "foo")
Esempio n. 5
0
 def setUp(self) -> None:
     super().setUp()
     self.context = XmlContext()
     self.meta = XmlMeta(clazz=Foo, qname="foo", source_qname="foo", nillable=False)
     self.node = ElementNode(
         position=0,
         meta=self.meta,
         context=self.context,
         config=ParserConfig(),
         attrs={},
         ns_map={},
     )
Esempio n. 6
0
    def test_fetch_with_xsi_type_and_subclass_not_found(
            self, mock_build, mock_find_subclass):
        meta = XmlMeta(
            clazz=ItemsType,
            qname="ItemsType",
            source_qname="ItemsType",
            nillable=False,
        )

        mock_build.return_value = meta
        mock_find_subclass.return_value = None
        actual = self.ctx.fetch(ItemsType, xsi_type="foo")
        self.assertEqual(meta, actual)
        mock_find_subclass.assert_called_once_with(ItemsType, "foo")
Esempio n. 7
0
 def test_next_node_when_config_fail_on_unknown_properties_is_false(self):
     ele = Element("nope")
     ctx = XmlContext()
     cfg = ParserConfig(fail_on_unknown_properties=False)
     meta = XmlMeta(
         name="foo",
         clazz=None,
         qname=QName("foo"),
         source_qname=QName("foo"),
         nillable=False,
     )
     node = ElementNode(position=0, meta=meta, config=cfg)
     actual = node.next_node(ele, 10, ctx)
     self.assertEqual(SkipNode(position=10), actual)
Esempio n. 8
0
    def test_fetch_with_xsi_type_and_subclass_found(self, mock_build,
                                                    mock_find_subclass):
        meta = XmlMeta(
            clazz=ItemsType,
            qname="ItemsType",
            source_qname="ItemsType",
            nillable=False,
        )
        xsi_meta = replace(meta, qname="XsiType")

        mock_build.side_effect = [meta, xsi_meta]
        mock_find_subclass.return_value = xsi_meta
        actual = self.ctx.fetch(ItemsType, xsi_type="foo")
        self.assertEqual(xsi_meta, actual)
        mock_find_subclass.assert_called_once_with(ItemsType, "foo")
Esempio n. 9
0
    def test_build_build_vars(self, mock_get_type_hints):
        var = XmlVar(element=True, name="foo", qname="{foo}bar", types=[int])
        mock_get_type_hints.return_value = [var]

        result = self.ctx.build(ItemsType, None)
        expected = XmlMeta(
            clazz=ItemsType,
            qname="ItemsType",
            source_qname="ItemsType",
            nillable=False,
            vars=[var],
        )

        self.assertEqual(expected, result)
        mock_get_type_hints.assert_called_once_with(ItemsType, None)
Esempio n. 10
0
    def test_next_node_when_given_qname_does_not_match_any_var(self):
        ele = Element("nope")
        ctx = XmlContext()
        cfg = ParserConfig()
        meta = XmlMeta(
            name="foo",
            clazz=None,
            qname=QName("foo"),
            source_qname=QName("foo"),
            nillable=False,
        )
        node = ElementNode(position=0, meta=meta, config=cfg)

        with self.assertRaises(XmlContextError) as cm:
            node.next_node(ele, 10, ctx)

        self.assertEqual("foo does not support mixed content: nope",
                         str(cm.exception))
Esempio n. 11
0
    def test_next_node_when_given_qname_matches_primitive_var(self):
        ele = Element("a")
        ctx = XmlContext()
        cfg = ParserConfig()
        var = XmlText(name="a", qname=QName("a"), types=[int], default=100)
        meta = XmlMeta(
            name="foo",
            clazz=None,
            qname=QName("foo"),
            source_qname=QName("foo"),
            nillable=False,
            vars=[var],
        )
        node = ElementNode(position=0, meta=meta, config=cfg)

        actual = node.next_node(ele, 10, ctx)
        self.assertIsInstance(actual, PrimitiveNode)
        self.assertEqual(10, actual.position)
        self.assertEqual(var, actual.var)
Esempio n. 12
0
    def test_next_node_when_given_qname_matches_any_element_var(self):
        ele = Element("a")
        ctx = XmlContext()
        cfg = ParserConfig()
        var = XmlWildcard(name="a",
                          qname=QName("a"),
                          types=[],
                          dataclass=False)
        meta = XmlMeta(
            name="foo",
            clazz=None,
            qname=QName("foo"),
            source_qname=QName("foo"),
            nillable=False,
            vars=[var],
        )
        node = ElementNode(position=0, meta=meta, config=cfg)

        actual = node.next_node(ele, 10, ctx)
        self.assertIsInstance(actual, WildcardNode)
        self.assertEqual(10, actual.position)
        self.assertEqual(var.qname, actual.qname)
Esempio n. 13
0
    def test_property_element_form(self):
        meta = XmlMeta(
            name="foo",
            clazz=BookForm,
            qname=QName("foo"),
            source_qname=QName("foo"),
            nillable=False,
        )
        self.assertEqual(FormType.UNQUALIFIED, meta.element_form)

        meta = replace(meta, qname=QName("bar", "foo"))
        self.assertEqual(FormType.QUALIFIED, meta.element_form)

        meta.vars.append(XmlElement(name="a", qname=QName("a")))
        self.assertEqual(FormType.UNQUALIFIED, meta.element_form)

        meta.vars.append(
            XmlElement(name="b", qname=QName("b"), namespaces=["bar"]))
        self.assertEqual(FormType.UNQUALIFIED, meta.element_form)

        meta.vars.pop(0)
        self.assertEqual(FormType.QUALIFIED, meta.element_form)
Esempio n. 14
0
    def build(self, clazz: Type, parent_ns: Optional[str] = None) -> XmlMeta:
        if clazz not in self.cache:
            if not is_dataclass(clazz):
                raise XmlContextError(f"Object {clazz} is not a dataclass.")

            meta = getattr(clazz, "Meta", None)
            if meta and meta.__qualname__ != f"{clazz.__name__}.Meta":
                meta = None

            name = getattr(meta, "name", self.name_generator(clazz.__name__))
            nillable = getattr(meta, "nillable", False)
            namespace = getattr(meta, "namespace", parent_ns)
            module = sys.modules[clazz.__module__]
            source_namespace = getattr(module, "__NAMESPACE__", None)

            self.cache[clazz] = XmlMeta(
                name=name,
                clazz=clazz,
                qname=QName(namespace, name),
                source_qname=QName(source_namespace, name),
                nillable=nillable,
                vars=list(self.get_type_hints(clazz, namespace)),
            )
        return self.cache[clazz]