⚡ Solution Summary

  • The typechecker is correct; it sees the type as Dict[str, Any].
  • Accessing properties like event.data.object.id works at runtime.
  • To avoid type errors, consider using type stubs or suppressing specific warnings.
### Describe the bug I see several examples you have of doing basically my snippet below, such https://docs.stripe.com/webhooks/process-undelivered-events). But for me, Pyright is failing on basic attribute access. I have double checked all my software versions. In the snipped, VSCode hints me that event is an Event, data is a Data, and object is a dict[str, Any] consistent with my results. When I option-click to drill in I indeed get: class Data(StripeObject): object: Dict[str, Any] I am not sure if I am somehow doing something basically wrong here. If so I'd love to know what it is, even if it is just missing where the static type check failure is documented. If not, is it _possible that the code actually runs per your example but doesn't support type checking? Maybe you have some __getattr__ interception for properties that Pyright cannot pick up? If not, is your suggestion to use ClassName.contruct_event(event_obj) or something else? ### To Reproduce ```py try: # same result when using stripe.Webhook.construct_event event = stripe.StripeClient(api_key=api_key).construct_event( payload=payload, sig_header=signature_header, secret=webhook_secret ) except ValueError as e: raise BadRequestError(f"Invalid payload from Stripe {e}") except stripe.SignatureVerificationError: raise BadRequestError("Invalid signature on Stripe request") base_obj = event.data.object # Pyland in VSCode and Pyright from shell report "cannot access attribute id for dict[str, Any]" # Same occurs if it is in a conditional (if event.type == "....) fail = base_obj.id ``` ### Expected behavior accessing "id" passes static type analysis ### Code snippets ```Python ``` ### OS 15.3.2 ### Language version Python 3.12 ### Library version stripe-python-12.1 ### API version Whatever SDK 12 sets by default ### Additional context Pyright 1.1.400 relevant pyproject.toml: ```toml [tool.pyright] include = ["src/**/*.py"] exclude = ["tests/**/*.py"] pythonVersion = "3.12" reportMissingTypeStubs = true reportGeneralTypeIssues = "error" ```

Discussion & Fixes

xavdid-stripe 2025-05-09
Hey @kadut, great questions! I agree this is confusing. The typechecker is technically correct and is trying to save you from potential mistakes. When you construct a `StripeObject`, we have a big lookup table to turn a dictionary into a more specific class. Those classes inherit from `dict`, so `Dict[str, Any]` is technically the correct type there (albeit an unspecific one). At runtime, because the object is a `StripeObject` we translate property access to the underlying dict key. So `event.data.object.id` _does_ work, it just gives a type error in the editor. To prevent that, you can cast that property to its actual class. Here's a full example: ```py import os from typing import cast from stripe import Customer, StripeClient client = StripeClient(os.environ["STRIPE_API_KEY"]) # same thing you get back when constructing an event events = client.events.list() e = events.data[0] c = e.data.object # there's type errors, but these work at runtime print(f"c is a '{c.object}' which is a {type(c)} at runtime") print(f"its ID is {c.id}") # cast to the correct type to get better typing: c = cast(Customer, c) print(f"the values are the same, but no more editor issues! {c.id=}, {c.object=}") ``` --- I don't see any calls to `event.data.object.id` in our docs, but I can fix those if you can point me to them! Our docs use `event.data.object['id']`, which is just as correct, but works without a type error --- Lastly, better typing in SDKs is something we're actually working on right now. If you (or any other reader) is willing, we'd love you to take a brief survey about it! https://forms.gle/sqoMbCoxe5wymdNm8

Get updates

We publish verified fixes weekly. No spam.

Subscribe