Skip to content

Commit

Permalink
Fix incorrect handling of additional request parameters (#850)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamil-stripe authored Aug 3, 2022
1 parent e65630a commit b2014e6
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 2 deletions.
38 changes: 36 additions & 2 deletions stripe/api_resources/abstract/api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,27 @@ def _static_request(
stripe_account=None,
params=None,
):
params = None if params is None else params.copy()
api_key = util.read_special_variable(params, "api_key", api_key)
idempotency_key = util.read_special_variable(
params, "idempotency_key", idempotency_key
)
stripe_version = util.read_special_variable(
params, "stripe_version", stripe_version
)
stripe_account = util.read_special_variable(
params, "stripe_account", stripe_account
)
headers = util.read_special_variable(params, "headers", None)

requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)

if idempotency_key is not None:
headers = {} if headers is None else headers.copy()
headers.update(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, params
Expand All @@ -137,9 +154,26 @@ def _static_request_stream(
stripe_account=None,
params=None,
):
params = None if params is None else params.copy()
api_key = util.read_special_variable(params, "api_key", api_key)
idempotency_key = util.read_special_variable(
params, "idempotency_key", idempotency_key
)
stripe_version = util.read_special_variable(
params, "stripe_version", stripe_version
)
stripe_account = util.read_special_variable(
params, "stripe_account", stripe_account
)
headers = util.read_special_variable(params, "headers", None)

requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)

if idempotency_key is not None:
headers = {} if headers is None else headers.copy()
headers.update(util.populate_headers(idempotency_key))

response, _ = requestor.request_stream(method_, url_, params, headers)
return response
13 changes: 13 additions & 0 deletions stripe/stripe_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,19 @@ def _request(
headers=None,
params=None,
):
params = None if params is None else params.copy()
api_key = util.read_special_variable(params, "api_key", api_key)
idempotency_key = util.read_special_variable(
params, "idempotency_key", idempotency_key
)
stripe_version = util.read_special_variable(
params, "stripe_version", stripe_version
)
stripe_account = util.read_special_variable(
params, "stripe_account", stripe_account
)
headers = util.read_special_variable(params, "headers", headers)

stripe_account = stripe_account or self.stripe_account
stripe_version = stripe_version or self.stripe_version
api_key = api_key or self.api_key
Expand Down
14 changes: 14 additions & 0 deletions stripe/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,20 @@ def populate_headers(idempotency_key):
return None


def read_special_variable(params, key_name, default_value):
value = default_value
params_value = None

if params is not None and key_name in params:
params_value = params[key_name]
del params[key_name]

if value is None:
value = params_value

return value


def merge_dicts(x, y):
z = x.copy()
z.update(y)
Expand Down
19 changes: 19 additions & 0 deletions tests/api_resources/abstract/test_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,25 @@ def test_retrieve_and_refresh(self, request_mock):
with pytest.raises(KeyError):
res["bobble"]

def test_request_with_special_fields_prefers_explicit(self, request_mock):
url = "/v1/myresources/foo"
request_mock.stub_request(
"get",
url,
{"id": "foo2", "bobble": "scrobble"},
)

self.MyResource._static_request(
"get",
"/v1/myresources/foo",
idempotency_key="explicit",
params={"idempotency_key": "params", "bobble": "scrobble"},
)

request_mock.assert_requested(
"get", url, {"bobble": "scrobble"}, {"Idempotency-Key": "explicit"}
)

