Skip to content
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

Deserialize using the default values if it exists #35

Merged
merged 4 commits into from
Apr 22, 2022
Merged

Conversation

Edresson
Copy link
Contributor

No description provided.

@@ -115,9 +115,9 @@ def _default_value(x: Field):
Returns:
object: default value of the input Field.
"""
if x.default != MISSING:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if it was a spelling mistake but if it wasn't I added the check for both MISSING object (_MISSING) and MISSING string(MISSING)

@@ -432,6 +437,11 @@ def deserialize_immutable(cls, data: dict) -> "Serializable":
if field.name in vars(cls):
Copy link
Contributor Author

@Edresson Edresson Apr 21, 2022

Choose a reason for hiding this comment

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

This check does not get the complex type (like List[int] and others). The default values of complex type fields will be ignored. To deal with that, I added here a check if the default value is not "MISSING" we use it instead of raising the error. So if we need that the user provides some param it needs to be defined as "MISSING" type (string or object).

@Edresson Edresson requested review from erogol and reuben and removed request for erogol April 21, 2022 18:10
@reuben
Copy link
Contributor

reuben commented Apr 21, 2022

Can you add a test that fails before this PR is applied but passed with it applied?

@Edresson
Copy link
Contributor Author

Edresson commented Apr 21, 2022

Can you add a test that fails before this PR is applied but passed with it applied?

Without this PR will break all times that we define a complex type (like List[int]) and do not provide it as data in .new_from_dict() or from_dict(). The default value will be ignored and it will raise an error.
I think that defaults values need to be used, given that it is not a Required field. I add a new field in the test_init_from_dict unit test to show the "error". I'm not so familiar with Coqpit yet. If you know a better way to solve this, please let me know :).

@reuben
Copy link
Contributor

reuben commented Apr 21, 2022

So while reviewing I noticed that you changed both deserialize and deserialize_immutable, but the test only calls init_from_dict, which uses deserialize_immutable. So I added the following test on the main branch, to make sure deserialize is being handled properly:

diff --git a/tests/test_init_from_dict.py b/tests/test_init_from_dict.py
index 2e14d3f..2a4dc46 100644
--- a/tests/test_init_from_dict.py
+++ b/tests/test_init_from_dict.py
@@ -21,6 +21,8 @@ class Reference(Coqpit):
             Person(name="Ceren", age=15),
         ]
     )
+    people_ids: List[int] = field(
+        default_factory=lambda: [1, 2, 3])
 
 
 @dataclass
@@ -31,6 +33,9 @@ class WithRequired(Coqpit):
 def test_new_from_dict():
     ref_config = Reference(name="Fancy", size=3 ** 10, people=[Person(name="Anonymous", age=42)])
 
+    in_place_deserialize = Reference()
+    in_place_deserialize.from_dict({"name": "Fancy", "size": 3 ** 10, "people": [{"name": "Anonymous", "age": 42}]})
+
     new_config = Reference.new_from_dict(
         {"name": "Fancy", "size": 3 ** 10, "people": [{"name": "Anonymous", "age": 42}]}
     )

But it passes even before this change. Do you have a good idea of what's going on? Should we keep the changes only to deserialize_immutable or is there something deeper that needs to be figured out here?

@Edresson
Copy link
Contributor Author

So while reviewing I noticed that you changed both deserialize and deserialize_immutable, but the test only calls init_from_dict, which uses deserialize_immutable. So I added the following test on the main branch, to make sure deserialize is being handled properly:

diff --git a/tests/test_init_from_dict.py b/tests/test_init_from_dict.py
index 2e14d3f..2a4dc46 100644
--- a/tests/test_init_from_dict.py
+++ b/tests/test_init_from_dict.py
@@ -21,6 +21,8 @@ class Reference(Coqpit):
             Person(name="Ceren", age=15),
         ]
     )
+    people_ids: List[int] = field(
+        default_factory=lambda: [1, 2, 3])
 
 
 @dataclass
@@ -31,6 +33,9 @@ class WithRequired(Coqpit):
 def test_new_from_dict():
     ref_config = Reference(name="Fancy", size=3 ** 10, people=[Person(name="Anonymous", age=42)])
 
+    in_place_deserialize = Reference()
+    in_place_deserialize.from_dict({"name": "Fancy", "size": 3 ** 10, "people": [{"name": "Anonymous", "age": 42}]})
+
     new_config = Reference.new_from_dict(
         {"name": "Fancy", "size": 3 ** 10, "people": [{"name": "Anonymous", "age": 42}]}
     )

But it passes even before this change. Do you have a good idea of what's going on? Should we keep the changes only to deserialize_immutable or is there something deeper that needs to be figured out here?

Yeah, on my side it only broke in deserialize_immutable. I added as well in deserialize because I thought probably it will broken without. I don't know if it is good to keep or not.

@reuben
Copy link
Contributor

reuben commented Apr 22, 2022

Then let's take it out since we don't understand it, better to add if if a real need is identified and understood. Other than that LGTM! Thanks for the PR

@Edresson
Copy link
Contributor Author

Then let's take it out since we don't understand it, better to add if if a real need is identified and understood. Other than that LGTM! Thanks for the PR

Done :)

@reuben reuben merged commit 80c2702 into main Apr 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants