Skip to content

Commit 97205a1

Browse files
authored
custom_method decorator for defining static methods for custom API requests (#547)
* `custom_method` decorator for defining static methods for custom API requests * Add custom methods to all resources
1 parent 88d2a2b commit 97205a1

34 files changed

Lines changed: 301 additions & 18 deletions

stripe/api_resources/abstract/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
)
2222
from stripe.api_resources.abstract.verify_mixin import VerifyMixin
2323

24+
from stripe.api_resources.abstract.custom_method import custom_method
25+
2426
from stripe.api_resources.abstract.nested_resource_class_methods import (
2527
nested_resource_class_methods,
2628
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from __future__ import absolute_import, division, print_function
2+
3+
from stripe import util
4+
from stripe.six.moves.urllib.parse import quote_plus
5+
6+
7+
def custom_method(name, http_verb, http_path=None):
8+
if http_verb not in ["get", "post", "delete"]:
9+
raise ValueError(
10+
"Invalid http_verb: %s. Must be one of 'get', 'post' or 'delete'"
11+
% http_verb
12+
)
13+
if http_path is None:
14+
http_path = name
15+
16+
def wrapper(cls):
17+
def custom_method_request(cls, sid, **params):
18+
url = "%s/%s/%s" % (
19+
cls.class_url(),
20+
quote_plus(util.utf8(sid)),
21+
http_path,
22+
)
23+
return cls._static_request(http_verb, url, **params)
24+
25+
existing_method = getattr(cls, name, None)
26+
if existing_method is None:
27+
setattr(cls, name, classmethod(custom_method_request))
28+
else:
29+
# If a method with the same name we want to use already exists on
30+
# the class, we assume it's an instance method. In this case, the
31+
# new class method is prefixed with `_cls_`, and the original
32+
# instance method is decorated with `util.class_method_variant` so
33+
# that the new class method is called when the original method is
34+
# called as a class method.
35+
setattr(cls, "_cls_" + name, classmethod(custom_method_request))
36+
instance_method = util.class_method_variant("_cls_" + name)(
37+
existing_method
38+
)
39+
setattr(cls, name, instance_method)
40+
41+
return cls
42+
43+
return wrapper

stripe/api_resources/account.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
from stripe.api_resources.abstract import UpdateableAPIResource
88
from stripe.api_resources.abstract import ListableAPIResource
99
from stripe.api_resources.abstract import nested_resource_class_methods
10-
10+
from stripe.api_resources.abstract import custom_method
1111
from stripe.six.moves.urllib.parse import quote_plus
1212

1313

14+
@custom_method("reject", http_verb="post")
1415
@nested_resource_class_methods(
1516
"external_account",
1617
operations=["create", "retrieve", "update", "delete", "list"],

stripe/api_resources/charge.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from stripe.api_resources.abstract import CreateableAPIResource
55
from stripe.api_resources.abstract import UpdateableAPIResource
66
from stripe.api_resources.abstract import ListableAPIResource
7+
from stripe.api_resources.abstract import custom_method
78

89

10+
@custom_method("capture", http_verb="post")
911
class Charge(
1012
CreateableAPIResource, ListableAPIResource, UpdateableAPIResource
1113
):

stripe/api_resources/customer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
from stripe.api_resources.abstract import DeletableAPIResource
66
from stripe.api_resources.abstract import UpdateableAPIResource
77
from stripe.api_resources.abstract import ListableAPIResource
8+
from stripe.api_resources.abstract import custom_method
89
from stripe.api_resources.abstract import nested_resource_class_methods
910

1011

12+
@custom_method("delete_discount", http_verb="delete", http_path="discount")
1113
@nested_resource_class_methods(
1214
"source", operations=["create", "retrieve", "update", "delete", "list"]
1315
)

stripe/api_resources/dispute.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
from stripe import util
44
from stripe.api_resources.abstract import ListableAPIResource
55
from stripe.api_resources.abstract import UpdateableAPIResource
6+
from stripe.api_resources.abstract import custom_method
67

78

9+
@custom_method("close", http_verb="post")
810
class Dispute(ListableAPIResource, UpdateableAPIResource):
911
OBJECT_NAME = "dispute"
1012

stripe/api_resources/invoice.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55
from stripe.api_resources.abstract import DeletableAPIResource
66
from stripe.api_resources.abstract import UpdateableAPIResource
77
from stripe.api_resources.abstract import ListableAPIResource
8+
from stripe.api_resources.abstract import custom_method
89

910

11+
@custom_method("finalize_invoice", http_verb="post", http_path="finalize")
12+
@custom_method("mark_uncollectible", http_verb="post")
13+
@custom_method("pay", http_verb="post")
14+
@custom_method("send_invoice", http_verb="post", http_path="send")
15+
@custom_method("void_invoice", http_verb="post", http_path="void")
1016
class Invoice(
1117
CreateableAPIResource,
1218
UpdateableAPIResource,

stripe/api_resources/issuing/authorization.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
from stripe import util
44
from stripe.api_resources.abstract import UpdateableAPIResource
55
from stripe.api_resources.abstract import ListableAPIResource
6+
from stripe.api_resources.abstract import custom_method
67

78

9+
@custom_method("approve", http_verb="post")
10+
@custom_method("decline", http_verb="post")
811
class Authorization(ListableAPIResource, UpdateableAPIResource):
912
OBJECT_NAME = "issuing.authorization"
1013

stripe/api_resources/issuing/card.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
from stripe.api_resources.abstract import CreateableAPIResource
44
from stripe.api_resources.abstract import UpdateableAPIResource
55
from stripe.api_resources.abstract import ListableAPIResource
6+
from stripe.api_resources.abstract import custom_method
67

78

9+
@custom_method("details", http_verb="get")
810
class Card(CreateableAPIResource, ListableAPIResource, UpdateableAPIResource):
911
OBJECT_NAME = "issuing.card"
1012

stripe/api_resources/order.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
from stripe.api_resources.abstract import CreateableAPIResource
55
from stripe.api_resources.abstract import UpdateableAPIResource
66
from stripe.api_resources.abstract import ListableAPIResource
7+
from stripe.api_resources.abstract import custom_method
78

89

10+
@custom_method("pay", http_verb="post")
11+
@custom_method("return_order", http_verb="post", http_path="returns")
912
class Order(CreateableAPIResource, UpdateableAPIResource, ListableAPIResource):
1013
OBJECT_NAME = "order"
1114

0 commit comments

Comments
 (0)