-
Notifications
You must be signed in to change notification settings - Fork 20
Support xs:list
inline lists, take 2
#38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6ba8825
d6c038c
d075694
6d8f38c
f21f0b8
4ca2f74
09159f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,11 +121,93 @@ class RootModel(BaseXmlModel, tag='model'): | |
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_homogeneous_definition_errors(): | ||
with pytest.raises(errors.ModelFieldError): | ||
class TestModel(BaseXmlModel): | ||
attr1: List[int] = attr() | ||
def test_text_list_extraction(): | ||
class RootModel(BaseXmlModel, tag="model"): | ||
values: List[int] | ||
|
||
xml = ''' | ||
<model>1 2 70 -34</model> | ||
''' | ||
|
||
actual_obj = RootModel.from_xml(xml) | ||
expected_obj = RootModel( | ||
values = [1, 2, 70, -34], | ||
) | ||
|
||
assert actual_obj == expected_obj | ||
|
||
actual_xml = actual_obj.to_xml() | ||
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_text_tuple_extraction(): | ||
class RootModel(BaseXmlModel, tag="model"): | ||
values: Tuple[int, ...] | ||
|
||
xml = ''' | ||
<model>1 2 70 -34</model> | ||
''' | ||
|
||
actual_obj = RootModel.from_xml(xml) | ||
expected_obj = RootModel( | ||
values=[1, 2, 70, -34], | ||
) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, nice catch! |
||
assert actual_obj == expected_obj | ||
|
||
actual_xml = actual_obj.to_xml() | ||
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_attr_list_extraction(): | ||
class RootModel(BaseXmlModel, tag="model"): | ||
values: List[float] = attr() | ||
|
||
xml = ''' | ||
<model values="3.14 -1.0 300.0"/> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will there be support for custom delimiters for attribute values? The space char seems to be the default for now, but curious if other delimiters will be supported in the future. I can imagine values might be separated by other chars like # comma delimiter
<model values="3.14,-1.0,300.0"/>
# vertical bar delimiter.
<model values="3.14|-1.0|300.0"/> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current PR implements support for XML Schema lists, https://www.w3.org/TR/xmlschema11-2/#atomic-vs-list , which, afaict, only support white-space delimited values. I have no plans to implement other delimiters as this covers my (or rather my project $work's) needs. For other kinds of delimiters, I think you're better off using elements, as they are more general. However, if someone need to consume lists with other delimiters, I'd gladly help with the implementation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @ajoino, thank you for your reply. Yes the main issue I have is on the consumption side. At the moment my challenge is with the deserialization of the XML. I am hoping to be able to parse the Example XML: <?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1" name="BookA" pageReferences="2,6,14"/>
<book id="2" name="BookB" pageReferences="1,8,57"/>
</books> Python Classes: class Book(BaseXmlModel, tag="book"):
id: str = attr(name="id")
name: str = attr(name="name")
page_references: str = attr(name="pageReferences")
class BookResponse(BaseXmlModel, tag="books"):
books: Optional[List[Book]] = element() I was mainly wondering if it would be possible to pass a custom delimiter param to class Book(BaseXmlModel, tag="book"):
...
page_references: List[int] = attr(name="pageReferences", delimiter=",") |
||
''' | ||
# This will fail if scientific notation is used | ||
# i.e. if 300 is replaced with 3e2 or 300, the deserializer | ||
# will always use the standard notation with the added `.0`. | ||
# While this behaviour fails the tests, it shouldn't | ||
# matter in practice. | ||
|
||
actual_obj = RootModel.from_xml(xml) | ||
expected_obj = RootModel( | ||
values=[3.14, -1.0, 3e2], | ||
) | ||
|
||
assert actual_obj == expected_obj | ||
|
||
actual_xml = actual_obj.to_xml() | ||
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_attr_tuple_extraction(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the test is the same as previous. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm testing both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean they are literally identical. Based on the test name I think the model should be like this: class RootModel(BaseXmlModel, tag="model"):
values: Tuple[float] = attr() |
||
class RootModel(BaseXmlModel, tag="model"): | ||
values: Tuple[float, ...] = attr() | ||
|
||
xml = ''' | ||
<model values="3.14 -1.0 300.0"/> | ||
''' | ||
# This will fail if scientific notation is used | ||
# i.e. if 300 is replaced with 3e2 or 300, the deserializer | ||
# will always use the standard notation with the added `.0`. | ||
# While this behaviour fails the tests, it shouldn't | ||
# matter in practice. | ||
|
||
actual_obj = RootModel.from_xml(xml) | ||
expected_obj = RootModel( | ||
values=(3.14, -1.0, 3e2), | ||
) | ||
|
||
assert actual_obj == expected_obj | ||
|
||
actual_xml = actual_obj.to_xml() | ||
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_homogeneous_definition_errors(): | ||
with pytest.raises(errors.ModelFieldError): | ||
class TestModel(BaseXmlModel): | ||
attr1: List[Tuple[int, ...]] | ||
|
@@ -156,3 +238,10 @@ class TestSubModel(BaseXmlModel): | |
|
||
class TestModel(BaseXmlModel): | ||
__root__: List[TestSubModel] | ||
|
||
with pytest.raises(errors.ModelFieldError): | ||
class TestSubModel(BaseXmlModel): | ||
attr: int | ||
|
||
class TestModel(BaseXmlModel): | ||
text: List[TestSubModel] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,7 +46,7 @@ class TestSubModel(BaseXmlModel, tag='model'): | |
|
||
class TestModel(BaseXmlModel, tag='model'): | ||
model: TestSubModel | ||
list: List[TestSubModel] = [] | ||
list: List[TestSubModel] = element(default=[]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the reason of that change? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously, that model would only have one possible text field, as This is one of the backwards-incompatible changes I mentioned in the old PR. |
||
tuple: Optional[Tuple[TestSubModel, TestSubModel]] = None | ||
attrs: Dict[str, str] = {} | ||
wrapped: Optional[str] = wrapped('envelope') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this test is redundant because is tests the same case as the previous one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment below.