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

fix(event_handler): custom serializer recursive values when using data validation #4664

Merged
merged 9 commits into from
Jul 3, 2024

Conversation

heitorlessa
Copy link
Contributor

@heitorlessa heitorlessa commented Jul 1, 2024

Issue number: #4658

Summary

Recursively include custom serializer for all supported data types (dicts, sequences, dataclasses, Pydantic Models).

Previously, we were only using a custom_serializer for top-level keys. That meant the custom_serializer reference was getting lost during recursion.

With this change, we can now correctly serialize custom items in a list, custom values in a dict, custom values in a dataclass/Pydantic model, etc. however deep.

Changes

Please provide a summary of what's being changed

User experience

Please share what the user experience looks like before and after this change

from aws_lambda_powertools.event_handler.openapi.encoders import jsonable_encoder
from bson import Decimal128


def custom_serializer(obj):
    if isinstance(obj, Decimal128):
        return int(obj.to_decimal())

    return obj


# work
print(jsonable_encoder(Decimal128('123'), custom_serializer=custom_serializer))

# works AFTER this PR gets merged
print(jsonable_encoder({'dec': Decimal128('123')}, custom_serializer=custom_serializer))

Checklist

If your change doesn't seem to apply, please leave them unchecked.

Is this a breaking change?

RFC issue number:

Checklist:

  • Migration process documented
  • Implement warnings (if it can live side by side)

Acknowledgment

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@heitorlessa heitorlessa requested a review from a team as a code owner July 1, 2024 07:58
@pull-request-size pull-request-size bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 1, 2024
@heitorlessa heitorlessa marked this pull request as draft July 1, 2024 07:58
@github-actions github-actions bot added the bug Something isn't working label Jul 1, 2024
Copy link

codecov bot commented Jul 1, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.45%. Comparing base (e14e768) to head (dfaf6eb).
Report is 686 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4664      +/-   ##
===========================================
+ Coverage    96.38%   96.45%   +0.07%     
===========================================
  Files          214      223       +9     
  Lines        10030    10728     +698     
  Branches      1846     1996     +150     
===========================================
+ Hits          9667    10348     +681     
- Misses         259      268       +9     
- Partials       104      112       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@pull-request-size pull-request-size bot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jul 1, 2024
@pull-request-size pull-request-size bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jul 1, 2024
@heitorlessa heitorlessa marked this pull request as ready for review July 1, 2024 10:09
@heitorlessa
Copy link
Contributor Author

Will check CI later this afternoon.

@heitorlessa
Copy link
Contributor Author

@leandrodamascena when you can, I'm gonna need your help on how to best test pydantic version differences to get this to pass.

I'll get back to this late afternoon / evening

@leandrodamascena
Copy link
Contributor

@leandrodamascena when you can, I'm gonna need your help on how to best test pydantic version differences to get this to pass.

I'll get back to this late afternoon / evening

Hey @heitorlessa! Two things here:

1 - I found a bug in the Nox tests that is installing Pydantic 2.0 in the v1.0 test only in some situations, I don't know why, but it is. To fix this, I'll change this line to @nox.parametrize(" pydantic", ["1.10,<2.0", "2.0"]).

2 - This test is wrong because it is not possible to do this with Pydantic to dump JSON. The first thing we do when we detect that it is a Pydantic model is to dump it into JSON and then invoke the jsonable_encoder function again with this JSON, and in this new invocation it is possible to use custom_serializer. I understand what you tried to do, but we need to change this test a little.
image

I'll fix both problems tomorrow morning! Thanks for working on this.

@pull-request-size pull-request-size bot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 2, 2024
Copy link
Contributor

@leandrodamascena leandrodamascena left a comment

Choose a reason for hiding this comment

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

Hello @heitorlessa! I removed the change where we added custom_serializer to the Pydantic model because it will never work. When using Pydantic, the customer must handle the serializer within the model itself, otherwise Pydantic will fail.

Reference: pydantic/pydantic#7991

For me this PR is approved!

@leandrodamascena leandrodamascena changed the title fix(event_handler): custom serializer recursive values fix(event_handler): custom serializer recursive values when using data validation Jul 2, 2024
@leandrodamascena leandrodamascena linked an issue Jul 2, 2024 that may be closed by this pull request
@heitorlessa
Copy link
Contributor Author

Gotcha! thanks a lot @leandrodamascena and for fixing the pydantic nox unrelated bug too; I didn't know field_serializer existed.

class MyResult(BaseModel):
    name: str
    token_list: TokenList

    @field_serializer('token_list')
    def token_list_serializer(self, token_list: TokenList, _info):
        return orjson.Fragment(orjson.dumps(token_list.model_dump()))

@heitorlessa heitorlessa requested a review from sthulb July 3, 2024 07:06
@heitorlessa
Copy link
Contributor Author

@sthulb need your approval as Leandro pushed a fix to this PR

@sthulb sthulb merged commit 1554019 into aws-powertools:develop Jul 3, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working event_handlers size/M Denotes a PR that changes 30-99 lines, ignoring generated files. tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: custom serializer isn't being used by nested dict
3 participants