1# -*- coding: utf-8 -*- 2#-------------------------------------------------------------------------- 3# 4# Copyright (c) Microsoft Corporation. All rights reserved. 5# 6# The MIT License (MIT) 7# 8# Permission is hereby granted, free of charge, to any person obtaining a copy 9# of this software and associated documentation files (the ""Software""), to deal 10# in the Software without restriction, including without limitation the rights 11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12# copies of the Software, and to permit persons to whom the Software is 13# furnished to do so, subject to the following conditions: 14# 15# The above copyright notice and this permission notice shall be included in 16# all copies or substantial portions of the Software. 17# 18# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24# THE SOFTWARE. 25# 26#-------------------------------------------------------------------------- 27import sys 28import xml.etree.ElementTree as ET 29 30import pytest 31 32from msrest.serialization import Serializer, Deserializer, Model, xml_key_extractor 33 34 35def assert_xml_equals(x1, x2): 36 print("--------X1--------") 37 ET.dump(x1) 38 print("--------X2--------") 39 ET.dump(x2) 40 41 assert x1.tag == x2.tag 42 assert (x1.text or "").strip() == (x2.text or "").strip() 43 # assert x1.tail == x2.tail # Swagger does not change tail 44 assert x1.attrib == x2.attrib 45 assert len(x1) == len(x2) 46 for c1, c2 in zip(x1, x2): 47 assert_xml_equals(c1, c2) 48 49class TestXmlDeserialization: 50 51 def test_basic(self): 52 """Test an ultra basic XML.""" 53 basic_xml = """<?xml version="1.0"?> 54 <Data country="france"> 55 <Long>12</Long> 56 <EmptyLong/> 57 <Age>37</Age> 58 <EmptyAge/> 59 <EmptyString/> 60 </Data>""" 61 62 class XmlModel(Model): 63 _attribute_map = { 64 'longnode': {'key': 'longnode', 'type': 'long', 'xml':{'name': 'Long'}}, 65 'empty_long': {'key': 'empty_long', 'type': 'long', 'xml':{'name': 'EmptyLong'}}, 66 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age'}}, 67 'empty_age': {'key': 'empty_age', 'type': 'int', 'xml':{'name': 'EmptyAge'}}, 68 'empty_string': {'key': 'empty_string', 'type': 'str', 'xml':{'name': 'EmptyString'}}, 69 'not_set': {'key': 'not_set', 'type': 'str', 'xml':{'name': 'NotSet'}}, 70 'country': {'key': 'country', 'type': 'str', 'xml':{'name': 'country', 'attr': True}}, 71 } 72 _xml_map = { 73 'name': 'Data' 74 } 75 76 s = Deserializer({"XmlModel": XmlModel}) 77 result = s(XmlModel, basic_xml, "application/xml") 78 79 assert result.longnode == 12 80 assert result.empty_long is None 81 assert result.age == 37 82 assert result.empty_age is None 83 assert result.country == "france" 84 assert result.empty_string == "" 85 assert result.not_set is None 86 87 def test_basic_unicode(self): 88 """Test a XML with unicode.""" 89 basic_xml = u"""<?xml version="1.0" encoding="utf-8"?> 90 <Data language="français"/>""" 91 92 class XmlModel(Model): 93 _attribute_map = { 94 'language': {'key': 'language', 'type': 'str', 'xml':{'name': 'language', 'attr': True}}, 95 } 96 _xml_map = { 97 'name': 'Data' 98 } 99 100 s = Deserializer({"XmlModel": XmlModel}) 101 result = s(XmlModel, basic_xml, "application/xml") 102 103 assert result.language == u"français" 104 105 def test_basic_text(self): 106 """Test a XML with unicode.""" 107 basic_xml = u"""<?xml version="1.0" encoding="utf-8"?> 108 <Data language="english">I am text</Data>""" 109 110 class XmlModel(Model): 111 _attribute_map = { 112 'language': {'key': 'language', 'type': 'str', 'xml':{'name': 'language', 'attr': True}}, 113 'content': {'key': 'content', 'type': 'str', 'xml':{'text': True}}, 114 } 115 _xml_map = { 116 'name': 'Data' 117 } 118 119 s = Deserializer({"XmlModel": XmlModel}) 120 result = s(XmlModel, basic_xml, "application/xml") 121 122 assert result.language == "english" 123 assert result.content == "I am text" 124 125 def test_add_prop(self): 126 """Test addProp as a dict. 127 """ 128 basic_xml = """<?xml version="1.0"?> 129 <Data> 130 <Metadata> 131 <Key1>value1</Key1> 132 <Key2>value2</Key2> 133 </Metadata> 134 </Data>""" 135 136 class XmlModel(Model): 137 _attribute_map = { 138 'metadata': {'key': 'Metadata', 'type': '{str}', 'xml': {'name': 'Metadata'}}, 139 } 140 _xml_map = { 141 'name': 'Data' 142 } 143 144 s = Deserializer({"XmlModel": XmlModel}) 145 result = s(XmlModel, basic_xml, "application/xml") 146 147 assert len(result.metadata) == 2 148 assert result.metadata['Key1'] == "value1" 149 assert result.metadata['Key2'] == "value2" 150 151 def test_object(self): 152 basic_xml = """<?xml version="1.0"?> 153 <Data country="france"> 154 <Age>37</Age> 155 </Data>""" 156 157 s = Deserializer() 158 result = s('object', basic_xml, "application/xml") 159 160 # Should be a XML tree 161 assert result.tag == "Data" 162 assert result.get("country") == "france" 163 for child in result: 164 assert child.tag == "Age" 165 assert child.text == "37" 166 167 def test_object_no_text(self): 168 basic_xml = """<?xml version="1.0"?><Data country="france"><Age>37</Age></Data>""" 169 170 s = Deserializer() 171 result = s('object', basic_xml, "application/xml") 172 173 # Should be a XML tree 174 assert result.tag == "Data" 175 assert result.get("country") == "france" 176 for child in result: 177 assert child.tag == "Age" 178 assert child.text == "37" 179 180 def test_basic_empty(self): 181 """Test an basic XML with an empty node.""" 182 basic_xml = """<?xml version="1.0"?> 183 <Data> 184 <Age/> 185 </Data>""" 186 187 class XmlModel(Model): 188 _attribute_map = { 189 'age': {'key': 'age', 'type': 'str', 'xml':{'name': 'Age'}}, 190 } 191 _xml_map = { 192 'name': 'Data' 193 } 194 195 s = Deserializer({"XmlModel": XmlModel}) 196 result = s(XmlModel, basic_xml, "application/xml") 197 198 assert result.age == "" 199 200 def test_basic_empty_list(self): 201 """Test an basic XML with an empty node.""" 202 basic_xml = """<?xml version="1.0"?> 203 <Data/>""" 204 205 class XmlModel(Model): 206 _attribute_map = { 207 'age': {'key': 'age', 'type': 'str', 'xml':{'name': 'Age'}}, 208 } 209 _xml_map = { 210 'name': 'Data' 211 } 212 213 s = Deserializer({"XmlModel": XmlModel}) 214 result = s('[XmlModel]', basic_xml, "application/xml") 215 216 assert result == [] 217 218 def test_list_wrapped_items_name_basic_types(self): 219 """Test XML list and wrap, items is basic type and there is itemsName. 220 """ 221 222 basic_xml = """<?xml version="1.0"?> 223 <AppleBarrel> 224 <GoodApples> 225 <Apple>granny</Apple> 226 <Apple>fuji</Apple> 227 </GoodApples> 228 </AppleBarrel>""" 229 230 class AppleBarrel(Model): 231 _attribute_map = { 232 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples', 'wrapped': True, 'itemsName': 'Apple'}}, 233 } 234 _xml_map = { 235 'name': 'AppleBarrel' 236 } 237 238 s = Deserializer({"AppleBarrel": AppleBarrel}) 239 result = s(AppleBarrel, basic_xml, "application/xml") 240 241 assert result.good_apples == ["granny", "fuji"] 242 243 def test_list_not_wrapped_items_name_basic_types(self): 244 """Test XML list and no wrap, items is basic type and there is itemsName. 245 """ 246 247 basic_xml = """<?xml version="1.0"?> 248 <AppleBarrel> 249 <Apple>granny</Apple> 250 <Apple>fuji</Apple> 251 </AppleBarrel>""" 252 253 class AppleBarrel(Model): 254 _attribute_map = { 255 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples', 'itemsName': 'Apple'}}, 256 } 257 _xml_map = { 258 'name': 'AppleBarrel' 259 } 260 261 s = Deserializer({"AppleBarrel": AppleBarrel}) 262 result = s(AppleBarrel, basic_xml, "application/xml") 263 264 assert result.good_apples == ["granny", "fuji"] 265 266 def test_list_wrapped_basic_types(self): 267 """Test XML list and wrap, items is basic type and there is no itemsName. 268 """ 269 270 basic_xml = """<?xml version="1.0"?> 271 <AppleBarrel> 272 <GoodApples> 273 <GoodApples>granny</GoodApples> 274 <GoodApples>fuji</GoodApples> 275 </GoodApples> 276 </AppleBarrel>""" 277 278 class AppleBarrel(Model): 279 _attribute_map = { 280 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 281 } 282 _xml_map = { 283 'name': 'AppleBarrel' 284 } 285 286 s = Deserializer({"AppleBarrel": AppleBarrel}) 287 result = s(AppleBarrel, basic_xml, "application/xml") 288 289 assert result.good_apples == ["granny", "fuji"] 290 291 def test_list_not_wrapped_basic_types(self): 292 """Test XML list and no wrap, items is basic type and there is no itemsName. 293 """ 294 295 basic_xml = """<?xml version="1.0"?> 296 <AppleBarrel> 297 <GoodApples>granny</GoodApples> 298 <GoodApples>fuji</GoodApples> 299 </AppleBarrel>""" 300 301 class AppleBarrel(Model): 302 _attribute_map = { 303 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples'}}, 304 } 305 _xml_map = { 306 'name': 'AppleBarrel' 307 } 308 309 s = Deserializer({"AppleBarrel": AppleBarrel}) 310 result = s(AppleBarrel, basic_xml, "application/xml") 311 312 assert result.good_apples == ["granny", "fuji"] 313 314 315 def test_list_wrapped_items_name_complex_types(self): 316 """Test XML list and wrap, items is ref and there is itemsName. 317 """ 318 319 basic_xml = """<?xml version="1.0"?> 320 <AppleBarrel> 321 <GoodApples> 322 <Apple name="granny"/> 323 <Apple name="fuji"/> 324 </GoodApples> 325 </AppleBarrel>""" 326 327 class AppleBarrel(Model): 328 _attribute_map = { 329 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True, 'itemsName': 'Apple'}}, 330 } 331 _xml_map = { 332 'name': 'AppleBarrel' 333 } 334 335 class Apple(Model): 336 _attribute_map = { 337 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 338 } 339 _xml_map = { 340 'name': 'Pomme' # Should be ignored, since "itemsName" is defined 341 } 342 343 s = Deserializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 344 result = s('AppleBarrel', basic_xml, "application/xml") 345 346 assert [apple.name for apple in result.good_apples] == ["granny", "fuji"] 347 348 def test_list_not_wrapped_items_name_complex_types(self): 349 """Test XML list and wrap, items is ref and there is itemsName. 350 """ 351 352 basic_xml = """<?xml version="1.0"?> 353 <AppleBarrel> 354 <Apple name="granny"/> 355 <Apple name="fuji"/> 356 </AppleBarrel>""" 357 358 class AppleBarrel(Model): 359 _attribute_map = { 360 # Pomme should be ignored, since it's invalid to define itemsName for a $ref type 361 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'itemsName': 'Pomme'}}, 362 } 363 _xml_map = { 364 'name': 'AppleBarrel' 365 } 366 367 class Apple(Model): 368 _attribute_map = { 369 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 370 } 371 _xml_map = { 372 'name': 'Apple' 373 } 374 375 s = Deserializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 376 result = s(AppleBarrel, basic_xml, "application/xml") 377 378 assert [apple.name for apple in result.good_apples] == ["granny", "fuji"] 379 380 def test_list_wrapped_complex_types(self): 381 """Test XML list and wrap, items is ref and there is no itemsName. 382 """ 383 384 basic_xml = """<?xml version="1.0"?> 385 <AppleBarrel> 386 <GoodApples> 387 <Apple name="granny"/> 388 <Apple name="fuji"/> 389 </GoodApples> 390 </AppleBarrel>""" 391 392 class AppleBarrel(Model): 393 _attribute_map = { 394 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 395 } 396 _xml_map = { 397 'name': 'AppleBarrel' 398 } 399 400 class Apple(Model): 401 _attribute_map = { 402 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 403 } 404 _xml_map = { 405 'name': 'Apple' 406 } 407 408 s = Deserializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 409 result = s(AppleBarrel, basic_xml, "application/xml") 410 411 assert [apple.name for apple in result.good_apples] == ["granny", "fuji"] 412 413 def test_list_not_wrapped_complex_types(self): 414 """Test XML list and wrap, items is ref and there is no itemsName. 415 """ 416 417 basic_xml = """<?xml version="1.0"?> 418 <AppleBarrel> 419 <Apple name="granny"/> 420 <Apple name="fuji"/> 421 </AppleBarrel>""" 422 423 class AppleBarrel(Model): 424 _attribute_map = { 425 # Name is ignored if wrapped is False 426 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples'}}, 427 } 428 _xml_map = { 429 'name': 'AppleBarrel' 430 } 431 432 class Apple(Model): 433 _attribute_map = { 434 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 435 } 436 _xml_map = { 437 'name': 'Apple' 438 } 439 440 s = Deserializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 441 result = s(AppleBarrel, basic_xml, "application/xml") 442 443 assert [apple.name for apple in result.good_apples] == ["granny", "fuji"] 444 445 def test_basic_additional_properties(self): 446 """Test an ultra basic XML.""" 447 basic_xml = """<?xml version="1.0"?> 448 <Metadata> 449 <number>1</number> 450 <name>bob</name> 451 </Metadata>""" 452 453 class XmlModel(Model): 454 455 _attribute_map = { 456 'additional_properties': {'key': '', 'type': '{str}', 'xml': {'name': 'additional_properties'}}, 457 'encrypted': {'key': 'Encrypted', 'type': 'str', 'xml': {'name': 'Encrypted', 'attr': True}}, 458 } 459 _xml_map = { 460 'name': 'Metadata' 461 } 462 463 def __init__(self, **kwargs): 464 super(XmlModel, self).__init__(**kwargs) 465 self.additional_properties = kwargs.get('additional_properties', None) 466 self.encrypted = kwargs.get('encrypted', None) 467 468 s = Deserializer({"XmlModel": XmlModel}) 469 result = s(XmlModel, basic_xml, "application/xml") 470 471 assert result.additional_properties == {'name': 'bob', 'number': '1'} 472 assert result.encrypted is None 473 474 def test_basic_namespace(self): 475 """Test an ultra basic XML.""" 476 basic_xml = """<?xml version="1.0"?> 477 <Data xmlns:fictional="http://characters.example.com"> 478 <fictional:Age>37</fictional:Age> 479 </Data>""" 480 481 class XmlModel(Model): 482 _attribute_map = { 483 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age', 'prefix':'fictional','ns':'http://characters.example.com'}}, 484 } 485 _xml_map = { 486 'name': 'Data' 487 } 488 489 s = Deserializer({"XmlModel": XmlModel}) 490 result = s(XmlModel, basic_xml, "application/xml") 491 492 assert result.age == 37 493 494 def test_complex_namespace(self): 495 """Test recursive namespace.""" 496 basic_xml = """<?xml version="1.0"?> 497 <entry xmlns="http://www.w3.org/2005/Atom" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 498 <author> 499 <name>lmazuel</name> 500 </author> 501 <AuthorizationRules xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"> 502 <AuthorizationRule i:type="SharedAccessAuthorizationRule"> 503 <KeyName>testpolicy</KeyName> 504 </AuthorizationRule> 505 </AuthorizationRules> 506 <CountDetails xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"> 507 <d2p1:ActiveMessageCount xmlns:d2p1="http://schemas.microsoft.com/netservices/2011/06/servicebus">12</d2p1:ActiveMessageCount> 508 </CountDetails> 509 </entry>""" 510 511 class XmlRoot(Model): 512 _attribute_map = { 513 'author': {'key': 'author', 'type': 'QueueDescriptionResponseAuthor'}, 514 'authorization_rules': {'key': 'AuthorizationRules', 'type': '[AuthorizationRule]', 'xml': {'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect', 'wrapped': True, 'itemsNs': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect'}}, 515 'message_count_details': {'key': 'MessageCountDetails', 'type': 'MessageCountDetails'}, 516 } 517 _xml_map = { 518 'name': 'entry', 'ns': 'http://www.w3.org/2005/Atom' 519 } 520 521 class QueueDescriptionResponseAuthor(Model): 522 _attribute_map = { 523 'name': {'key': 'name', 'type': 'str', 'xml': {'ns': 'http://www.w3.org/2005/Atom'}}, 524 } 525 _xml_map = { 526 'ns': 'http://www.w3.org/2005/Atom' 527 } 528 529 class AuthorizationRule(Model): 530 _attribute_map = { 531 'type': {'key': 'type', 'type': 'str', 'xml': {'attr': True, 'prefix': 'i', 'ns': 'http://www.w3.org/2001/XMLSchema-instance'}}, 532 'key_name': {'key': 'KeyName', 'type': 'str', 'xml': {'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect'}}, 533 } 534 _xml_map = { 535 'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect' 536 } 537 538 class MessageCountDetails(Model): 539 _attribute_map = { 540 'active_message_count': {'key': 'ActiveMessageCount', 'type': 'int', 'xml': {'prefix': 'd2p1', 'ns': 'http://schemas.microsoft.com/netservices/2011/06/servicebus'}}, 541 } 542 _xml_map = { 543 'name': 'CountDetails', 'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect' 544 } 545 546 547 s = Deserializer({ 548 "XmlRoot": XmlRoot, 549 "QueueDescriptionResponseAuthor": QueueDescriptionResponseAuthor, 550 "AuthorizationRule": AuthorizationRule, 551 "MessageCountDetails": MessageCountDetails, 552 }) 553 result = s(XmlRoot, basic_xml, "application/xml") 554 555 assert result.author.name == "lmazuel" 556 assert result.authorization_rules[0].key_name == "testpolicy" 557 assert result.authorization_rules[0].type == "SharedAccessAuthorizationRule" 558 assert result.message_count_details.active_message_count == 12 559 560 def test_polymorphic_deserialization(self): 561 562 basic_xml = """<?xml version="1.0"?> 563 <entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 564 <Filter xsi:type="CorrelationFilter"> 565 <CorrelationId>12</CorrelationId> 566 </Filter> 567 </entry>""" 568 569 class XmlRoot(Model): 570 _attribute_map = { 571 'filter': {'key': 'Filter', 'type': 'RuleFilter'}, 572 } 573 _xml_map = { 574 'name': 'entry' 575 } 576 577 class RuleFilter(Model): 578 _attribute_map = { 579 'type': {'key': 'type', 'type': 'str', 'xml': {'attr': True, 'prefix': 'xsi', 'ns': 'http://www.w3.org/2001/XMLSchema-instance'}}, 580 } 581 582 _subtype_map = { 583 'type': {'CorrelationFilter': 'CorrelationFilter', 'SqlFilter': 'SqlFilter'} 584 } 585 _xml_map = { 586 'name': 'Filter' 587 } 588 589 class CorrelationFilter(RuleFilter): 590 _attribute_map = { 591 'type': {'key': 'type', 'type': 'str', 'xml': {'attr': True, 'prefix': 'xsi', 'ns': 'http://www.w3.org/2001/XMLSchema-instance'}}, 592 'correlation_id': {'key': 'CorrelationId', 'type': 'int'}, 593 } 594 595 def __init__( 596 self, 597 correlation_id = None, 598 **kwargs 599 ): 600 super(CorrelationFilter, self).__init__(**kwargs) 601 self.type = 'CorrelationFilter' 602 self.correlation_id = correlation_id 603 604 class SqlFilter(RuleFilter): 605 _attribute_map = { 606 'type': {'key': 'type', 'type': 'str', 'xml': {'attr': True, 'prefix': 'xsi', 'ns': 'http://www.w3.org/2001/XMLSchema-instance'}}, 607 } 608 609 def __init__( 610 self, 611 **kwargs 612 ): 613 pytest.fail("Don't instantiate me") 614 615 s = Deserializer({ 616 "XmlRoot": XmlRoot, 617 "RuleFilter": RuleFilter, 618 "SqlFilter": SqlFilter, 619 "CorrelationFilter": CorrelationFilter, 620 }) 621 result = s(XmlRoot, basic_xml, "application/xml") 622 623 assert isinstance(result.filter, CorrelationFilter) 624 assert result.filter.correlation_id == 12 625 626 627class TestXmlSerialization: 628 629 def test_basic(self): 630 """Test an ultra basic XML.""" 631 basic_xml = ET.fromstring("""<?xml version="1.0"?> 632 <Data country="france"> 633 <Age>37</Age> 634 </Data>""") 635 636 class XmlModel(Model): 637 _attribute_map = { 638 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age'}}, 639 'country': {'key': 'country', 'type': 'str', 'xml':{'name': 'country', 'attr': True}}, 640 } 641 _xml_map = { 642 'name': 'Data' 643 } 644 645 mymodel = XmlModel( 646 age=37, 647 country="france" 648 ) 649 650 s = Serializer({"XmlModel": XmlModel}) 651 rawxml = s.body(mymodel, 'XmlModel') 652 653 assert_xml_equals(rawxml, basic_xml) 654 655 def test_basic_unicode(self): 656 """Test a XML with unicode.""" 657 basic_xml = ET.fromstring(u"""<?xml version="1.0" encoding="utf-8"?> 658 <Data language="français"/>""".encode("utf-8")) 659 660 class XmlModel(Model): 661 _attribute_map = { 662 'language': {'key': 'language', 'type': 'str', 'xml':{'name': 'language', 'attr': True}}, 663 } 664 _xml_map = { 665 'name': 'Data' 666 } 667 668 mymodel = XmlModel( 669 language=u"français" 670 ) 671 672 s = Serializer({"XmlModel": XmlModel}) 673 rawxml = s.body(mymodel, 'XmlModel') 674 675 assert_xml_equals(rawxml, basic_xml) 676 677 def test_nested_unicode(self): 678 679 class XmlModel(Model): 680 _attribute_map = { 681 'message_text': {'key': 'MessageText', 'type': 'str', 'xml': {'name': 'MessageText'}}, 682 } 683 684 _xml_map = { 685 'name': 'Message' 686 } 687 688 mymodel_no_unicode = XmlModel(message_text=u'message1') 689 s = Serializer({"XmlModel": XmlModel}) 690 body = s.body(mymodel_no_unicode, 'XmlModel') 691 xml_content = ET.tostring(body, encoding="utf8") 692 assert xml_content == b"<?xml version='1.0' encoding='utf8'?>\n<Message><MessageText>message1</MessageText></Message>" 693 694 mymodel_with_unicode = XmlModel(message_text=u'message1㚈') 695 s = Serializer({"XmlModel": XmlModel}) 696 body = s.body(mymodel_with_unicode, 'XmlModel') 697 xml_content = ET.tostring(body, encoding="utf8") 698 assert xml_content == b"<?xml version='1.0' encoding='utf8'?>\n<Message><MessageText>message1\xe3\x9a\x88</MessageText></Message>" 699 700 @pytest.mark.skipif(sys.version_info < (3,6), 701 reason="Dict ordering not guaranted before 3.6, makes this complicated to test.") 702 def test_add_prop(self): 703 """Test addProp as a dict. 704 """ 705 basic_xml = ET.fromstring("""<?xml version="1.0"?> 706 <Data> 707 <Metadata> 708 <Key1>value1</Key1> 709 <Key2>value2</Key2> 710 </Metadata> 711 </Data>""") 712 713 class XmlModel(Model): 714 _attribute_map = { 715 'metadata': {'key': 'Metadata', 'type': '{str}', 'xml': {'name': 'Metadata'}}, 716 } 717 _xml_map = { 718 'name': 'Data' 719 } 720 721 mymodel = XmlModel( 722 metadata={ 723 'Key1': 'value1', 724 'Key2': 'value2', 725 } 726 ) 727 728 s = Serializer({"XmlModel": XmlModel}) 729 rawxml = s.body(mymodel, 'XmlModel') 730 731 assert_xml_equals(rawxml, basic_xml) 732 733 def test_object(self): 734 """Test serialize object as is. 735 """ 736 basic_xml = ET.fromstring("""<?xml version="1.0"?> 737 <Data country="france"> 738 <Age>37</Age> 739 </Data>""") 740 741 s = Serializer() 742 rawxml = s.body(basic_xml, 'object') 743 744 # It should actually be the same object, should not even try to touch it 745 assert rawxml is basic_xml 746 747 @pytest.mark.skipif(sys.version_info < (3,6), 748 reason="Unstable before python3.6 for some reasons") 749 def test_type_basic(self): 750 """Test some types.""" 751 basic_xml = ET.fromstring("""<?xml version="1.0"?> 752 <Data> 753 <Age>37</Age> 754 <Enabled>true</Enabled> 755 </Data>""") 756 757 class XmlModel(Model): 758 _attribute_map = { 759 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age'}}, 760 'enabled': {'key': 'enabled', 'type': 'bool', 'xml':{'name': 'Enabled'}}, 761 } 762 _xml_map = { 763 'name': 'Data' 764 } 765 766 mymodel = XmlModel( 767 age=37, 768 enabled=True 769 ) 770 771 s = Serializer({"XmlModel": XmlModel}) 772 rawxml = s.body(mymodel, 'XmlModel') 773 774 assert_xml_equals(rawxml, basic_xml) 775 776 def test_basic_text(self): 777 """Test a XML with unicode.""" 778 basic_xml = ET.fromstring("""<?xml version="1.0" encoding="utf-8"?> 779 <Data language="english">I am text</Data>""") 780 781 class XmlModel(Model): 782 _attribute_map = { 783 'language': {'key': 'language', 'type': 'str', 'xml':{'name': 'language', 'attr': True}}, 784 'content': {'key': 'content', 'type': 'str', 'xml':{'text': True}}, 785 } 786 _xml_map = { 787 'name': 'Data' 788 } 789 790 mymodel = XmlModel( 791 language="english", 792 content="I am text" 793 ) 794 795 s = Serializer({"XmlModel": XmlModel}) 796 rawxml = s.body(mymodel, 'XmlModel') 797 798 assert_xml_equals(rawxml, basic_xml) 799 800 801 def test_direct_array(self): 802 """Test an ultra basic XML.""" 803 basic_xml = ET.fromstring("""<?xml version="1.0"?> 804 <bananas> 805 <Data country="france"/> 806 </bananas> 807 """) 808 809 class XmlModel(Model): 810 _attribute_map = { 811 'country': {'key': 'country', 'type': 'str', 'xml':{'name': 'country', 'attr': True}}, 812 } 813 _xml_map = { 814 'name': 'Data' 815 } 816 817 mymodel = XmlModel( 818 country="france" 819 ) 820 821 s = Serializer({"XmlModel": XmlModel}) 822 rawxml = s.body( 823 [mymodel], 824 '[XmlModel]', 825 serialization_ctxt={'xml': {'name': 'bananas', 'wrapped': True}} 826 ) 827 828 assert_xml_equals(rawxml, basic_xml) 829 830 def test_list_wrapped_basic_types(self): 831 """Test XML list and wrap, items is basic type and there is no itemsName. 832 """ 833 834 basic_xml = ET.fromstring("""<?xml version="1.0"?> 835 <AppleBarrel> 836 <GoodApples> 837 <GoodApples>granny</GoodApples> 838 <GoodApples>fuji</GoodApples> 839 </GoodApples> 840 </AppleBarrel>""") 841 842 class AppleBarrel(Model): 843 _attribute_map = { 844 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 845 } 846 _xml_map = { 847 'name': 'AppleBarrel' 848 } 849 850 mymodel = AppleBarrel( 851 good_apples=['granny', 'fuji'] 852 ) 853 854 s = Serializer({"AppleBarrel": AppleBarrel}) 855 rawxml = s.body(mymodel, 'AppleBarrel') 856 857 assert_xml_equals(rawxml, basic_xml) 858 859 def test_list_not_wrapped_basic_types(self): 860 """Test XML list and no wrap, items is basic type and there is no itemsName. 861 """ 862 863 basic_xml = ET.fromstring("""<?xml version="1.0"?> 864 <AppleBarrel> 865 <GoodApples>granny</GoodApples> 866 <GoodApples>fuji</GoodApples> 867 </AppleBarrel>""") 868 869 class AppleBarrel(Model): 870 _attribute_map = { 871 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples'}}, 872 } 873 _xml_map = { 874 'name': 'AppleBarrel' 875 } 876 877 mymodel = AppleBarrel( 878 good_apples=['granny', 'fuji'] 879 ) 880 881 s = Serializer({"AppleBarrel": AppleBarrel}) 882 rawxml = s.body(mymodel, 'AppleBarrel') 883 884 assert_xml_equals(rawxml, basic_xml) 885 886 def test_list_wrapped_items_name_complex_types(self): 887 """Test XML list and wrap, items is ref and there is itemsName. 888 """ 889 890 basic_xml = ET.fromstring("""<?xml version="1.0"?> 891 <AppleBarrel> 892 <GoodApples> 893 <Apple name="granny"/> 894 <Apple name="fuji"/> 895 </GoodApples> 896 </AppleBarrel>""") 897 898 class AppleBarrel(Model): 899 _attribute_map = { 900 # Pomme should be ignored, since it's invalid to define itemsName for a $ref type 901 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True, 'itemsName': 'Pomme'}}, 902 } 903 _xml_map = { 904 'name': 'AppleBarrel' 905 } 906 907 class Apple(Model): 908 _attribute_map = { 909 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 910 } 911 _xml_map = { 912 'name': 'Apple' 913 } 914 915 mymodel = AppleBarrel( 916 good_apples=[ 917 Apple(name='granny'), 918 Apple(name='fuji') 919 ] 920 ) 921 922 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 923 rawxml = s.body(mymodel, 'AppleBarrel') 924 925 assert_xml_equals(rawxml, basic_xml) 926 927 def test_list_not_wrapped_items_name_complex_types(self): 928 """Test XML list and wrap, items is ref and there is itemsName. 929 """ 930 931 basic_xml = ET.fromstring("""<?xml version="1.0"?> 932 <AppleBarrel> 933 <Apple name="granny"/> 934 <Apple name="fuji"/> 935 </AppleBarrel>""") 936 937 class AppleBarrel(Model): 938 _attribute_map = { 939 # Pomme should be ignored, since it's invalid to define itemsName for a $ref type 940 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'itemsName': 'Pomme'}}, 941 } 942 _xml_map = { 943 'name': 'AppleBarrel' 944 } 945 946 class Apple(Model): 947 _attribute_map = { 948 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 949 } 950 _xml_map = { 951 'name': 'Apple' 952 } 953 954 mymodel = AppleBarrel( 955 good_apples=[ 956 Apple(name='granny'), 957 Apple(name='fuji') 958 ] 959 ) 960 961 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 962 rawxml = s.body(mymodel, 'AppleBarrel') 963 964 assert_xml_equals(rawxml, basic_xml) 965 966 def test_list_wrapped_complex_types(self): 967 """Test XML list and wrap, items is ref and there is no itemsName. 968 """ 969 970 basic_xml = ET.fromstring("""<?xml version="1.0"?> 971 <AppleBarrel> 972 <GoodApples> 973 <Apple name="granny"/> 974 <Apple name="fuji"/> 975 </GoodApples> 976 </AppleBarrel>""") 977 978 class AppleBarrel(Model): 979 _attribute_map = { 980 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 981 } 982 _xml_map = { 983 'name': 'AppleBarrel' 984 } 985 986 class Apple(Model): 987 _attribute_map = { 988 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 989 } 990 _xml_map = { 991 'name': 'Apple' 992 } 993 994 mymodel = AppleBarrel( 995 good_apples=[ 996 Apple(name='granny'), 997 Apple(name='fuji') 998 ] 999 ) 1000 1001 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1002 rawxml = s.body(mymodel, 'AppleBarrel') 1003 1004 assert_xml_equals(rawxml, basic_xml) 1005 1006 def test_list_not_wrapped_complex_types(self): 1007 """Test XML list and wrap, items is ref and there is no itemsName. 1008 """ 1009 1010 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1011 <AppleBarrel> 1012 <Apple name="granny"/> 1013 <Apple name="fuji"/> 1014 </AppleBarrel>""") 1015 1016 class AppleBarrel(Model): 1017 _attribute_map = { 1018 # Name is ignored if "wrapped" is False 1019 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples'}}, 1020 } 1021 _xml_map = { 1022 'name': 'AppleBarrel' 1023 } 1024 1025 class Apple(Model): 1026 _attribute_map = { 1027 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1028 } 1029 _xml_map = { 1030 'name': 'Apple' 1031 } 1032 1033 mymodel = AppleBarrel( 1034 good_apples=[ 1035 Apple(name='granny'), 1036 Apple(name='fuji') 1037 ] 1038 ) 1039 1040 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1041 rawxml = s.body(mymodel, 'AppleBarrel') 1042 1043 assert_xml_equals(rawxml, basic_xml) 1044 1045 @pytest.mark.skipif(sys.version_info < (3,6), 1046 reason="Unstable before python3.6 for some reasons") 1047 def test_two_complex_same_type(self): 1048 """Two different attribute are same type 1049 """ 1050 1051 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1052 <AppleBarrel> 1053 <EuropeanApple name="granny"/> 1054 <USAApple name="fuji"/> 1055 </AppleBarrel>""") 1056 1057 class AppleBarrel(Model): 1058 _attribute_map = { 1059 'eu_apple': {'key': 'EuropeanApple', 'type': 'Apple', 'xml': {'name': 'EuropeanApple'}}, 1060 'us_apple': {'key': 'USAApple', 'type': 'Apple', 'xml': {'name': 'USAApple'}}, 1061 } 1062 _xml_map = { 1063 'name': 'AppleBarrel' 1064 } 1065 1066 class Apple(Model): 1067 _attribute_map = { 1068 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1069 } 1070 _xml_map = { 1071 } 1072 1073 mymodel = AppleBarrel( 1074 eu_apple=Apple(name='granny'), 1075 us_apple=Apple(name='fuji'), 1076 ) 1077 1078 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1079 rawxml = s.body(mymodel, 'AppleBarrel') 1080 1081 assert_xml_equals(rawxml, basic_xml) 1082 1083 1084 def test_basic_namespace(self): 1085 """Test an ultra basic XML.""" 1086 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1087 <Data xmlns:fictional="http://characters.example.com"> 1088 <fictional:Age>37</fictional:Age> 1089 </Data>""") 1090 1091 class XmlModel(Model): 1092 _attribute_map = { 1093 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age', 'prefix':'fictional','ns':'http://characters.example.com'}}, 1094 } 1095 _xml_map = { 1096 'name': 'Data' 1097 } 1098 1099 mymodel = XmlModel( 1100 age=37, 1101 ) 1102 1103 s = Serializer({"XmlModel": XmlModel}) 1104 rawxml = s.body(mymodel, 'XmlModel') 1105 1106 assert_xml_equals(rawxml, basic_xml) 1107 1108 def test_basic_is_xml(self): 1109 """Test an ultra basic XML.""" 1110 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1111 <Data country="france"> 1112 <Age>37</Age> 1113 </Data>""") 1114 1115 class XmlModel(Model): 1116 _attribute_map = { 1117 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age'}}, 1118 'country': {'key': 'country', 'type': 'str', 'xml':{'name': 'country', 'attr': True}}, 1119 } 1120 _xml_map = { 1121 'name': 'Data' 1122 } 1123 1124 mymodel = XmlModel( 1125 age=37, 1126 country="france", 1127 ) 1128 1129 s = Serializer({"XmlModel": XmlModel}) 1130 rawxml = s.body(mymodel, 'XmlModel', is_xml=True) 1131 1132 assert_xml_equals(rawxml, basic_xml) 1133 1134 def test_basic_unicode_is_xml(self): 1135 """Test a XML with unicode.""" 1136 basic_xml = ET.fromstring(u"""<?xml version="1.0" encoding="utf-8"?> 1137 <Data language="français"/>""".encode("utf-8")) 1138 1139 class XmlModel(Model): 1140 _attribute_map = { 1141 'language': {'key': 'language', 'type': 'str', 'xml':{'name': 'language', 'attr': True}}, 1142 } 1143 _xml_map = { 1144 'name': 'Data' 1145 } 1146 1147 mymodel = XmlModel( 1148 language=u"français" 1149 ) 1150 1151 s = Serializer({"XmlModel": XmlModel}) 1152 rawxml = s.body(mymodel, 'XmlModel', is_xml=True) 1153 1154 assert_xml_equals(rawxml, basic_xml) 1155 1156 1157 @pytest.mark.skipif(sys.version_info < (3,6), 1158 reason="Dict ordering not guaranted before 3.6, makes this complicated to test.") 1159 def test_add_prop_is_xml(self): 1160 """Test addProp as a dict. 1161 """ 1162 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1163 <Data> 1164 <Metadata> 1165 <Key1>value1</Key1> 1166 <Key2>value2</Key2> 1167 </Metadata> 1168 </Data>""") 1169 1170 class XmlModel(Model): 1171 _attribute_map = { 1172 'metadata': {'key': 'Metadata', 'type': '{str}', 'xml': {'name': 'Metadata'}}, 1173 } 1174 _xml_map = { 1175 'name': 'Data' 1176 } 1177 1178 mymodel = XmlModel( 1179 metadata={ 1180 'Key1': 'value1', 1181 'Key2': 'value2', 1182 } 1183 ) 1184 1185 s = Serializer({"XmlModel": XmlModel}) 1186 rawxml = s.body(mymodel, 'XmlModel', is_xml=True) 1187 1188 assert_xml_equals(rawxml, basic_xml) 1189 1190 def test_object_is_xml(self): 1191 """Test serialize object as is. 1192 """ 1193 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1194 <Data country="france"> 1195 <Age>37</Age> 1196 </Data>""") 1197 1198 s = Serializer() 1199 rawxml = s.body(basic_xml, 'object', is_xml=True) 1200 1201 # It should actually be the same object, should not even try to touch it 1202 assert rawxml is basic_xml 1203 1204 @pytest.mark.skipif(sys.version_info < (3,6), 1205 reason="Unstable before python3.6 for some reasons") 1206 def test_type_basic_is_xml(self): 1207 """Test some types.""" 1208 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1209 <Data> 1210 <Age>37</Age> 1211 <Enabled>true</Enabled> 1212 </Data>""") 1213 1214 class XmlModel(Model): 1215 _attribute_map = { 1216 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age'}}, 1217 'enabled': {'key': 'enabled', 'type': 'bool', 'xml':{'name': 'Enabled'}}, 1218 } 1219 _xml_map = { 1220 'name': 'Data' 1221 } 1222 1223 mymodel = XmlModel( 1224 age=37, 1225 enabled=True 1226 ) 1227 1228 s = Serializer({"XmlModel": XmlModel}) 1229 rawxml = s.body(mymodel, 'XmlModel', is_xml=True) 1230 1231 assert_xml_equals(rawxml, basic_xml) 1232 1233 def test_direct_array_is_xml(self): 1234 """Test an ultra basic XML.""" 1235 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1236 <bananas> 1237 <Data country="france"/> 1238 </bananas> 1239 """) 1240 1241 class XmlModel(Model): 1242 _attribute_map = { 1243 'country': {'key': 'country', 'type': 'str', 'xml':{'name': 'country', 'attr': True}}, 1244 } 1245 _xml_map = { 1246 'name': 'Data' 1247 } 1248 1249 mymodel = XmlModel( 1250 country="france" 1251 ) 1252 1253 s = Serializer({"XmlModel": XmlModel}) 1254 rawxml = s.body( 1255 [mymodel], 1256 '[XmlModel]', 1257 serialization_ctxt={'xml': {'name': 'bananas', 'wrapped': True}}, 1258 is_xml=True 1259 ) 1260 1261 assert_xml_equals(rawxml, basic_xml) 1262 1263 def test_list_wrapped_basic_types_is_xml(self): 1264 """Test XML list and wrap, items is basic type and there is no itemsName. 1265 """ 1266 1267 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1268 <AppleBarrel> 1269 <GoodApples> 1270 <GoodApples>granny</GoodApples> 1271 <GoodApples>fuji</GoodApples> 1272 </GoodApples> 1273 </AppleBarrel>""") 1274 1275 class AppleBarrel(Model): 1276 _attribute_map = { 1277 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 1278 } 1279 _xml_map = { 1280 'name': 'AppleBarrel' 1281 } 1282 1283 mymodel = AppleBarrel( 1284 good_apples=['granny', 'fuji'] 1285 ) 1286 1287 s = Serializer({"AppleBarrel": AppleBarrel}) 1288 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1289 1290 assert_xml_equals(rawxml, basic_xml) 1291 1292 def test_list_not_wrapped_basic_types_is_xml(self): 1293 """Test XML list and no wrap, items is basic type and there is no itemsName. 1294 """ 1295 1296 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1297 <AppleBarrel> 1298 <GoodApples>granny</GoodApples> 1299 <GoodApples>fuji</GoodApples> 1300 </AppleBarrel>""") 1301 1302 class AppleBarrel(Model): 1303 _attribute_map = { 1304 'good_apples': {'key': 'GoodApples', 'type': '[str]', 'xml': {'name': 'GoodApples'}}, 1305 } 1306 _xml_map = { 1307 'name': 'AppleBarrel' 1308 } 1309 1310 mymodel = AppleBarrel( 1311 good_apples=['granny', 'fuji'] 1312 ) 1313 1314 s = Serializer({"AppleBarrel": AppleBarrel}) 1315 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1316 1317 assert_xml_equals(rawxml, basic_xml) 1318 1319 def test_list_wrapped_items_name_complex_types_is_xml(self): 1320 """Test XML list and wrap, items is ref and there is itemsName. 1321 """ 1322 1323 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1324 <AppleBarrel> 1325 <GoodApples> 1326 <Apple name="granny"/> 1327 <Apple name="fuji"/> 1328 </GoodApples> 1329 </AppleBarrel>""") 1330 1331 class AppleBarrel(Model): 1332 _attribute_map = { 1333 # Pomme should be ignored, since it's invalid to define itemsName for a $ref type 1334 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True, 'itemsName': 'Pomme'}}, 1335 } 1336 _xml_map = { 1337 'name': 'AppleBarrel' 1338 } 1339 1340 class Apple(Model): 1341 _attribute_map = { 1342 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1343 } 1344 _xml_map = { 1345 'name': 'Apple' 1346 } 1347 1348 mymodel = AppleBarrel( 1349 good_apples=[ 1350 Apple(name='granny'), 1351 Apple(name='fuji') 1352 ] 1353 ) 1354 1355 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1356 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1357 1358 assert_xml_equals(rawxml, basic_xml) 1359 1360 def test_list_not_wrapped_items_name_complex_types_is_xml(self): 1361 """Test XML list and wrap, items is ref and there is itemsName. 1362 """ 1363 1364 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1365 <AppleBarrel> 1366 <Apple name="granny"/> 1367 <Apple name="fuji"/> 1368 </AppleBarrel>""") 1369 1370 class AppleBarrel(Model): 1371 _attribute_map = { 1372 # Pomme should be ignored, since it's invalid to define itemsName for a $ref type 1373 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'itemsName': 'Pomme'}}, 1374 } 1375 _xml_map = { 1376 'name': 'AppleBarrel' 1377 } 1378 1379 class Apple(Model): 1380 _attribute_map = { 1381 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1382 } 1383 _xml_map = { 1384 'name': 'Apple' 1385 } 1386 1387 mymodel = AppleBarrel( 1388 good_apples=[ 1389 Apple(name='granny'), 1390 Apple(name='fuji') 1391 ] 1392 ) 1393 1394 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1395 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1396 1397 assert_xml_equals(rawxml, basic_xml) 1398 1399 def test_list_wrapped_complex_types_is_xml(self): 1400 """Test XML list and wrap, items is ref and there is no itemsName. 1401 """ 1402 1403 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1404 <AppleBarrel> 1405 <GoodApples> 1406 <Apple name="granny"/> 1407 <Apple name="fuji"/> 1408 </GoodApples> 1409 </AppleBarrel>""") 1410 1411 class AppleBarrel(Model): 1412 _attribute_map = { 1413 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples', 'wrapped': True}}, 1414 } 1415 _xml_map = { 1416 'name': 'AppleBarrel' 1417 } 1418 1419 class Apple(Model): 1420 _attribute_map = { 1421 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1422 } 1423 _xml_map = { 1424 'name': 'Apple' 1425 } 1426 1427 mymodel = AppleBarrel( 1428 good_apples=[ 1429 Apple(name='granny'), 1430 Apple(name='fuji') 1431 ] 1432 ) 1433 1434 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1435 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1436 1437 assert_xml_equals(rawxml, basic_xml) 1438 1439 def test_list_not_wrapped_complex_types_is_xml(self): 1440 """Test XML list and wrap, items is ref and there is no itemsName. 1441 """ 1442 1443 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1444 <AppleBarrel> 1445 <Apple name="granny"/> 1446 <Apple name="fuji"/> 1447 </AppleBarrel>""") 1448 1449 class AppleBarrel(Model): 1450 _attribute_map = { 1451 # Name is ignored if "wrapped" is False 1452 'good_apples': {'key': 'GoodApples', 'type': '[Apple]', 'xml': {'name': 'GoodApples'}}, 1453 } 1454 _xml_map = { 1455 'name': 'AppleBarrel' 1456 } 1457 1458 class Apple(Model): 1459 _attribute_map = { 1460 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1461 } 1462 _xml_map = { 1463 'name': 'Apple' 1464 } 1465 1466 mymodel = AppleBarrel( 1467 good_apples=[ 1468 Apple(name='granny'), 1469 Apple(name='fuji') 1470 ] 1471 ) 1472 1473 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1474 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1475 1476 assert_xml_equals(rawxml, basic_xml) 1477 1478 @pytest.mark.skipif(sys.version_info < (3,6), 1479 reason="Unstable before python3.6 for some reasons") 1480 def test_two_complex_same_type_is_xml(self): 1481 """Two different attribute are same type 1482 """ 1483 1484 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1485 <AppleBarrel> 1486 <EuropeanApple name="granny"/> 1487 <USAApple name="fuji"/> 1488 </AppleBarrel>""") 1489 1490 class AppleBarrel(Model): 1491 _attribute_map = { 1492 'eu_apple': {'key': 'EuropeanApple', 'type': 'Apple', 'xml': {'name': 'EuropeanApple'}}, 1493 'us_apple': {'key': 'USAApple', 'type': 'Apple', 'xml': {'name': 'USAApple'}}, 1494 } 1495 _xml_map = { 1496 'name': 'AppleBarrel' 1497 } 1498 1499 class Apple(Model): 1500 _attribute_map = { 1501 'name': {'key': 'name', 'type': 'str', 'xml':{'name': 'name', 'attr': True}}, 1502 } 1503 _xml_map = { 1504 } 1505 1506 mymodel = AppleBarrel( 1507 eu_apple=Apple(name='granny'), 1508 us_apple=Apple(name='fuji'), 1509 ) 1510 1511 s = Serializer({"AppleBarrel": AppleBarrel, "Apple": Apple}) 1512 rawxml = s.body(mymodel, 'AppleBarrel', is_xml=True) 1513 1514 assert_xml_equals(rawxml, basic_xml) 1515 1516 1517 def test_basic_namespace_is_xml(self): 1518 """Test an ultra basic XML.""" 1519 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1520 <Data xmlns:fictional="http://characters.example.com"> 1521 <fictional:Age>37</fictional:Age> 1522 </Data>""") 1523 1524 class XmlModel(Model): 1525 _attribute_map = { 1526 'age': {'key': 'age', 'type': 'int', 'xml':{'name': 'Age', 'prefix':'fictional','ns':'http://characters.example.com'}}, 1527 } 1528 _xml_map = { 1529 'name': 'Data' 1530 } 1531 1532 mymodel = XmlModel( 1533 age=37, 1534 ) 1535 1536 s = Serializer({"XmlModel": XmlModel}) 1537 rawxml = s.body(mymodel, 'XmlModel', is_xml=True) 1538 1539 assert_xml_equals(rawxml, basic_xml) 1540 1541 @pytest.mark.skipif(sys.version_info < (3,6), 1542 reason="Unstable before python3.6 for some reasons") 1543 def test_complex_namespace(self): 1544 """Test recursive namespace.""" 1545 basic_xml = ET.fromstring("""<?xml version="1.0"?> 1546 <entry xmlns="http://www.w3.org/2005/Atom" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 1547 <author> 1548 <name>lmazuel</name> 1549 </author> 1550 <AuthorizationRules xmlns="http://schemas.microsoft.com/netservices/2010/10/servicebus/connect"> 1551 <AuthorizationRule i:type="SharedAccessAuthorizationRule"> 1552 <KeyName>testpolicy</KeyName> 1553 </AuthorizationRule> 1554 </AuthorizationRules> 1555 </entry>""") 1556 1557 class XmlRoot(Model): 1558 _attribute_map = { 1559 'author': {'key': 'author', 'type': 'QueueDescriptionResponseAuthor'}, 1560 'authorization_rules': {'key': 'AuthorizationRules', 'type': '[AuthorizationRule]', 'xml': {'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect', 'wrapped': True, 'itemsNs': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect'}}, 1561 } 1562 _xml_map = { 1563 'name': 'entry', 'ns': 'http://www.w3.org/2005/Atom' 1564 } 1565 1566 class QueueDescriptionResponseAuthor(Model): 1567 _attribute_map = { 1568 'name': {'key': 'name', 'type': 'str', 'xml': {'ns': 'http://www.w3.org/2005/Atom'}}, 1569 } 1570 _xml_map = { 1571 'ns': 'http://www.w3.org/2005/Atom' 1572 } 1573 1574 class AuthorizationRule(Model): 1575 _attribute_map = { 1576 'type': {'key': 'type', 'type': 'str', 'xml': {'attr': True, 'prefix': 'i', 'ns': 'http://www.w3.org/2001/XMLSchema-instance'}}, 1577 'key_name': {'key': 'KeyName', 'type': 'str', 'xml': {'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect'}}, 1578 } 1579 _xml_map = { 1580 'ns': 'http://schemas.microsoft.com/netservices/2010/10/servicebus/connect' 1581 } 1582 1583 mymodel = XmlRoot( 1584 author = QueueDescriptionResponseAuthor(name = "lmazuel"), 1585 authorization_rules = [AuthorizationRule( 1586 type="SharedAccessAuthorizationRule", 1587 key_name="testpolicy" 1588 )] 1589 ) 1590 1591 s = Serializer({ 1592 "XmlRoot": XmlRoot, 1593 "QueueDescriptionResponseAuthor": QueueDescriptionResponseAuthor, 1594 "AuthorizationRule": AuthorizationRule, 1595 }) 1596 rawxml = s.body(mymodel, 'XmlModel') 1597 1598 assert_xml_equals(rawxml, basic_xml) 1599