-
Notifications
You must be signed in to change notification settings - Fork 432
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
AttributeError: service_agreement #1227
Comments
@pslowinski-wn I don't fully grasp the issue you're reporting here. The |
@remi-stripe I hope it makes sense. |
@pslowinski-wn Your code checks whether
I do think you have to handle the |
@pslowinski-wn I confirmed this is also covered in our wiki here under the |
When I run this code, it only works for accounts with
|
Damn you're right I'm sorry. I thought I thoroughly tested the examples but I double checked it and I tested on the wrong account. Right now the only solution I found is to use |
I am doing the below:
However, it is rather a hack ;-) |
@pslowinski-wn Okay so I think our types are incorrect for the case where a property is sometimes completely absent. For now, I think using
And we're going to investigate changing the types to use |
I am definitely not a Python expert. However, |
I don't disagree but we avoid doing that in our SDKs and we mirror what the API does instead. It's a common pattern to have some properties really be optional. The most canonical example would be the PaymentMethod API where you have But I agree it can make it awkward in some languages and that's what we're going to investigate further. And to be clear, I've never liked that |
If we wanted to change the types to match what happens at runtime, we would need If we wanted to change the runtime to match what's described by the types, your suggestion
to break and need to change to an We could consider making "absent as none" behavior opt-in, and recommend this to anybody who uses types -- which I am experimenting with in #1229. Then it would be
and this would make the runtime behavior match what's described in the types. But this seems hard to discover and doesn't feel like a true fix, and the types would still be inaccurate for anybody unable to discover this option. |
Another option would be to leave the possibly-completely-absent fields at runtime, omit them from the type definitions, and expose properties or getters with a different name and the desired semantics, e.g. instead of
you would do
or maybe
but so far I can't really think of any naming scheme that would make this feel good. |
I like that idea. I would also hope |
I opened a "typing" discussion on the Python discourse about this issue to see if anybody there has any ideas. https://discuss.python.org/t/typing-notrequired-like-for-potentially-absent-class-attributes/46963 If not, I think probably my preferred approach for addressing this is the add additional getters I described, which we would pursue if enough users were running into this and having trouble. |
Please i need help on WCFM slipt payment, I'm getting { "tos_acceptance": { Please can anybody help me with this? |
@verocauto Your platform account seems based in Canada and Cross-Border Payouts are only supported with US platform so this just won't work. Please work with our support team for help instead of using this older Github issue about something else: https://support.stripe.com/contact |
@remi-stripe from what I can see in the Stripe API docs, this field is marked as nullable but not optional. That means the typing is actually correct (the field should always be present, and have an explicit null value), but the implementation of the API/lib is wrong in comparison with the API contract (i.e. the field is absent instead of present with explicit null value). |
If the desired behavior really is that this field should be absent, then the current API docs and the current Python typing is wrong and needs to be updated. Perhaps something like this (stripped down example) would be appropriate for modelling fields that can be absent (this passes type checking in Python), in combination with additional getter methods which you suggested above: import typing
Absent: typing.TypeAlias = ( # Absent is used to represent a field that may be absent in response in type annotations
typing.Never
)
def get_absent_as_none(self: object, attr_name: str) -> typing.Any:
if hasattr(self, attr_name):
return getattr(self, attr_name)
return None
class TosAcceptance:
# ...
service_agreement: typing.Union[typing.Optional[str], Absent]
def get_service_agreement(self) -> typing.Optional[str]:
get_absent_as_none(self, 'service_agreement')
t = TosAcceptance()
my_var: typing.Optional[str | None] = t.service_agreement This adds type annotations that at least hint at the potential dangers of accessing |
The alternative is to actually implement an explicit Absent singleton type and return that instead of throwing an error on access for absent fields, but that would involve making breaking changes to the Python library. import enum
import typing
class AbsentType(enum.Enum):
token = 0
Absent: typing.Final = ( # singleton type that represents the special value of 'absent'
AbsentType.token
)
class TosAcceptance:
# ...
service_agreement: typing.Union[typing.Optional[str], AbsentType] = Absent
t = TosAcceptance()
my_var: typing.Optional[str]
my_var = t.service_agreement # fails
my_var = t.service_agreement if t.service_agreement is not Absent else None # works This would make all of this actually become type checkable for users of the lib, and also make implementing absent_as_none very easy for devs themselves if necessary as it's just: T = typing.TypeVar("T")
def absent_as_none(val: typing.Union[T, AbsentType]]) -> typing.Optional[T]:
if val is not Absent:
return val
return None I think you could mitigate the breaking change by having this new behaviour configurable in your try:
if k in self._field_remappings:
k = self._field_remappings[k]
if some_default_config_value and self[k] is Absent:
raise AttributeError("some msg")
return self[k]
except KeyError as err:
raise AttributeError(*err.args) |
The API Reference never says when a property is optional though so what you see on the API Ref isn't incorrect or proving something, it's more that it's incomplete. |
Describe the bug
Account
class hastos_acceptance: Optional[TosAcceptance]
.TosAcceptance
class hasservice_agreement: Optional[str]
The following code:
Should not rais exceptions, but it does:
AttributeError: service_agreement
To Reproduce
if
statementtheExpected behavior
Exception should not be raised
Code snippets
No response
OS
macOS
Language version
3.11.4
Library version
8.1.0
API version
2019-08-14
Additional context
No response
The text was updated successfully, but these errors were encountered: