Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions stripe/_api_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
_default_proxy: Optional[str] = None


def is_v2_delete_resp(method: str, api_mode: ApiMode) -> bool:
return method == "delete" and api_mode == "V2"


class _APIRequestor(object):
_instance: ClassVar["_APIRequestor|None"] = None

Expand Down Expand Up @@ -201,6 +205,7 @@ def request(
params=params,
requestor=requestor,
api_mode=api_mode,
is_v2_deleted_object=is_v2_delete_resp(method, api_mode),
)

return obj
Expand Down Expand Up @@ -234,6 +239,7 @@ async def request_async(
params=params,
requestor=requestor,
api_mode=api_mode,
is_v2_deleted_object=is_v2_delete_resp(method, api_mode),
)

return obj
Expand Down
11 changes: 10 additions & 1 deletion stripe/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ def _convert_to_stripe_object(
klass_: Optional[Type["StripeObject"]] = None,
requestor: "_APIRequestor",
api_mode: ApiMode,
is_v2_deleted_object: bool = False,
) -> "StripeObject": ...


Expand All @@ -283,6 +284,7 @@ def _convert_to_stripe_object(
klass_: Optional[Type["StripeObject"]] = None,
requestor: "_APIRequestor",
api_mode: ApiMode,
is_v2_deleted_object: bool = False,
) -> List["StripeObject"]: ...


Expand All @@ -293,6 +295,8 @@ def _convert_to_stripe_object(
klass_: Optional[Type["StripeObject"]] = None,
requestor: "_APIRequestor",
api_mode: ApiMode,
# if true, we should ignore the `object` field for finding the class name. This is set by the API requestor
is_v2_deleted_object: bool = False,
) -> Union["StripeObject", List["StripeObject"]]:
# If we get a StripeResponse, we'll want to return a
# StripeObject with the last_response field filled out with
Expand Down Expand Up @@ -321,7 +325,12 @@ def _convert_to_stripe_object(
resp = resp.copy()
klass_name = resp.get("object")
if isinstance(klass_name, str):
if api_mode == "V2" and klass_name == "v2.core.event":
if is_v2_deleted_object:
# circular import
from stripe.v2._deleted_object import DeletedObject

klass = DeletedObject
elif api_mode == "V2" and klass_name == "v2.core.event":
event_name = resp.get("type", "")
klass = get_thin_event_classes().get(
event_name, stripe.StripeObject
Expand Down
1 change: 1 addition & 0 deletions stripe/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from stripe.v2 import billing as billing, core as core
from stripe.v2._billing_service import BillingService as BillingService
from stripe.v2._core_service import CoreService as CoreService
from stripe.v2._deleted_object import DeletedObject as DeletedObject
from stripe.v2._event import Event as Event
from stripe.v2._event_destination import EventDestination as EventDestination
# The end of the section generated from our OpenAPI spec
15 changes: 15 additions & 0 deletions stripe/v2/_deleted_object.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# File generated from our OpenAPI spec
from stripe._stripe_object import StripeObject
from typing import Optional


class DeletedObject(StripeObject):
id: str
"""
The ID of the object that's being deleted.
"""
object: Optional[str]
"""
String representing the object's type. Objects of the same type share the same value of the object field.
"""
13 changes: 7 additions & 6 deletions stripe/v2/core/_event_destination_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from stripe._request_options import RequestOptions
from stripe._stripe_service import StripeService
from stripe._util import sanitize_id
from stripe.v2._deleted_object import DeletedObject
from stripe.v2._event import Event
from stripe.v2._event_destination import EventDestination
from stripe.v2._list_object import ListObject
from typing import Dict, List, Optional, cast
from typing import Dict, List, cast
from typing_extensions import Literal, NotRequired, TypedDict


Expand Down Expand Up @@ -124,7 +125,7 @@ class UpdateParams(TypedDict):
"""
Additional fields to include in the response. Currently supports `webhook_endpoint.url`.
"""
metadata: NotRequired[Dict[str, Optional[str]]]
metadata: NotRequired[Dict[str, str]]
"""
Metadata.
"""
Expand Down Expand Up @@ -226,12 +227,12 @@ def delete(
id: str,
params: "EventDestinationService.DeleteParams" = {},
options: RequestOptions = {},
) -> EventDestination:
) -> DeletedObject:
"""
Delete an event destination.
"""
return cast(
EventDestination,
DeletedObject,
self._request(
"delete",
"/v2/core/event_destinations/{id}".format(id=sanitize_id(id)),
Expand All @@ -246,12 +247,12 @@ async def delete_async(
id: str,
params: "EventDestinationService.DeleteParams" = {},
options: RequestOptions = {},
) -> EventDestination:
) -> DeletedObject:
"""
Delete an event destination.
"""
return cast(
EventDestination,
DeletedObject,
await self._request_async(
"delete",
"/v2/core/event_destinations/{id}".format(id=sanitize_id(id)),
Expand Down
49 changes: 49 additions & 0 deletions tests/test_api_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import stripe
from stripe import util
from stripe._api_requestor import _api_encode, _APIRequestor
from stripe._customer import Customer
from stripe._request_options import RequestOptions
from stripe._requestor_options import (
RequestorOptions,
Expand All @@ -21,6 +22,7 @@
StripeStreamResponse,
StripeStreamResponseAsync,
)
from stripe.v2._deleted_object import DeletedObject
from tests.http_client_mock import HTTPClientMock

VALID_API_METHODS = ("get", "post", "delete")
Expand Down Expand Up @@ -471,6 +473,53 @@ def test_methods_with_params_and_streaming_response(
)
http_client_mock.assert_requested(method, abs_url=abs_url)

def test_delete_methods(self, requestor, http_client_mock):
for path in [self.v1_path, self.v2_path]:
method = "delete"
http_client_mock.stub_request(
method,
path=path,
rbody=json.dumps({"id": "abc_123", "object": "customer"}),
rcode=200,
)

resp = requestor.request(method, path, {}, base_address="api")

http_client_mock.assert_requested(method, post_data=None)

if path == self.v1_path:
assert isinstance(resp, Customer)
else:
assert isinstance(resp, DeletedObject)

assert resp.id == "abc_123"
assert resp.object == "customer"

@pytest.mark.anyio
async def test_delete_methods_async(self, requestor, http_client_mock):
for path in [self.v1_path, self.v2_path]:
method = "delete"
http_client_mock.stub_request(
method,
path=path,
rbody=json.dumps({"id": "abc_123", "object": "customer"}),
rcode=200,
)

resp = await requestor.request_async(
method, path, {}, base_address="api"
)

http_client_mock.assert_requested(method, post_data=None)

if path == self.v1_path:
assert isinstance(resp, Customer)
else:
assert isinstance(resp, DeletedObject)

assert resp.id == "abc_123"
assert resp.object == "customer"

def test_uses_headers(self, requestor, http_client_mock):
http_client_mock.stub_request(
"get", path=self.v1_path, rbody="{}", rcode=200
Expand Down