1from __future__ import absolute_import, division, print_function
2
3from stripe import util
4from stripe.six.moves.urllib.parse import quote_plus
5
6
7def 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
44