There doesn't seem to be a way of robustly relying on library's types for API responses
Describe the bug
As described in this issue we can use either python dot or dict notation for accessing API response values.
For the types included in the library, dot notation successfully returns the correct types:
whereas using dict notation results in everything you access being set to Any
This is fine, however there's an issue with using dot notation (also mentioned in the other issue) where calling subscription.items results in a crash because it tries to access dict's items() function instead.
This means the types can't be relied upon. It also means there's no way of using the types without people knowing they need to access items in a different way.
Is there a workaround for this? Or a fix?
To Reproduce
- Use a python type checking system (we use pyright)
- Try and access the plan object from a subscription response using
plan = subscription.items.data[0].plan. It will crash, but the plan type will be set correctly - Instead, try accessing using
plan = subscription['items']['data'][0]['plan']. It will work, but the types will be wrong.
Expected behavior
At least one of the following should be happen (ideally both):
- The types should fail when accessing items using dot notation
- The types should return the correct value when using dict notation
Code snippets
No response
OS
macOS
Language version
python 3.8.10
Library version
stripe-python 7.14.0
API version
2023-10-16
Additional context
No response
Thanks for reporting @matt-dalton
We are aware of this issue and it is in our backlog to address it.
what I've done locally for this is:
# this _technically_ exists, but is inaccessible because it collides with dict.items(), so you have to
# use the __getitem__ method to access it
# items: list[StripeSubscriptionItem] # the items included in this subscription (prices live here)
def __getitem__(self, item: typing.Literal["items"]) -> StripeList[SubscriptionItem]:
pass
(This comes up for SubscriptionSchedulePhase too, and possibly other places.)
In our codebase we want to use dot notation for all cases unless we are forced to use []; unfortunately for the more general case this would be much more of a PITA.
@overload
def __getitem__(self, item: Literal["items"] -> List[SubscriptionItem]:
...
@overload
def __getitem__(self, item: Literal["customer"] -> str | Customer:
...
and so on for each field; maybe this is feasible if these types are all auto generated rather than hand maintained
good luck!
Same issue, we are converting over from JSON dictionary access to use the library fields and this was confusing but now I'm gunshy about trusting the library.
We're soliciting feedback around some potential solutions to the items problem. There are breaking changes and tradeoffs in each direction, so we're hoping that hearing from developers can give us some direction. Please leave a comment if this is still relevant to you: https://github.com/stripe/stripe-python/issues/1454
I have ran into this as well which caused a production issue. Relying on the types (and the the docs to be fair) after upgrading to Basil I changed all my susbcription.current_period_start calls to subscription.items.data[0].curremnt_period_start. The same for current_period_end too etc. This then caused me to get the following error:
AttributeError: 'builtin_function_or_method' object has no attribute 'data'
After a brief chat on the Stripe Developers discord here and some manual API calls we realised it had to be accessed by subscription["items"].data[0].current_period_start but now data is typed Any instead of `List[SubscriptionItem] and so on further such as current_period_start now also being Any.
Wwe either need to be able to to use dot notation and for subscription.items.data[0].curremnt_period_start to just work, or we stick with subscription["items"].data[0].current_period_start and the types just need fixing.
I have ran into this as well which caused a production issue. Relying on the types (and the the docs to be fair) after upgrading to Basil I changed all my
susbcription.current_period_startcalls tosubscription.items.data[0].curremnt_period_start. The same forcurrent_period_endtoo etc. This then caused me to get the following error:AttributeError: 'builtin_function_or_method' object has no attribute 'data'
I recently upgraded to Basil myself and I faced the exact same issue.