Skip to content

Commit

Permalink
Merge pull request #543 from stripe/ob-delete-class-method
Browse files Browse the repository at this point in the history
Add support for static deletion
  • Loading branch information
ob-stripe authored Apr 3, 2019
2 parents 77e3a05 + d085b71 commit 88d2a2b
Show file tree
Hide file tree
Showing 26 changed files with 201 additions and 26 deletions.
22 changes: 21 additions & 1 deletion stripe/api_resources/abstract/api_resource.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import absolute_import, division, print_function

from stripe import error, util, six
from stripe import api_requestor, error, util, six
from stripe.stripe_object import StripeObject
from stripe.six.moves.urllib.parse import quote_plus

Expand Down Expand Up @@ -43,3 +43,23 @@ def instance_url(self):
base = self.class_url()
extn = quote_plus(id)
return "%s/%s" % (base, extn)

@classmethod
def _static_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
8 changes: 8 additions & 0 deletions stripe/api_resources/abstract/deletable_api_resource.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
from __future__ import absolute_import, division, print_function

from stripe import util
from stripe.api_resources.abstract.api_resource import APIResource
from stripe.six.moves.urllib.parse import quote_plus


class DeletableAPIResource(APIResource):
@classmethod
def _cls_delete(cls, sid, **params):
url = "%s/%s" % (cls.class_url(), quote_plus(util.utf8(sid)))
return cls._static_request("delete", url, **params)

@util.class_method_variant("_cls_delete")
def delete(self, **params):
self.refresh_from(self.request("delete", self.instance_url(), params))
return self
23 changes: 2 additions & 21 deletions stripe/api_resources/abstract/updateable_api_resource.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,15 @@
from __future__ import absolute_import, division, print_function

from stripe import api_requestor, util
from stripe import util
from stripe.api_resources.abstract.api_resource import APIResource
from stripe.six.moves.urllib.parse import quote_plus


