stripe-python icon indicating copy to clipboard operation
stripe-python copied to clipboard

For webhooks, `webhook.request` is both a method and a data attribute

Open AaronBeaudoin opened this issue 2 years ago • 4 comments

Describe the bug

Incoming webhook events have a request data attribute, but the event instance already has a request bound method, so we end up with a bit of a conflict. The data attribute can still be accessed with event["request"] but it feels weird to need to do that for just that one data attribute and then use dot syntax for everything else.

>>> event = stripe.Webhook.construct_event(...)

>>> event.request
<bound method StripeObject.request of <Event event id=<id_omitted> at 0x1035bb450> JSON: { ...

>>> event["request"]
<StripeObject id=<id_omitted> at 0x102e95810> JSON: {
  "id": "<id_omitted>",
  "idempotency_key": "<idempotency_key_omitted>"
}

event.request and event["request"] both returning different things is rather confusing, and it took me quite a while to figure out what was going on.

To Reproduce

  1. Construct a webhook event.
  2. Access event.request.
  3. Access event["request"].
  4. Notice that they are different.

I would probably consider this less of a "bug" and more of an oversight.

Expected behavior

The event.request method should probably be something like event._request so it doesn't conflict with the incoming data. That way I can call event.request and actually get the attribute from the body of the webhook as expected.

Code snippets

No response

OS

macOS

Language version

Python 3.9.10

Library version

stripe-python v2.76.0

API version

2020-08-27

Additional context

No response

AaronBeaudoin avatar Jun 16 '22 19:06 AaronBeaudoin

@AaronBeaudoin thanks for the detailed report! This feels similar to how items on Subscription can't be accessed by sub.items because items is a default method on dict which all our API resources inherit from. We'll see if this is something we could fix in the future though.

remi-stripe avatar Jun 16 '22 20:06 remi-stripe

Faced the same issue on the latest build stripe 3.5.0. This is rather confusing and hopefully gets addressed in a future release.

☝️ Same issue trying to access Subscription.items

For now I'll use something like:

def get_subscription(subscription_id: str) -> stripe.Subscription:
    try:
        return stripe.Subscription.retrieve(subscription_id)
    except StripeError as e:
        print(e.error)
        print(e.json_body)
        print(e.user_message)
        raise ValueError(f"Failed to retrieve subscription {subscription_id}")

subscription = get_subscription(subscription_id)
subscription.to_dict()["items"] # since subscription.items is dict's built-in method 

HichameMoriceau avatar Dec 31 '22 14:12 HichameMoriceau

Let me take a crack at this issue.

Andres-Ventura avatar Feb 06 '23 20:02 Andres-Ventura