diff --git a/stripe/api_resources/abstract/api_resource.py b/stripe/api_resources/abstract/api_resource.py index 664ea1c93..c2bcd8c61 100644 --- a/stripe/api_resources/abstract/api_resource.py +++ b/stripe/api_resources/abstract/api_resource.py @@ -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 @@ -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 diff --git a/stripe/stripe_object.py b/stripe/stripe_object.py index a06cedd2e..80ca5d664 100644 --- a/stripe/stripe_object.py +++ b/stripe/stripe_object.py @@ -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 diff --git a/stripe/util.py b/stripe/util.py index 619f9cb1f..d4c55392f 100644 --- a/stripe/util.py +++ b/stripe/util.py @@ -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) diff --git a/tests/api_resources/abstract/test_api_resource.py b/tests/api_resources/abstract/test_api_resource.py index 9bed856b9..13794611d 100644 --- a/tests/api_resources/abstract/test_api_resource.py +++ b/tests/api_resources/abstract/test_api_resource.py @@ -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", diff --git a/tests/api_resources/abstract/test_custom_method.py b/tests/api_resources/abstract/test_custom_method.py index f02a87e9e..f3471ebf6 100644 --- a/tests/api_resources/abstract/test_custom_method.py +++ b/tests/api_resources/abstract/test_custom_method.py @@ -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", @@ -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") diff --git a/tests/api_resources/abstract/test_deletable_api_resource.py b/tests/api_resources/abstract/test_deletable_api_resource.py index e8a452c8b..532bd493e 100644 --- a/tests/api_resources/abstract/test_deletable_api_resource.py +++ b/tests/api_resources/abstract/test_deletable_api_resource.py @@ -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") diff --git a/tests/api_resources/abstract/test_updateable_api_resource.py b/tests/api_resources/abstract/test_updateable_api_resource.py index 21c577459..161961562 100644 --- a/tests/api_resources/abstract/test_updateable_api_resource.py +++ b/tests/api_resources/abstract/test_updateable_api_resource.py @@ -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")