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

Feature request: event_parser envelopes should handle unions of BaseModels #2734

Closed
1 of 2 tasks
dcheno opened this issue Jul 10, 2023 · 9 comments
Closed
1 of 2 tasks
Assignees
Labels
breaking-change Breaking change feature-request feature request v3 Features that will be included in Powertools v3.

Comments

@dcheno
Copy link

dcheno commented Jul 10, 2023

Use case

Pydantic supports parsing unions of BaseModel types. This can be pretty handy when a lambda might accept a few different event types.

Example: a callback handler lambda might process an error response or a success response type. These might have different fields.

The current implementation of BaseEnvelope will error if you pass a Union or Annotated Union to the model field. This is because neither of those types have a parse_raw or parse_obj method which BaseModel expects.

Solution/User Experience

I believe this can mostly be taken care of by switching from using model.parse_raw and model.parse_obj here in BaseEnvelope to use pydantic.parse_obj_as and pydantic.parse_raw_as (available from pydantic 1.7 onwards so should match this projects dependencies). Docs here.

Happy to work on a PR, just wanted to check in here before I did too much work.

Alternative solutions

1. I've gotten around this in the past by just parsing the parent type in `event_parser`. For example, parsing `EventBridgeModel`, then parsing the `detail` myself using `parse_obj_as`.
2. This can also be solved on a case-by-case basis by rearchitecting the event structure so that the Union takes place within the model being parsed, but changing the event fields isn't always an option in existing codebases.

Acknowledgment

@dcheno dcheno added feature-request feature request triage Pending triage from maintainers labels Jul 10, 2023
@boring-cyborg
Copy link

boring-cyborg bot commented Jul 10, 2023

Thanks for opening your first issue here! We'll come back to you as soon as we can.
In the meantime, check out the #python channel on our Powertools for AWS Lambda Discord: Invite link

@leandrodamascena
Copy link
Contributor

Looking at this now.

@leandrodamascena leandrodamascena removed the triage Pending triage from maintainers label Jul 12, 2023
@leandrodamascena leandrodamascena moved this from Triage to Working on it in Powertools for AWS Lambda (Python) Jul 12, 2023
@leandrodamascena
Copy link
Contributor

Hi @dcheno! Do you have a snippet of the code you are using to reproduce this feature request? I understand your point about our current codebase, but I'm trying to think of situations where this might happen.

Thank you

@leandrodamascena leandrodamascena self-assigned this Jul 13, 2023
@dcheno
Copy link
Author

dcheno commented Jul 13, 2023

hey @leandrodamascena , thanks for taking a look.

Sure, here's the kind of thing I run into occassionaly:

from aws_lambda_powertools.utilities.parser import event_parser
from pydantic import BaseModel, Field
from typing import Annotated, Any, Literal, Union


class SuccessfulCallback(BaseModel):
    status: Literal["succeeded"]
    name: str
    breed: Literal["Husky", "Labrador"]


class FailedCallback(BaseModel):
    status: Literal["failed"]
    error: str


DogCallback = Annotated[
    Union[SuccessfulCallback, FailedCallback], Field(discriminator="status")
]


@event_parser(model=DogCallback)
def lambda_handler(event: DogCallback, _: Any) -> str:
    if isinstance(event, FailedCallback): # alternatively `if event.status == "failed"` (if your type checker is on top of things)
        return f"Uh oh. Had a problem: {event.error}"

    return f"Successfully retrieved {event.breed} named {event.name}"


def main() -> None:
    print(
        lambda_handler(
            {"status": "succeeded", "name": "Clifford", "breed": "Labrador"}, None
        )
    )


if __name__ == "__main__":
    main()

Which returns error:

Traceback (most recent call last):
  .../python3.10/typing.py", line 375, in __getattr__
    raise AttributeError(item)
AttributeError: parse_obj

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  ...site-packages/aws_lambda_powertools/utilities/parser/parser.py", line 82, in event_parser
    parsed_event = parse(event=event, model=model, envelope=envelope) if envelope else parse(event=event, model=model)
 ...aws_lambda_powertools.utilities.parser.exceptions.InvalidModelTypeError: Input model must implement BaseModel, model=typing.Annotated[typing.Union[__main__.SuccessfulCallback, __main__.FailedCallback], FieldInfo(default=PydanticUndefined, discriminator='status', extra={})]

There are definitely ways around this, but I've had lambdas like this a few times so thought it would be worth checking in.

@heitorlessa heitorlessa moved this from Working on it to Pending review in Powertools for AWS Lambda (Python) Aug 1, 2023
@leandrodamascena
Copy link
Contributor

Hello @dcheno! I'm back to this issue and sorry for a long time without an update.

I was looking at our base code and trying to come up with some scenarios to see how we can update it but I think, we can't do that right now. Powertools now supports Pydantic v1 and v2 and keep Pydantic functions that work in both versions without code change. I see the parse_raw_as function has been removed in Pydantic v2.

We already have a Roadmap to drop Pydanticv1 in Powertools v3 and in this new version, we will refactor the parser utility with Pydanticv2 and can add it. We are estimating (tentative) Powertools v3 for later this year/early next year.

I'll update our roadmap to add this feature to support unions of BaseModels in an Annotated type.

Thanks.

@leandrodamascena leandrodamascena moved this from Pending review to On hold in Powertools for AWS Lambda (Python) Aug 17, 2023
@leandrodamascena leandrodamascena moved this from On hold to Backlog in Powertools for AWS Lambda (Python) Aug 17, 2023
@leandrodamascena leandrodamascena added the breaking-change Breaking change label Aug 17, 2023
@dcheno
Copy link
Author

dcheno commented Aug 21, 2023

hi @leandrodamascena, thanks for taking a look! that makes sense. I'll keep an eye out for v3

@leandrodamascena leandrodamascena added this to the Powertools v3 milestone Aug 28, 2023
@leandrodamascena leandrodamascena added the v3 Features that will be included in Powertools v3. label Aug 28, 2023
@leandrodamascena leandrodamascena changed the title Feature request: event_parser envelopes handle unions of BaseModels Feature request: event_parser envelopes should handle unions of BaseModels Apr 23, 2024
@sthulb sthulb self-assigned this Jun 7, 2024
@leandrodamascena
Copy link
Contributor

Closed via #4502

@github-project-automation github-project-automation bot moved this from Backlog to Coming soon in Powertools for AWS Lambda (Python) Jun 26, 2024
@github-actions github-actions bot added the pending-release Fix or implementation already in dev waiting to be released label Jun 26, 2024
Copy link
Contributor

⚠️COMMENT VISIBILITY WARNING⚠️

This issue is now closed. Please be mindful that future comments are hard for our team to see.

If you need more assistance, please either tag a team member or open a new issue that references this one.

If you wish to keep having a conversation with other community members under this issue feel free to do so.

Copy link
Contributor

This is now released under 2.40.0 version!

@github-actions github-actions bot removed the pending-release Fix or implementation already in dev waiting to be released label Jun 27, 2024
@leandrodamascena leandrodamascena moved this from Coming soon to Shipped in Powertools for AWS Lambda (Python) Jan 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Breaking change feature-request feature request v3 Features that will be included in Powertools v3.
Projects
Status: Shipped
Development

No branches or pull requests

3 participants