def test_parse_any_element(self): element = Element("foo") element.set("a", "1") element.set("b", "2") element.set( QName(Namespace.XSI.uri, "type").text, QName(Namespace.XS.uri, "float").text ) element.text = "yes" element.tail = "no" actual = ParserUtils.parse_any_element(element) expected = AnyElement( qname=element.tag, text="yes", tail="no", attributes={ "a": "1", "b": "2", QName(Namespace.XSI.uri, "type"): QName(Namespace.XS.uri, "float"), }, ns_map=element.nsmap, ) self.assertEqual(expected, actual) actual = ParserUtils.parse_any_element(element, False) self.assertIsNone(actual.qname)
def test_bind_objects(self): @dataclass class A: x: int y: int = field(init=False) w: object = field(metadata=dict(type=XmlType.WILDCARD)) ctx = XmlContext() meta = ctx.build(A) x = meta.find_var("x") y = meta.find_var("y") w = meta.find_var("wild") wild_element = AnyElement(qname="foo") objects = [ ("foo", 0), (x.qname, 1), (y.qname, 2), (w.qname, None), (w.qname, wild_element), ] params = {} ParserUtils.bind_objects(params, meta, 1, objects) expected = { "x": 1, "w": AnyElement( children=[AnyElement(qname="w", text=""), AnyElement(qname="foo")] ), } self.assertEqual(expected, params)
def test_bind_element_wild_text_when_find_var_returns_none(self): meta = mock.Mock(XmlMeta) meta.find_var = MagicMock(return_value=None) elem = Element("foo") params = {} ParserUtils.bind_element_wild_text(params, meta, elem) self.assertEqual(0, len(params))
def test_bind_attrs_skip_empty_attrs(self, mock_find_var): metadata = self.ctx.build(ProductType) params = {} ParserUtils.bind_attrs(params, metadata, {}, {}) self.assertEqual(0, len(params)) self.assertEqual(0, mock_find_var.call_count)
def bind(self, qname: str, text: NoneStr, tail: NoneStr, objects: List) -> bool: params: Dict = {} wild_node = False text_node = False ParserUtils.bind_attrs(params, self.meta, self.attrs, self.ns_map) wild_var = self.meta.find_var(mode=FindMode.WILDCARD) if wild_var and wild_var.mixed: ParserUtils.bind_mixed_objects(params, wild_var, self.position, objects) else: ParserUtils.bind_objects(params, self.meta, self.position, objects) text_node = ParserUtils.bind_content(params, self.meta, text, self.ns_map) if not text_node and wild_var: ParserUtils.bind_wild_content(params, wild_var, text, tail, self.attrs, self.ns_map) obj = self.meta.clazz(**params) if self.derived: obj = DerivedElement(qname=qname, value=obj, substituted=self.substituted) objects.append((qname, obj)) if not wild_var and self.mixed and not wild_node: tail = ParserUtils.normalize_content(tail) if tail: objects.append((None, tail)) return True
def test_bind_attrs(self, mock_parse_value, mock_parse_any_attribute): mock_parse_value.return_value = "2020-03-02" mock_parse_any_attribute.return_value = "foobar" metadata = self.ctx.build(ProductType) eff_date = metadata.find_var("effDate") params = {} ns_map = {} attrs = {"effDate": "2020-03-01", "foo": "bar"} ParserUtils.bind_attrs(params, metadata, attrs, ns_map) expected = { "eff_date": "2020-03-02", "other_attributes": { "foo": "foobar" }, } self.assertEqual(expected, params) mock_parse_any_attribute.assert_called_once_with("bar", ns_map) mock_parse_value.assert_called_once_with( "2020-03-01", eff_date.types, eff_date.default, ns_map, eff_date.tokens, eff_date.format, )
def test_bind_element_text_with_no_text_var(self): element = Element("foo") element.text = "foo" params = {} metadata = self.ctx.build(Books) ParserUtils.bind_element_text(params, metadata, element) self.assertEqual({}, params)
def test_parse_any_attribute(self): ns_map = {"xsi": Namespace.XSI.uri, "xsd": Namespace.XS.uri} value = ParserUtils.parse_any_attribute("xsd:string", ns_map) self.assertEqual("{http://www.w3.org/2001/XMLSchema}string", value) ns_map["http"] = "happens" value = ParserUtils.parse_any_attribute("http://www.com", ns_map) self.assertEqual("http://www.com", value)
def test_parse_value(self, mock_deserialize): self.assertEqual(1, ParserUtils.parse_value(None, [int], 1)) self.assertIsNone(ParserUtils.parse_value(None, [int], lambda: 1)) self.assertTrue(2, ParserUtils.parse_value("1", [int], None)) mock_deserialize.assert_called_once_with("1", [int], ns_map=None, format=None)
def test_parse_value_with_tokens_true(self): actual = ParserUtils.parse_value(" 1 2 3", [int], list, None, True) self.assertEqual([1, 2, 3], actual) actual = ParserUtils.parse_value(["1", "2", "3"], [int], list, None, True) self.assertEqual([1, 2, 3], actual) actual = ParserUtils.parse_value(None, [int], lambda: [1, 2, 3], None, True) self.assertEqual([1, 2, 3], actual)
def test_bind_element_wild_text_when_element_has_no_text_and_tail(self): var = XmlVar(name="a", qname=QName("a")) meta = mock.Mock(XmlMeta) meta.find_var = MagicMock(return_value=var) elem = Element("foo") params = {} ParserUtils.bind_element_wild_text(params, meta, elem) self.assertEqual(0, len(params))
def test_score_object(self): self.assertEqual(-1.0, ParserUtils.score_object(None)) cls = make_dataclass("b", [("x", int), ("y", str), ("z", Any)]) self.assertEqual(2.5, ParserUtils.score_object(cls(1, "1", None))) self.assertEqual(-1, ParserUtils.score_object(None)) self.assertEqual(1.0, ParserUtils.score_object("a")) self.assertEqual(1.5, ParserUtils.score_object(2.9))
def test_xsi_type(self): ns_map = {"bar": "xsdata"} attrs = {} self.assertIsNone(ParserUtils.xsi_type(attrs, ns_map)) attrs = {QNames.XSI_TYPE: "foo"} self.assertEqual("foo", ParserUtils.xsi_type(attrs, ns_map)) attrs = {QNames.XSI_TYPE: "bar:foo"} self.assertEqual("{xsdata}foo", ParserUtils.xsi_type(attrs, ns_map))
def test_bind_attrs_doesnt_overwrite_values(self): metadata = self.ctx.build(ProductType) params = dict(eff_date="foo") attrs = {"effDate": "2020-03-01"} ns_map = {} ParserUtils.bind_attrs(params, metadata, attrs, ns_map) expected = {"eff_date": "foo", "other_attributes": {"effDate": "2020-03-01"}} self.assertEqual(expected, params)
def test_bind_objects_with_unassigned_object(self, mock_warning): a = make_dataclass("a", [("x", int)]) meta = XmlContext().build(a) params = {} objects = [("x", 1), ("y", 2)] ParserUtils.bind_objects(params, meta, 0, objects) self.assertEqual({"x": 1}, params) mock_warning.assert_called_once_with("Unassigned parsed object %s", "y")
def test_bind_element_attrs_doesnt_overwrite_values(self): metadata = self.ctx.build(ProductType) element = Element("foo") element.set("effDate", "2020-03-01") params = dict(eff_date="foo") ParserUtils.bind_element_attrs(params, metadata, element) expected = {"eff_date": "foo", "other_attributes": {"effDate": "2020-03-01"}} self.assertEqual(expected, params)
def test_parse_xsi_type(self): ele = Element("foo") self.assertIsNone(ParserUtils.parse_xsi_type(ele)) ele.set(QNames.XSI_TYPE, "foo") self.assertEqual(QName("foo"), ParserUtils.parse_xsi_type(ele)) ele = Element("foo", nsmap=dict(bar="xsdata")) ele.set(QNames.XSI_TYPE, "bar:foo") self.assertEqual(QName("xsdata", "foo"), ParserUtils.parse_xsi_type(ele))
def bind(self, qname: str, text: NoneStr, tail: NoneStr, objects: List) -> bool: obj = AnyElement( qname=qname, text=ParserUtils.normalize_content(text), tail=ParserUtils.normalize_content(tail), attributes=ParserUtils.parse_any_attributes(self.attrs, self.ns_map), children=ParserUtils.fetch_any_children(self.position, objects), ) objects.append((self.var.qname, obj)) return True
def test_bind_var_with_list_var(self): var = XmlVar(name="a", qname="a", list_element=True) params = {} status = ParserUtils.bind_var(params, var, 1) self.assertTrue(status) self.assertEqual({"a": [1]}, params) status = ParserUtils.bind_var(params, var, 2) self.assertTrue(status) self.assertEqual({"a": [1, 2]}, params)
def test_bind_element_param_with_list_var(self): var = XmlVar(name="a", qname=QName("a"), default=list) params = {} status = ParserUtils.bind_element_param(params, var, 1) self.assertTrue(status) self.assertEqual({"a": [1]}, params) status = ParserUtils.bind_element_param(params, var, 2) self.assertTrue(status) self.assertEqual({"a": [1, 2]}, params)
def test_bind_element_param(self): var = XmlVar(name="a", qname=QName("a")) params = {} status = ParserUtils.bind_element_param(params, var, 1) self.assertTrue(status) self.assertEqual({"a": 1}, params) status = ParserUtils.bind_element_param(params, var, 2) self.assertFalse(status) self.assertEqual({"a": 1}, params)
def test_data_type(self): ns_map = {"bar": "xsdata"} attrs = {} self.assertEqual(DataType.STRING, ParserUtils.data_type(attrs, ns_map)) ns_map = {"xs": Namespace.XS.uri} attrs = {QNames.XSI_TYPE: "xs:foo"} self.assertEqual(DataType.STRING, ParserUtils.data_type(attrs, ns_map)) attrs = {QNames.XSI_TYPE: "xs:float"} self.assertEqual(DataType.FLOAT, ParserUtils.data_type(attrs, ns_map))
def parse_element(self, element: Element, objects: List[Any]) -> Tuple: """ Parse the given element attributes/text/tail, find all child objects and mixed content and initialize a new generic element instance. :return: A tuple of the object's qualified name and a new :class:`xsdata.formats.dataclass.models.generics.AnyElement` instance. """ obj = ParserUtils.parse_any_element(element) obj.children = ParserUtils.fetch_any_children(self.position, objects) return self.qname, obj
def test_parse_value_with_ns_map(self, mock_to_python): ns_map = dict(a=1) ParserUtils.parse_value(" 1 2 3", [int], list, ns_map, True) ParserUtils.parse_value(" 1 2 3", [str], None, ns_map, False) self.assertEqual(4, mock_to_python.call_count) mock_to_python.assert_has_calls([ mock.call("1", [int], ns_map=ns_map, format=None), mock.call("2", [int], ns_map=ns_map, format=None), mock.call("3", [int], ns_map=ns_map, format=None), mock.call(" 1 2 3", [str], ns_map=ns_map, format=None), ])
def test_bind_attrs_ignore_init_false_vars(self): metadata = self.ctx.build(ProductType) eff_date = metadata.find_var("effDate") metadata.vars.remove(eff_date) metadata.vars.append(replace(eff_date, init=False, xml_type=None)) params = {} attrs = {"effDate": "2020-03-01"} ns_map = {} ParserUtils.bind_attrs(params, metadata, attrs, ns_map) self.assertEqual({"other_attributes": {}}, params)
def test_bind_elements_attrs_ignore_init_false_vars(self): metadata = self.ctx.build(ProductType) eff_date = metadata.find_var("effDate") metadata.vars.remove(eff_date) metadata.vars.append(replace(eff_date, init=False)) element = Element("foo") element.set("effDate", "2020-03-01") params = {} ParserUtils.bind_element_attrs(params, metadata, element) self.assertEqual({}, params)
def test_bind_content(self, mock_parse_value): metadata = self.ctx.build(SizeType) var = metadata.find_var(mode=FindMode.TEXT) params = {} ns_map = {"a": "b"} self.assertFalse(ParserUtils.bind_content(params, metadata, None, ns_map)) self.assertEqual({}, params) self.assertTrue(ParserUtils.bind_content(params, metadata, "foo", ns_map)) self.assertEqual({"value": "yes!"}, params) mock_parse_value.assert_called_once_with( "foo", var.types, var.default, ns_map, var.list_element )
def test_bind_element_text_with_text_var(self, mock_parse_value): element = Element("foo") params = {} metadata = self.ctx.build(SizeType) var = metadata.find_var(mode=FindMode.TEXT) ParserUtils.bind_element_text(params, metadata, element) self.assertEqual({}, params) element.text = "foo" ParserUtils.bind_element_text(params, metadata, element) self.assertEqual({"value": "yes!"}, params) mock_parse_value.assert_called_once_with( var.types, element.text, var.default, element.nsmap, var.is_list, )
def parse_value(cls, value: Any, var: XmlVar) -> Any: """Convert any value to one of the given var types.""" return ParserUtils.parse_value(value, var.types, var.default, ns_map=EMPTY_MAP, tokens=var.tokens)
def next_node(self, element: Element, position: int, ctx: XmlContext) -> XmlNode: """ Initialize the next node to be queued for the given starting element. Search by the given element tag for a matching variable and create the next node by the variable type. :return: The next node to be queued. :raises: XmlContextError if the element is unknown and parser config is strict. """ qname = QName(element.tag) var = self.meta.find_var(qname, FindMode.NOT_WILDCARD) if not var: var = self.meta.find_var(qname, FindMode.WILDCARD) if not var: if self.config.fail_on_unknown_properties: raise XmlContextError( f"{self.meta.qname} does not support mixed content: {qname}" ) return SkipNode(position=position) if var.clazz: xsi_type = ParserUtils.parse_xsi_type(element) meta = ctx.fetch(var.clazz, self.meta.qname.namespace, xsi_type) return ElementNode(position=position, meta=meta, config=self.config) if var.is_any_type: return WildcardNode(position=position, qname=var.qname) return PrimitiveNode(position=position, var=var)