Skip to content

Commit

Permalink
Add support for passing full objects instead of IDs to custom methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ob-stripe committed Aug 6, 2019
1 parent 76c35ae commit 7018dd5
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
8 changes: 8 additions & 0 deletions stripe/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,16 @@ def __get__(self, obj=None, objtype=None):
@functools.wraps(self.method)
def _wrapper(*args, **kwargs):
if obj is not None:
# Method was called as an instance method, e.g.
# instance.method(...)
return self.method(obj, *args, **kwargs)
elif len(args) > 0 and isinstance(args[0], objtype):
# Method was called as a class method with the instance as the
# first argument, e.g. Class.method(instance, ...) which in
# Python is the same thing as calling an instance method
return self.method(args[0], *args[1:], **kwargs)
else:
# Method was called as a class method, e.g. Class.method(...)
class_method = getattr(objtype, self.class_method_name)
return class_method(*args, **kwargs)

Expand Down
62 changes: 62 additions & 0 deletions tests/api_resources/abstract/test_custom_method.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from __future__ import absolute_import, division, print_function

import stripe
from stripe import util


class TestCustomMethod(object):
@stripe.api_resources.abstract.custom_method(
"do_stuff", http_verb="post", http_path="do_the_thing"
)
class MyResource(stripe.api_resources.abstract.APIResource):
OBJECT_NAME = "myresource"

def do_stuff(self, idempotency_key=None, **params):
url = self.instance_url() + "/do_the_thing"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self

def test_call_custom_method_class(self, request_mock):
request_mock.stub_request(
"post",
"/v1/myresources/mid/do_the_thing",
{"id": "mid", "thing_done": True},
rheaders={"request-id": "req_id"},
)

self.MyResource.do_stuff("mid", foo="bar")

request_mock.assert_requested(
"post", "/v1/myresources/mid/do_the_thing", {"foo": "bar"}
)

def test_call_custom_method_class_with_object(self, request_mock):
request_mock.stub_request(
"post",
"/v1/myresources/mid/do_the_thing",
{"id": "mid", "thing_done": True},
rheaders={"request-id": "req_id"},
)

obj = self.MyResource.construct_from({"id": "mid"}, "mykey")
self.MyResource.do_stuff(obj, foo="bar")

request_mock.assert_requested(
"post", "/v1/myresources/mid/do_the_thing", {"foo": "bar"}
)

def test_call_custom_method_instance(self, request_mock):
request_mock.stub_request(
"post",
"/v1/myresources/mid/do_the_thing",
{"id": "mid", "thing_done": True},
rheaders={"request-id": "req_id"},
)

obj = self.MyResource.construct_from({"id": "mid"}, "mykey")
obj.do_stuff(foo="bar")

request_mock.assert_requested(
"post", "/v1/myresources/mid/do_the_thing", {"foo": "bar"}
)
19 changes: 19 additions & 0 deletions tests/api_resources/abstract/test_deletable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,25 @@ def test_delete_class(self, request_mock):
assert obj.last_response is not None
assert obj.last_response.request_id == "req_id"

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

obj = self.MyDeletable.construct_from({"id": "mid"}, "mykey")

self.MyDeletable.delete(obj)

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",
Expand Down

0 comments on commit 7018dd5

Please sign in to comment.