-
Notifications
You must be signed in to change notification settings - Fork 20
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
Support xs:list
inline lists, take 2
#38
base: dev
Are you sure you want to change the base?
Conversation
I think you branched off from master. Please rebase to dev because you PR brings commits from master branch. |
163969d
to
6e333f2
Compare
Rebased on dev so things should be in order now. |
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_text_tuple_extraction(): |
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.
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_attr_tuple_extraction(): |
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.
the test is the same as previous.
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.
I'm testing both tuple
and list
to make sure that they both work. But yes, they are essentially the same and if this test is covered by other tests I'm willing to remove it.
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.
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()
@@ -39,7 +39,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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, that model would only have one possible text field, as List
fields were implicitly elements. Now, without explicitly making a List
type an element, it will be interpreted as the text. That would make that model have two Python fields that represent XML texts, model
and list
. Since the intention of the test was to have list
represent an XML element, I changed to explicitly be so.
This is one of the backwards-incompatible changes I mentioned in the old PR.
(This is @ajoino, accidentally commented using my work account again...) Nice to see that 0.6.0 was released, though I'm sad I couldn't get this finished in time. Regarding pre-commit:
Something poetry-related given the logs but I don't use poetry for my own projects so it's hard to tell what's wrong. |
Hi. It is a bug in isort pre-commit hook. I fixed that here a24d8a2, so you could rebase to that commit or run |
Fixed review comments.
Added new tests and updated old tests as this addition is a regression/backwards incompatibility.
6e333f2
to
f21f0b8
Compare
I've updated to be up-to-speed with latest dev, but I rebased instead of merging and that goofed the history. |
): | ||
assert model_field.sub_fields and len(model_field.sub_fields) == 1 | ||
if ( | ||
isclass(model_field.type_) and issubclass(model_field.type_, pxml.BaseXmlModel) or |
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.
I extracted this logic to a function so that it can be reused.
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.
Very nice!
Fixed this and the other comments.
|
||
name = model_field.name | ||
|
||
assert name is not None, "attr must be name" |
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.
according to pydantic name is not optional so I think this check is redundant.
|
||
_, ns, nsmap = self._get_entity_info(model_field) | ||
|
||
name = model_field.name |
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.
it is better to use model_field.alias
to be compatible with pydantic aliased fields.
assert_xml_equal(actual_xml, xml) | ||
|
||
|
||
def test_attr_tuple_extraction(): |
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.
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()
expected_obj = RootModel( | ||
values=[1, 2, 70, -34], | ||
) | ||
|
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.
assert actual_obj == expected_obj
is missing I suppose
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.
Ah, nice catch!
Yeah I must've gotten so happy changing the name of the test that I forgot to change the logic...
text = element.pop_text() | ||
|
||
if text is None: | ||
return [] |
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.
I think it is better to return None
in this case otherwise default values will not work. For example for this model:
class RootModel(BaseXmlModel, tag="model"):
values: Tuple[int, ...] = (0, 0)
if deserialize
returns []
that code will not work because pydantic uses default values only if a value is not provided. But if deserialize
returns []
it will not be filtered out by the model deserializer and the default value will not be set which is not expected behavior I suppose.
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.
I don't know the best way to resolve multiple conversations on github but I've updated the PR with fixes to your comments.
I also realized recently that I probably should have created an issue first to discuss design and then made a PR. I apologize that I skipped that order and will do better next time. Thank you for your patience in dealing with me :)
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more @@ Coverage Diff @@
## dev #38 +/- ##
==========================================
- Coverage 93.70% 93.28% -0.43%
==========================================
Files 22 22
Lines 1033 1072 +39
==========================================
+ Hits 968 1000 +32
- Misses 65 72 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
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 comment
The 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 |
and ,
.
# 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 comment
The 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 comment
The 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 pageReferences
attribute and represent it as type List[int]
instead of str
. However, compared to your space delimited examples in this PR, I dealing with both |
and ,
delimiters.
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 attr()
. This could act as an override to the default space delimiter whenever it is specified. Alternatively you may have a better idea how to accomplish this, but this is just my reasoning for now.
class Book(BaseXmlModel, tag="book"):
...
page_references: List[int] = attr(name="pageReferences", delimiter=",")
is this going to be merged? support for xs:list is much needed |
@saharwenrix Hi, MRs to version 1 are no longer accepted, only critical bug fixes. |
This is a redo of PR #37
I have addressed all comments expect the larger one about
HeterogeneousSerializerFactory
, I will create a separate PR for that