def test_convert_to_stripe_object(self):
sample = {
"foo": "bar",
Expand Down
111 changes: 111 additions & 0 deletions tests/api_resources/abstract/test_custom_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,37 @@ def do_stream_stuff(self, idempotency_key=None, **params):
headers = util.populate_headers(idempotency_key)
return self.request_stream("post", url, params, headers)

@classmethod
def _cls_do_stuff_new_codegen(
cls,
id,
api_key=None,
stripe_version=None,
stripe_account=None,
**params
):
return cls._static_request(
"post",
"/v1/myresources/{id}/do_the_thing".format(
id=util.sanitize_id(id)
),
api_key=api_key,
stripe_version=stripe_version,
stripe_account=stripe_account,
params=params,
)

@util.class_method_variant("_cls_do_stuff_new_codegen")
def do_stuff_new_codegen(self, idempotency_key=None, **params):
return self._request(
"post",
"/v1/myresources/{id}/do_the_thing".format(
id=util.sanitize_id(self.get("id"))
),
idempotency_key=idempotency_key,
params=params,
)

def test_call_custom_method_class(self, request_mock):
request_mock.stub_request(
"post",
Expand Down Expand Up @@ -193,3 +224,83 @@ def test_call_custom_stream_method_instance(self, request_mock):
body_content = body_content.decode("utf-8")

assert body_content == "response body"

def test_call_custom_method_class_special_fields(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",
stripe_version="2017-08-15",
api_key="APIKEY",
idempotency_key="IdempotencyKey",
stripe_account="Acc",
)

request_mock.assert_requested(
"post",
"/v1/myresources/mid/do_the_thing",
{"foo": "bar"},
{"Idempotency-Key": "IdempotencyKey"},
)
request_mock.assert_api_version("2017-08-15")

def test_call_custom_method_class_newcodegen_special_fields(
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_new_codegen(
"mid",
foo="bar",
stripe_version="2017-08-15",
api_key="APIKEY",
idempotency_key="IdempotencyKey",
stripe_account="Acc",
)

request_mock.assert_requested(
"post",
"/v1/myresources/mid/do_the_thing",
{"foo": "bar"},
{"Idempotency-Key": "IdempotencyKey"},
)
request_mock.assert_api_version("2017-08-15")

def test_call_custom_method_instance_newcodegen_special_fields(
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_new_codegen(
foo="bar",
stripe_version="2017-08-15",
api_key="APIKEY",
idempotency_key="IdempotencyKey",
stripe_account="Acc",
headers={"extra_header": "val"},
)

request_mock.assert_requested(
"post",
"/v1/myresources/mid/do_the_thing",
{"foo": "bar"},
{"Idempotency-Key": "IdempotencyKey", "extra_header": "val"},
)
request_mock.assert_api_version("2017-08-15")
25 changes: 25 additions & 0 deletions tests/api_resources/abstract/test_deletable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,28 @@ def test_delete_instance(self, request_mock):

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

def test_delete_with_all_special_fields(self, request_mock):
request_mock.stub_request(
"delete",
"/v1/mydeletables/foo",
{"id": "foo", "bobble": "new_scrobble"},
{"Idempotency-Key": "IdempotencyKey"},
)

self.MyDeletable.delete(
"foo",
stripe_version="2017-08-15",
api_key="APIKEY",
idempotency_key="IdempotencyKey",
stripe_account="Acc",
bobble="new_scrobble",
)

request_mock.assert_requested(
"delete",
"/v1/mydeletables/foo",
{"bobble": "new_scrobble"},
{"Idempotency-Key": "IdempotencyKey"},
)
request_mock.assert_api_version("2017-08-15")
26 changes: 26 additions & 0 deletions tests/api_resources/abstract/test_updateable_api_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,29 @@ def test_retrieve_and_update_with_stripe_version(self, request_mock, obj):
res.save()

request_mock.assert_api_version("2017-08-15")

def test_modify_with_all_special_fields(self, request_mock, obj):
request_mock.stub_request(
"post",
"/v1/myupdateables/foo",
{"id": "foo", "bobble": "new_scrobble"},
{"Idempotency-Key": "IdempotencyKey"},
)

self.MyUpdateable.modify(
"foo",
stripe_version="2017-08-15",
api_key="APIKEY",
idempotency_key="IdempotencyKey",
stripe_account="Acc",
bobble="new_scrobble",
headers={"extra_header": "val"},
)

request_mock.assert_requested(
"post",
"/v1/myupdateables/foo",
{"bobble": "new_scrobble"},
{"Idempotency-Key": "IdempotencyKey", "extra_header": "val"},
)
request_mock.assert_api_version("2017-08-15")

0 comments on commit b2014e6

Please sign in to comment.