Skip to content

Commit

Permalink
Merge pull request #159 from khaeru/fix/xml-contact
Browse files Browse the repository at this point in the history
Fix read/write of common.Contact
  • Loading branch information
khaeru authored Jan 24, 2024
2 parents f0e00bc + c425a6e commit 57d4ce3
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 9 deletions.
7 changes: 5 additions & 2 deletions doc/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
What's new?
***********

.. Next release
.. ============
Next release
============

- Bug fix for reading :class:`.Agency` from SDMX-ML 2.1: name of the parent :class:`.Organisation` would be incorrectly attached to the Contact (:pull:`159`).
- Bug fix for writing :class:`.Contact` to SDMX-ML 2.1: :attr:`.Contact.uri` and :attr:`.Contact.email` would be written as, for instance, :xml:`<str:URI text="https://example.com"/>` instead of :xml:`<str:URI>https://example.com</str:URI>` (:pull:`159`).

v2.13.0 (2024-01-23)
====================
Expand Down
17 changes: 13 additions & 4 deletions sdmx/reader/xml/v21.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,9 +1026,6 @@ def _a(reader, elem):
only=False,
)
def _item_start(reader, elem):
# Avoid stealing the name & description of the parent ItemScheme from the stack
# TODO check this works for annotations

try:
if elem[0].tag in ("Ref", "URN"):
# `elem` is a reference, so it has no name/etc.; don't stash
Expand All @@ -1037,6 +1034,8 @@ def _item_start(reader, elem):
# No child elements; stash() anyway, but it will be a no-op
pass

# Avoid stealing the name & description of the parent ItemScheme from the stack
# TODO check this works for annotations
reader.stash(model.Annotation, "Name", "Description")


Expand Down Expand Up @@ -1298,16 +1297,26 @@ def _cat(reader, elem):
# §4.6: Organisations


@end("mes:Contact str:Contact")
@start("mes:Contact str:Contact", only=False)
def _contact_start(reader, elem):
# Avoid stealing the name of the parent Item
reader.stash("Name")


@end("mes:Contact str:Contact", only=False)
def _contact(reader, elem):
contact = model.Contact(
telephone=reader.pop_single("Telephone"),
uri=reader.pop_all("URI"),
email=reader.pop_all("Email"),
)

add_localizations(contact.name, reader.pop_all("Name"))
add_localizations(contact.org_unit, reader.pop_all("Department"))
add_localizations(contact.responsibility, reader.pop_all("Role"))

reader.unstash()

return contact


Expand Down
23 changes: 23 additions & 0 deletions sdmx/tests/reader/test_reader_xml_v21.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import sdmx
from sdmx.format.xml.v21 import qname
from sdmx.model import common
from sdmx.model.v21 import Facet, FacetType, FacetValueType
from sdmx.reader.xml.v21 import Reader, XMLParseError
from sdmx.writer.xml import Element as E
Expand Down Expand Up @@ -132,6 +133,28 @@ def test_gh_142(specimen):
assert all(0 == len(code.annotations) for code in cl)


def test_gh_159():
"""Test of https://github.com/khaeru/sdmx/pull/159."""
# Agency and contained Contact with distinct names
elem = E(
qname("str:Agency"),
E(qname("com:Name"), "Foo Agency"),
E(qname("str:Contact"), E(qname("com:Name"), "Jane Smith")),
id="FOO",
)

# - Create a reader
# - Convert to a file-like object compatible with read_message()
# - Parse the element
# - Retrieve the resulting object
reader = Reader()
reader.read_message(BytesIO(etree.tostring(elem)))
obj = reader.pop_single(common.Agency)

assert "Foo Agency" == str(obj.name)
assert "Jane Smith" == str(obj.contact[0].name)


# Each entry is a tuple with 2 elements:
# 1. an instance of lxml.etree.Element to be parsed.
# 2. Either:
Expand Down
8 changes: 7 additions & 1 deletion sdmx/tests/writer/test_writer_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ def dks(dsd):

def test_contact() -> None:
c = m.Contact(
name="John Smith", org_unit="Human Resources", telephone="+1234567890"
name="John Smith",
org_unit="Human Resources",
telephone="+1234567890",
uri=["https://example.org"],
email=["[email protected]"],
)

result = sdmx.to_xml(c, pretty_print=True)
Expand All @@ -60,6 +64,8 @@ def test_contact() -> None:
<com:Name xml:lang="en">John Smith</com:Name>
<str:Department xml:lang="en">Human Resources</str:Department>
<str:Telephone>+1234567890</str:Telephone>
<str:URI>https://example.org</str:URI>
<str:Email>[email protected]</str:Email>
</str:Contact>
"""
)
Expand Down
4 changes: 2 additions & 2 deletions sdmx/writer/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,8 @@ def _contact(obj: model.Contact):
+ i11lstring(obj.org_unit, "str:Department")
+ i11lstring(obj.responsibility, "str:Role")
+ ([Element("str:Telephone", obj.telephone)] if obj.telephone else [])
+ [Element("str:URI", text=value) for value in obj.uri]
+ [Element("str:Email", text=value) for value in obj.email]
+ [Element("str:URI", value) for value in obj.uri]
+ [Element("str:Email", value) for value in obj.email]
)
return elem

Expand Down

0 comments on commit 57d4ce3

Please sign in to comment.