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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Union type support #87

Merged
merged 16 commits into from Mar 4, 2021
Merged

Improve Union type support #87

merged 16 commits into from Mar 4, 2021

Conversation

ydylla
Copy link
Contributor

@ydylla ydylla commented Feb 10, 2021

This tries to add support for Unions with complex types like UUID or IPv4Address.

The basic idea is to use the code generation to add function for each Union the dataclass uses.
This union function then tries to serialize or deserialize the field according to the order of types defined in the Union.
The first one that works is used.

Using the code generation for this has the advantage that the user can influence the order of checks and that only types are checked that are defined in the Union.
Which should be faster, then always checking against all types that pyserde supports.

Currently, not all tests work. I have not found a good solution for nested Unions or container types within Unions, e.g. Union[List[int],List[str]].
We probably need some form of recursion.

Some notable other changes:

  • Implemented is_set in compat.py
  • The rendered dict & iter functions now define a variable serde_scope which I needed to pass it to the union functions.
  • The render functions now render NoneType as None. I think this broke the test_union_optional test, but I still have to look into it.

@yukinarit If you have time, I would appreciate a review and your opinion about the general idea?
Also I noticed you increased the version to 0.2.3 so only at patch level.
Do you use semantic versioning? Then it should be 0.3.0 in my opinion because the new type support is a feature 馃槃.

Closes #60

Copy link
Owner

@yukinarit yukinarit left a comment

Choose a reason for hiding this comment

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

@ydylla
Thank you for the contribution! Sorry for the delay in getting back to you because it was a holiday in Japan 馃槈

I left review comments. Please check 馃憤

serde/core.py Outdated Show resolved Hide resolved
serde/de.py Show resolved Hide resolved
@yukinarit
Copy link
Owner

Do you use semantic versioning? Then it should be 0.3.0 in my opinion because the new type support is a feature 馃槃.

Closes #60

Yes I treat pyserde versioning as 0.MAJOR.MINOR as discussed in this issue, but am not 100% sure this is right. How do you treat versioning before 1.0.0? 馃

@ydylla
Copy link
Contributor Author

ydylla commented Feb 12, 2021

Yes I treat pyserde versioning as 0.MAJOR.MINOR as discussed in this issue, but am not 100% sure this is right. How do you treat versioning before 1.0.0? 馃

In my projects I do not treat 0.x.x specially. I start with 0.1.0 and then increase minor 0.2.0 for features and patch 0.2.1 for fixes.
So once I need to assign a version and have other people using it I follow semantic versioning.
If I have to break something I would increase the major version despite semver allowing breaking changes in 0.x.x

@ydylla ydylla mentioned this pull request Feb 13, 2021
* passing union args per serde scope to rendered union function
* spliting is_instance into multiple functions & rendering the correct one will be faster
@yukinarit
Copy link
Owner

If I have to break something I would increase the major version despite semver allowing breaking changes in 0.x.x

Oh! I didn't know sember allows breaking change before 1.0.0 馃槻
I still don't want to update the major version because pyserde is not stable enough.

Anyway, I will change it from 0.2.3 to 0.3.0 maybe after a few more MRs are merged. 馃憤
Let me know If you need a new version pyserde in PyPI

* is_instance takes some shortcuts to increase performance, like only checking the 1st element of lists
* typecheck was only used in tests
To be more performant we just try to deserialize instead of checking types, this means the order of types in unions is important. More complex types should be tried first, otherwise simple types will prematurely  match.
* use a typed dataclass as container for serde internals
* removed more_types.py & the custom serializer code. Unkown type exception has now own function.
class inheritance caused overwriting of scope values
thanks tomlfile example, otherwise I had not noticed it
@codecov
Copy link

codecov bot commented Feb 26, 2021

Codecov Report

Merging #87 (e02e1ee) into master (6c4a832) will increase coverage by 1.03%.
The diff coverage is 92.37%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #87      +/-   ##
==========================================
+ Coverage   87.15%   88.18%   +1.03%     
==========================================
  Files          11       11              
  Lines         903      948      +45     
  Branches      187      203      +16     
==========================================
+ Hits          787      836      +49     
+ Misses         79       75       -4     
  Partials       37       37              
Impacted Files Coverage 螖
serde/inspect.py 51.85% <25.00%> (酶)
serde/core.py 85.61% <82.89%> (+3.35%) 猬嗭笍
serde/compat.py 95.23% <96.15%> (+1.90%) 猬嗭笍
serde/__init__.py 100.00% <100.00%> (酶)
serde/de.py 91.76% <100.00%> (+0.13%) 猬嗭笍
serde/json.py 100.00% <100.00%> (酶)
serde/msgpack.py 100.00% <100.00%> (酶)
serde/se.py 94.60% <100.00%> (+0.22%) 猬嗭笍
serde/toml.py 100.00% <100.00%> (酶)
serde/yaml.py 100.00% <100.00%> (酶)
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
螖 = absolute <relative> (impact), 酶 = not affected, ? = missing data
Powered by Codecov. Last update 6c4a832...e02e1ee. Read the comment docs.

@ydylla
Copy link
Contributor Author

ydylla commented Feb 26, 2021

Hi @yukinarit,
this is now ready to be reviewed, so if you have time please take a look.

I am not sure if you like 431c914 but I thought it would be nice (and cleaner) to use the serde scope like an actual scope, which contains all serde internals. This way we do not need several __foo__ names to hide the internal functions. In the generated functions the scope is now always available as serde_scope (for jinja and within the functions).

If you do not like it, it is no problem to get the union support working without it. So do not feel obliged to merge this.

@ydylla ydylla changed the title WIP: Improve Union type support Improve Union type support Feb 26, 2021
Copy link
Owner

@yukinarit yukinarit left a comment

Choose a reason for hiding this comment

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

Hi @ydylla
I don't mind replacing scope object with dataclass. I left a few comments in order to understand the intent of the code. Please answer to the question when you have time.

Thanks!

serde/compat.py Show resolved Hide resolved
@yukinarit yukinarit merged commit 52d4522 into yukinarit:master Mar 4, 2021
@yukinarit
Copy link
Owner

LGTM

@ydylla
Copy link
Contributor Author

ydylla commented Mar 4, 2021

馃コ Thanks for the merge.

@yukinarit
Copy link
Owner

No problem! Thanks for the contribution! 馃檪

@ydylla ydylla deleted the unions branch May 8, 2021 18:25
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.

Write more tests around Union
2 participants