Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions pydantic_xml/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,7 @@ def __init_subclass__(
else getattr(cls, '__xml_search_mode__', SearchMode.STRICT)

if parent_nsmap := getattr(cls, '__xml_nsmap__', None):
parent_nsmap.update(nsmap or {})
cls.__xml_nsmap__ = parent_nsmap
cls.__xml_nsmap__ = parent_nsmap | (nsmap or {})

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pipe operator was introduced in python 3.9 and not compatible with 3.8 which must be supported by the library.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, sorry i missed that this was still supporting 3.8. Thanks for the fix!

else:
cls.__xml_nsmap__ = nsmap

Expand Down
41 changes: 41 additions & 0 deletions tests/test_namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,47 @@ class TestModel(BaseTestModel, tag='model', ns='tst', nsmap={'tst': 'http://test
assert_xml_equal(actual_xml, xml1)


def test_subclass_nsmap_does_not_mutate_parent():
# defining a subclass with a different nsmap must not modify the parent's
# (or any shared module-level) namespace map.
nsmap_v1 = {"hq": "http://www.company.com/hq/v1", "pd": "http://www.company.com/prod"}
nsmap = {"hq": "http://www.company.com/hq", "pd": "http://www.company.com/prod"}
original_nsmap = dict(nsmap)

class Headquarters(BaseXmlModel, ns="hq", nsmap=nsmap):
country: str = element()
state: str = element()
city: str = element()

class HeadquartersV1(Headquarters, ns="hq", nsmap=nsmap_v1):
pass

class Company(BaseXmlModel, tag="Company", nsmap=nsmap):
trade_name: str = attr(name="trade-name")
headquarters: Headquarters

assert nsmap == original_nsmap, "parent nsmap must not be mutated by subclass definition"
assert Headquarters.__xml_nsmap__ == original_nsmap
assert HeadquartersV1.__xml_nsmap__ == {**original_nsmap, **nsmap_v1}

xml = """
<Company trade-name="Beboop" xmlns:pd="http://www.company.com/prod">
<hq:headquarters xmlns:hq="http://www.company.com/hq">
<hq:country>US</hq:country>
<hq:state>West Virginia</hq:state>
<hq:city>Almost Heaven</hq:city>
</hq:headquarters>
</Company>
"""

actual_obj = Company.from_xml(xml)
expected_obj = Company(
trade_name="Beboop",
headquarters=Headquarters(country="US", state="West Virginia", city="Almost Heaven"),
)
assert actual_obj == expected_obj


def test_submodel_namespaces_default_namespace_inheritance():
class TestSubModel(BaseXmlModel, tag='submodel', ns='', nsmap={'': 'http://test2.org'}):
attr1: int = attr()
Expand Down