class UpdateableAPIResource(APIResource):
@classmethod
def _modify(
cls,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request("post", url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)

@classmethod
def modify(cls, sid, **params):
url = "%s/%s" % (cls.class_url(), quote_plus(util.utf8(sid)))
return cls._modify(url, **params)
return cls._static_request("post", url, **params)

def save(self, idempotency_key=None):
updated_params = self.serialize(None)
Expand Down
3 changes: 2 additions & 1 deletion stripe/api_resources/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def retrieve(cls, id=None, api_key=None, **params):

@classmethod
def modify(cls, id=None, **params):
return cls._modify(cls._build_instance_url(id), **params)
url = cls._build_instance_url(id)
return cls._static_request("post", url, **params)

@classmethod
def _build_instance_url(cls, sid):
Expand Down
2 changes: 1 addition & 1 deletion stripe/api_resources/alipay_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def instance_url(self):
@classmethod
def modify(cls, customer, id, **params):
url = cls._build_instance_url(customer, id)
return cls._modify(url, **params)
return cls._static_request("post", url, **params)

@classmethod
def retrieve(
Expand Down
2 changes: 1 addition & 1 deletion stripe/api_resources/application_fee_refund.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def _build_instance_url(cls, fee, sid):
@classmethod
def modify(cls, fee, sid, **params):
url = cls._build_instance_url(fee, sid)
return cls._modify(url, **params)
return cls._static_request("post", url, **params)

def instance_url(self):
return self._build_instance_url(self.fee, self.id)
Expand Down
21 changes: 21 additions & 0 deletions stripe/util.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import absolute_import, division, print_function

import functools
import hmac
import io
import logging
Expand Down Expand Up @@ -285,3 +286,23 @@ def populate_headers(idempotency_key):
if idempotency_key is not None:
return {"Idempotency-Key": idempotency_key}
return None


class class_method_variant(object):
def __init__(self, class_method_name):
self.class_method_name = class_method_name

def __call__(self, method):
self.method = method
return self

def __get__(self, obj=None, objtype=None):
@functools.wraps(self.method)
def _wrapper(*args, **kwargs):
if obj is not None:
return self.method(obj, *args, **kwargs)
else:
class_method = getattr(objtype, self.class_method_name)
return class_method(*args, **kwargs)

return _wrapper
19 changes: 18 additions & 1 deletion tests/api_resources/abstract/test_deletable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,24 @@ class TestDeletableAPIResource(object):
class MyDeletable(stripe.api_resources.abstract.DeletableAPIResource):
OBJECT_NAME = "mydeletable"

def test_delete(self, request_mock):
def test_delete_class(self, request_mock):
request_mock.stub_request(
"delete",
"/v1/mydeletables/mid",
{"id": "mid", "deleted": True},
rheaders={"request-id": "req_id"},
)

obj = self.MyDeletable.delete("mid")

request_mock.assert_requested("delete", "/v1/mydeletables/mid", {})
assert obj.deleted is True
assert obj.id == "mid"

assert obj.last_response is not None
assert obj.last_response.request_id == "req_id"

def test_delete_instance(self, request_mock):
request_mock.stub_request(
"delete",
"/v1/mydeletables/mid",
Expand Down
7 changes: 7 additions & 0 deletions tests/api_resources/radar/test_value_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/radar/value_lists/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.radar.ValueList.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/radar/value_lists/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/radar/test_value_list_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/radar/value_list_items/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.radar.ValueListItem.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/radar/value_list_items/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/terminal/test_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/terminal/locations/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.terminal.Location.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/terminal/locations/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/terminal/test_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/terminal/readers/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.terminal.Reader.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/terminal/readers/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ def test_is_deletable(self, request_mock):
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Account.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/accounts/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_retrieve_no_id(self, request_mock):
resource = stripe.Account.retrieve()
request_mock.assert_requested("get", "/v1/account")
Expand Down
7 changes: 7 additions & 0 deletions tests/api_resources/test_apple_pay_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/apple_pay/domains/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.ApplePayDomain.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/apple_pay/domains/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_coupon.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/coupons/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Coupon.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/coupons/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ def test_is_deletable(self, request_mock):
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Customer.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/customers/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete_discount(self, request_mock):
resource = stripe.Customer.retrieve(TEST_RESOURCE_ID)
resource.delete_discount()
Expand Down
8 changes: 8 additions & 0 deletions tests/api_resources/test_ephemeral_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@ def test_is_deletable(self, request_mock):
request_mock.assert_requested(
"delete", "/v1/ephemeral_keys/%s" % resource.id
)
assert isinstance(resource, stripe.EphemeralKey)

def test_can_delete(self, request_mock):
resource = stripe.EphemeralKey.delete("ephkey_123")
request_mock.assert_requested(
"delete", "/v1/ephemeral_keys/ephkey_123"
)
assert isinstance(resource, stripe.EphemeralKey)
7 changes: 7 additions & 0 deletions tests/api_resources/test_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ def test_is_deletable(self, request_mock):
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Invoice.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/invoices/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_finalize_invoice(self, request_mock):
resource = stripe.Invoice.retrieve(TEST_RESOURCE_ID)
resource = resource.finalize_invoice()
Expand Down
7 changes: 7 additions & 0 deletions tests/api_resources/test_invoice_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ def test_is_saveable(self, request_mock):
"post", "/v1/invoiceitems/%s" % TEST_RESOURCE_ID
)

def test_can_delete(self, request_mock):
resource = stripe.InvoiceItem.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/invoiceitems/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_is_modifiable(self, request_mock):
resource = stripe.InvoiceItem.modify(
TEST_RESOURCE_ID, metadata={"key": "value"}
Expand Down
7 changes: 7 additions & 0 deletions tests/api_resources/test_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/plans/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Plan.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/plans/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/products/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Product.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/products/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_recipient.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/recipients/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.Recipient.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/recipients/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_sku.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/skus/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.SKU.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/skus/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ def test_is_deletable(self, request_mock):
)
assert isinstance(resource, stripe.Subscription)

def test_can_delete(self, request_mock):
resource = stripe.Subscription.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/subscriptions/%s" % TEST_RESOURCE_ID
)
assert isinstance(resource, stripe.Subscription)

def test_can_delete_discount(self, request_mock):
sub = stripe.Subscription.retrieve(TEST_RESOURCE_ID)
sub.delete_discount()
Expand Down
7 changes: 7 additions & 0 deletions tests/api_resources/test_subscription_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/subscription_items/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.SubscriptionItem.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/subscription_items/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True
7 changes: 7 additions & 0 deletions tests/api_resources/test_webhook_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,10 @@ def test_is_deletable(self, request_mock):
"delete", "/v1/webhook_endpoints/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

def test_can_delete(self, request_mock):
resource = stripe.WebhookEndpoint.delete(TEST_RESOURCE_ID)
request_mock.assert_requested(
"delete", "/v1/webhook_endpoints/%s" % TEST_RESOURCE_ID
)
assert resource.deleted is True

0 comments on commit 88d2a2b

Please sign in to comment.