-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add classmethod to stripe.PaymentIntent.confirm. #8498
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
Conversation
cba8c22
to
ca68934
Compare
This comment has been minimized.
This comment has been minimized.
2 similar comments
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
de9cb99
to
c7508e9
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
@overload | ||
@classmethod | ||
def confirm( | ||
cls, intent: str, api_key: str | None = ..., stripe_version: str | None = ..., stripe_account: str | None = ..., **params | ||
): ... | ||
@overload | ||
@classmethod | ||
def confirm(cls, idempotency_key: str | None = ..., **params): ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the second overload not be decorated with @classmethod
? If I understand the @class_method_variant
decorator correctly, this can be called in two versions:
PaymentIntent().confirm("key", ...)
PaymentIntent.confirm("payment intent", "key", ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mainly for avoiding mypy complaining about one of the methods not being decorated consistently with @classmethod
; another reason is that mypy does not correctly remove the first argument of the second variant for the caller without them both having @classmethod
. The first error can be silenced with a # type: ignore
directive, but the second error is likely a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it works, I'm fine with this. I think it would be a good idea to add a test case for a complicated case like this, though. Maybe @AlexWaygood can help with this.
We could also try to annotate class_method_variant()
correctly and use the decorator here. Descriptor protocol support in type checkers is decent. But that's probably out of scope for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be a good idea to add a test case for a complicated case like this, though. Maybe @AlexWaygood can help with this.
We don't (yet) have the infrastructure set up to add test cases for our third-party stub -- only our stdlib stubs. This has come up a few times now, though, so I can work on setting something up. But we probably shouldn't wait on merging this PR before then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I filed #8505 as a reminder to myself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also try to annotate class_method_variant() correctly and use the decorator here. Descriptor protocol support in type checkers is decent. But that's probably out of scope for this PR.
Yes. That's helpful for sweeping up other similar use cases of the decorator in the stubs, but I am not sure how that will be possible with type annotation alone. We can figure this out later.
4dd5204
to
73ec5c0
Compare
This comment has been minimized.
This comment has been minimized.
Similar to python#7230, stripe.PaymentIntent.confirm can be called as an instance method or a classmethod. Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This comment has been minimized.
This comment has been minimized.
1 similar comment
According to mypy_primer, this change has no effect on the checked open source code. 🤖🎉 |
It would be great if @andersk can review this as well. |
Note that stripe-python doesn’t have 1 or 2 methods like this, but 86. $ git grep -p -A1 @util.class_method_variant
stripe/api_resources/abstract/deletable_api_resource.py=class DeletableAPIResource(APIResource):
--
stripe/api_resources/abstract/deletable_api_resource.py: @util.class_method_variant("_cls_delete")
stripe/api_resources/abstract/deletable_api_resource.py- def delete(self, **param
8000
s):
--
stripe/api_resources/account.py=class Account(
--
stripe/api_resources/account.py: @util.class_method_variant("_cls_persons")
stripe/api_resources/account.py- def persons(self, idempotency_key=None, **params):
--
stripe/api_resources/account.py: @util.class_method_variant("_cls_reject")
stripe/api_resources/account.py- def reject(self, idempotency_key=None, **params):
--
stripe/api_resources/application_fee.py=class ApplicationFee(ListableAPIResource):
--
stripe/api_resources/application_fee.py: @util.class_method_variant("_cls_refund")
stripe/api_resources/application_fee.py- def refund(self, idempotency_key=None, **params):
--
stripe/api_resources/charge.py=class Charge(
--
stripe/api_resources/charge.py: @util.class_method_variant("_cls_capture")
stripe/api_resources/charge.py- def capture(self, idempotency_key=None, **params):
--
stripe/api_resources/checkout/session.py=class Session(CreateableAPIResource, ListableAPIResource):
--
stripe/api_resources/checkout/session.py: @util.class_method_variant("_cls_expire")
stripe/api_resources/checkout/session.py- def expire(self, idempotency_key=None, **params):
--
stripe/api_resources/checkout/session.py: @util.class_method_variant("_cls_list_line_items")
stripe/api_resources/checkout/session.py- def list_line_items(self, idempotency_key=None, **params):
--
stripe/api_resources/credit_note.py=class CreditNote(
--
stripe/api_resources/credit_note.py: @util.class_method_variant("_cls_void_credit_note")
stripe/api_resources/credit_note.py- def void_credit_note(self, idempotency_key=None, **params):
--
stripe/api_resources/customer.py=class Customer(
--
stripe/api_resources/customer.py: @util.class_method_variant("_cls_create_funding_instructions")
stripe/api_resources/customer.py- def create_funding_instructions(self, idempotency_key=None, **params):
--
stripe/api_resources/customer.py: @util.class_method_variant("_cls_delete_discount")
stripe/api_resources/customer.py- def delete_discount(self, idempotency_key=None, **params):
--
stripe/api_resources/customer.py: @util.class_method_variant("_cls_list_payment_methods")
stripe/api_resources/customer.py- def list_payment_methods(self, idempotency_key=None, **params):
--
stripe/api_resources/customer.py: @util.class_method_variant("_cls_retrieve_payment_method")
stripe/api_resources/customer.py- def retrieve_payment_method(
--
stripe/api_resources/customer.py: @util.class_method_variant("_cls_fund_cash_balance")
stripe/api_resources/customer.py- def fund_cash_balance(self, idempotency_key=None, **params):
--
stripe/api_resources/dispute.py=class Dispute(ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/dispute.py: @util.class_method_variant("_cls_close")
stripe/api_resources/dispute.py- def close(self, idempotency_key=None, **params):
--
stripe/api_resources/financial_connections/account.py=class Account(ListableAPIResource):
--
stripe/api_resources/financial_connections/account.py: @util.class_method_variant("_cls_disconnect")
stripe/api_resources/financial_connections/account.py- def disconnect(self, idempotency_key=None, **params):
--
stripe/api_resources/financial_connections/account.py: @util.class_method_variant("_cls_list_owners")
stripe/api_resources/financial_connections/account.py- def list_owners(self, idempotency_key=None, **params):
--
stripe/api_resources/financial_connections/account.py: @util.class_method_variant("_cls_refresh_account")
stripe/api_resources/financial_connections/account.py- def refresh_account(self, idempotency_key=None, **params):
--
stripe/api_resources/identity/verification_session.py=class VerificationSession(
--
stripe/api_resources/identity/verification_session.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/identity/verification_session.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/identity/verification_session.py: @util.class_method_variant("_cls_redact")
stripe/api_resources/identity/verification_session.py- def redact(self, idempotency_key=None, **params):
--
stripe/api_resources/invoice.py=class Invoice(
--
stripe/api_resources/invoice.py: @util.class_method_variant("_cls_finalize_invoice")
stripe/api_resources/invoice.py- def finalize_invoice(self, idempotency_key=None, **params):
--
stripe/api_resources/invoice.py: @util.class_method_variant("_cls_mark_uncollectible")
stripe/api_resources/invoice.py- def mark_uncollectible(self, idempotency_key=None, **params):
--
stripe/api_resources/invoice.py: @util.class_method_variant("_cls_pay")
stripe/api_resources/invoice.py- def pay(self, idempotency_key=None, **params):
--
stripe/api_resources/invoice.py: @util.class_method_variant("_cls_send_invoice")
stripe/api_resources/invoice.py- def send_invoice(self, idempotency_key=None, **params):
--
stripe/api_resources/invoice.py: @util.class_method_variant("_cls_void_invoice")
stripe/api_resources/invoice.py- def void_invoice(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/authorization.py=class Authorization(ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/issuing/authorization.py: @util.class_method_variant("_cls_approve")
stripe/api_resources/issuing/authorization.py- def approve(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/authorization.py: @util.class_method_variant("_cls_decline")
stripe/api_resources/issuing/authorization.py- def decline(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/card.py=class Card(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/issuing/card.py: @util.class_method_variant("_cls_deliver_card")
stripe/api_resources/issuing/card.py- def deliver_card(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/card.py: @util.class_method_variant("_cls_fail_card")
stripe/api_resources/issuing/card.py- def fail_card(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/card.py: @util.class_method_variant("_cls_return_card")
stripe/api_resources/issuing/card.py- def return_card(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/card.py: @util.class_method_variant("_cls_ship_card")
stripe/api_resources/issuing/card.py- def ship_card(self, idempotency_key=None, **params):
--
stripe/api_resources/issuing/dispute.py=class Dispute(
--
stripe/api_resources/issuing/dispute.py: @util.class_method_variant("_cls_submit")
stripe/api_resources/issuing/dispute.py- def submit(self, idempotency_key=None, **params):
--
stripe/api_resources/order.py=class Order(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/order.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/order.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/order.py: @util.class_method_variant("_cls_list_line_items")
stripe/api_resources/order.py- def list_line_items(self, idempotency_key=None, **params):
--
stripe/api_resources/order.py: @util.class_method_variant("_cls_reopen")
stripe/api_resources/order.py- def reopen(self, idempotency_key=None, **params):
--
stripe/api_resources/order.py: @util.class_method_variant("_cls_submit")
stripe/api_resources/order.py- def submit(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py=class PaymentIntent(
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_apply_customer_balance")
stripe/api_resources/payment_intent.py- def apply_customer_balance(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/payment_intent.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_capture")
stripe/api_resources/payment_intent.py- def capture(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_confirm")
stripe/api_resources/payment_intent.py- def confirm(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_increment_authorization")
stripe/api_resources/payment_intent.py- def increment_authorization(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_intent.py: @util.class_method_variant("_cls_verify_microdeposits")
stripe/api_resources/payment_intent.py- def verify_microdeposits(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_link.py=class PaymentLink(
--
stripe/api_resources/payment_link.py: @util.class_method_variant("_cls_list_line_items")
stripe/api_resources/payment_link.py- def list_line_items(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_method.py=class PaymentMethod(
--
stripe/api_resources/payment_method.py: @util.class_method_variant("_cls_attach")
stripe/api_resources/payment_method.py- def attach(self, idempotency_key=None, **params):
--
stripe/api_resources/payment_method.py: @util.class_method_variant("_cls_detach")
stripe/api_resources/payment_method.py- def detach(self, idempotency_key=None, **params):
--
stripe/api_resources/payout.py=class Payout(
--
stripe/api_resources/payout.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/payout.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/payout.py: @util.class_method_variant("_cls_reverse")
stripe/api_resources/payout.py- def reverse(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py=class Quote(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_accept")
stripe/api_resources/quote.py- def accept(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/quote.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_finalize_quote")
stripe/api_resources/quote.py- def finalize_quote(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_list_computed_upfront_line_items")
stripe/api_resources/quote.py- def list_computed_upfront_line_items(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_list_line_items")
stripe/api_resources/quote.py- def list_line_items(self, idempotency_key=None, **params):
--
stripe/api_resources/quote.py: @util.class_method_variant("_cls_pdf")
stripe/api_resources/quote.py- def pdf(
--
stripe/api_resources/refund.py=class Refund(
--
stripe/api_resources/refund.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/refund.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/refund.py: @util.class_method_variant("_cls_expire")
stripe/api_resources/refund.py- def expire(self, idempotency_key=None, **params):
--
stripe/api_resources/review.py=class Review(ListableAPIResource):
--
stripe/api_resources/review.py: @util.class_method_variant("_cls_approve")
stripe/api_resources/review.py- def approve(self, idempotency_key=None, **params):
--
stripe/api_resources/setup_intent.py=class SetupIntent(
--
stripe/api_resources/setup_intent.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/setup_intent.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/setup_intent.py: @util.class_method_variant("_cls_confirm")
stripe/api_resources/setup_intent.py- def confirm(self, idempotency_key=None, **params):
--
stripe/api_resources/setup_intent.py: @util.class_method_variant("_cls_verify_microdeposits")
stripe/api_resources/setup_intent.py- def verify_microdeposits(self, idempotency_key=None, **params):
--
stripe/api_resources/source.py=class Source(CreateableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/source.py: @util.class_method_variant("_cls_list_source_transactions")
stripe/api_resources/source.py- def list_source_transactions(self, idempotency_key=None, **params):
--
stripe/api_resources/source.py: @util.class_method_variant("_cls_verify")
stripe/api_resources/source.py- def verify(self, idempotency_key=None, **params):
--
stripe/api_resources/subscription.py=class Subscription(
--
stripe/api_resources/subscription.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/subscription.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/subscription.py: @util.class_method_variant("_cls_delete_discount")
stripe/api_resources/subscription.py- def delete_discount(self, idempotency_key=None, **params):
--
stripe/api_resources/subscription_schedule.py=class SubscriptionSchedule(
--
stripe/api_resources/subscription_schedule.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/subscription_schedule.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/subscription_schedule.py: @util.class_method_variant("_cls_release")
stripe/api_resources/subscription_schedule.py- def release(self, idempotency_key=None, **params):
--
stripe/api_resources/terminal/reader.py=class Reader(
--
stripe/api_resources/terminal/reader.py: @util.class_method_variant("_cls_cancel_action")
stripe/api_resources/terminal/reader.py- def cancel_action(self, idempotency_key=None, **params):
--
stripe/api_resources/terminal/reader.py: @util.class_method_variant("_cls_process_payment_intent")
stripe/api_resources/terminal/reader.py- def process_payment_intent(self, idempotency_key=None, **params):
--
stripe/api_resources/terminal/reader.py: @util.class_method_variant("_cls_process_setup_intent")
stripe/api_resources/terminal/reader.py- def process_setup_intent(self, idempotency_key=None, **params):
--
stripe/api_resources/terminal/reader.py: @util.class_method_variant("_cls_set_reader_display")
stripe/api_resources/terminal/reader.py- def set_reader_display(self, idempotency_key=None, **params):
--
stripe/api_resources/terminal/reader.py: @util.class_method_variant("_cls_present_payment_method")
stripe/api_resources/terminal/reader.py- def present_payment_method(self, idempotency_key=None, **params):
--
stripe/api_resources/test_helpers/test_clock.py=class TestClock(
--
stripe/api_resources/test_helpers/test_clock.py: @util.class_method_variant("_cls_advance")
stripe/api_resources/test_helpers/test_clock.py- def advance(self, idempotency_key=None, **params):
--
stripe/api_resources/topup.py=class Topup(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
--
stripe/api_resources/topup.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/topup.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/financial_account.py=class FinancialAccount(
--
stripe/api_resources/treasury/financial_account.py: @util.class_method_variant("_cls_retrieve_features")
stripe/api_resources/treasury/financial_account.py- def retrieve_features(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/financial_account.py: @util.class_method_variant("_cls_update_features")
stripe/api_resources/treasury/financial_account.py- def update_features(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/inbound_transfer.py=class InboundTransfer(CreateableAPIResource, ListableAPIResource):
--
stripe/api_resources/treasury/inbound_transfer.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/treasury/inbound_transfer.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/inbound_transfer.py: @util.class_method_variant("_cls_fail")
stripe/api_resources/treasury/inbound_transfer.py- def fail(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/inbound_transfer.py: @util.class_method_variant("_cls_return_inbound_transfer")
stripe/api_resources/treasury/inbound_transfer.py- def return_inbound_transfer(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/inbound_transfer.py: @util.class_method_variant("_cls_succeed")
stripe/api_resources/treasury/inbound_transfer.py- def succeed(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_payment.py=class OutboundPayment(CreateableAPIResource, ListableAPIResource):
--
stripe/api_resources/treasury/outbound_payment.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/treasury/outbound_payment.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_payment.py: @util.class_method_variant("_cls_fail")
stripe/api_resources/treasury/outbound_payment.py- def fail(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_payment.py: @util.class_method_variant("_cls_post")
stripe/api_resources/treasury/outbound_payment.py- def post(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_payment.py: @util.class_method_variant("_cls_return_outbound_payment")
stripe/api_resources/treasury/outbound_payment.py- def return_outbound_payment(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_transfer.py=class OutboundTransfer(CreateableAPIResource, ListableAPIResource):
--
stripe/api_resources/treasury/outbound_transfer.py: @util.class_method_variant("_cls_cancel")
stripe/api_resources/treasury/outbound_transfer.py- def cancel(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_transfer.py: @util.class_method_variant("_cls_fail")
stripe/api_resources/treasury/outbound_transfer.py- def fail(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_transfer.py: @util.class_method_variant("_cls_post")
stripe/api_resources/treasury/outbound_transfer.py- def post(self, idempotency_key=None, **params):
--
stripe/api_resources/treasury/outbound_transfer.py: @util.class_method_variant("_cls_return_outbound_transfer")
stripe/api_resources/treasury/outbound_transfer.py- def return_outbound_transfer(self, idempotency_key=None, **params):
--
tests/api_resources/abstract/test_custom_method.py=class TestCustomMethod(object):
--
tests/api_resources/abstract/test_custom_method.py: @util.class_method_variant("_cls_do_stuff_new_codegen")
tests/api_resources/abstract/test_custom_method.py- def do_stuff_new_codegen(self, idempotency_key=None, **params): It would kind of suck to go through this with all 86 of them, especially if the result is going to be inaccurate to work around mypy limitations. Maybe it’s worth reopening the conversation with upstream from #7230 about whether they really need this unusual pair of calling conventions. Even if they keep them both for backwards compatibility, it might make sense for them to mark one as deprecated, so we could remove it from the stubs and at least have an accurate type for the other. |
Similar to #7230,
stripe.PaymentIntent.confirm
can be called as aninstance method or a
classmethod
.