Skip to content

Commit be8cab1

Browse files
add support for v2 deleted objects (#1543)
* add support for v2 deleted objects
1 parent 68adcec commit be8cab1

File tree

6 files changed

+88
-7
lines changed

6 files changed

+88
-7
lines changed

stripe/_api_requestor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
_default_proxy: Optional[str] = None
6767

6868

69+
def is_v2_delete_resp(method: str, api_mode: ApiMode) -> bool:
70+
return method == "delete" and api_mode == "V2"
71+
72+
6973
class _APIRequestor(object):
7074
_instance: ClassVar["_APIRequestor|None"] = None
7175

@@ -201,6 +205,7 @@ def request(
201205
params=params,
202206
requestor=requestor,
203207
api_mode=api_mode,
208+
is_v2_deleted_object=is_v2_delete_resp(method, api_mode),
204209
)
205210

206211
return obj
@@ -234,6 +239,7 @@ async def request_async(
234239
params=params,
235240
requestor=requestor,
236241
api_mode=api_mode,
242+
is_v2_deleted_object=is_v2_delete_resp(method, api_mode),
237243
)
238244

239245
return obj

stripe/_util.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ def _convert_to_stripe_object(
272272
klass_: Optional[Type["StripeObject"]] = None,
273273
requestor: "_APIRequestor",
274274
api_mode: ApiMode,
275+
is_v2_deleted_object: bool = False,
275276
) -> "StripeObject": ...
276277

277278

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

288290

@@ -293,6 +295,8 @@ def _convert_to_stripe_object(
293295
klass_: Optional[Type["StripeObject"]] = None,
294296
requestor: "_APIRequestor",
295297
api_mode: ApiMode,
298+
# if true, we should ignore the `object` field for finding the class name. This is set by the API requestor
299+
is_v2_deleted_object: bool = False,
296300
) -> Union["StripeObject", List["StripeObject"]]:
297301
# If we get a StripeResponse, we'll want to return a
298302
# StripeObject with the last_response field filled out with
@@ -321,7 +325,12 @@ def _convert_to_stripe_object(
321325
resp = resp.copy()
322326
klass_name = resp.get("object")
323327
if isinstance(klass_name, str):
324-
if api_mode == "V2" and klass_name == "v2.core.event":
328+
if is_v2_deleted_object:
329+
# circular import
330+
from stripe.v2._deleted_object import DeletedObject
331+
332+
klass = DeletedObject
333+
elif api_mode == "V2" and klass_name == "v2.core.event":
325334
event_name = resp.get("type", "")
326335
klass = get_thin_event_classes().get(
327336
event_name, stripe.StripeObject

stripe/v2/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from stripe.v2 import billing as billing, core as core
77
from stripe.v2._billing_service import BillingService as BillingService
88
from stripe.v2._core_service import CoreService as CoreService
9+
from stripe.v2._deleted_object import DeletedObject as DeletedObject
910
from stripe.v2._event import Event as Event
1011
from stripe.v2._event_destination import EventDestination as EventDestination
1112
# The end of the section generated from our OpenAPI spec

stripe/v2/_deleted_object.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# -*- coding: utf-8 -*-
2+
# File generated from our OpenAPI spec
3+
from stripe._stripe_object import StripeObject
4+
from typing import Optional
5+
6+
7+
class DeletedObject(StripeObject):
8+
id: str
9+
"""
10+
The ID of the object that's being deleted.
11+
"""
12+
object: Optional[str]
13+
"""
14+
String representing the object's type. Objects of the same type share the same value of the object field.
15+
"""

stripe/v2/core/_event_destination_service.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from stripe._request_options import RequestOptions
44
from stripe._stripe_service import StripeService
55
from stripe._util import sanitize_id
6+
from stripe.v2._deleted_object import DeletedObject
67
from stripe.v2._event import Event
78
from stripe.v2._event_destination import EventDestination
89
from stripe.v2._list_object import ListObject
9-
from typing import Dict, List, Optional, cast
10+
from typing import Dict, List, cast
1011
from typing_extensions import Literal, NotRequired, TypedDict
1112

1213

@@ -124,7 +125,7 @@ class UpdateParams(TypedDict):
124125
"""
125126
Additional fields to include in the response. Currently supports `webhook_endpoint.url`.
126127
"""
127-
metadata: NotRequired[Dict[str, Optional[str]]]
128+
metadata: NotRequired[Dict[str, str]]
128129
"""
129130
Metadata.
130131
"""
@@ -226,12 +227,12 @@ def delete(
226227
id: str,
227228
params: "EventDestinationService.DeleteParams" = {},
228229
options: RequestOptions = {},
229-
) -> EventDestination:
230+
) -> DeletedObject:
230231
"""
231232
Delete an event destination.
232233
"""
233234
return cast(
234-
EventDestination,
235+
DeletedObject,
235236
self._request(
236237
"delete",
237238
"/v2/core/event_destinations/{id}".format(id=sanitize_id(id)),
@@ -246,12 +247,12 @@ async def delete_async(
246247
id: str,
247248
params: "EventDestinationService.DeleteParams" = {},
248249
options: RequestOptions = {},
249-
) -> EventDestination:
250+
) -> DeletedObject:
250251
"""
251252
Delete an event destination.
252253
"""
253254
return cast(
254-
EventDestination,
255+
DeletedObject,
255256
await self._request_async(
256257
"delete",
257258
"/v2/core/event_destinations/{id}".format(id=sanitize_id(id)),

tests/test_api_requestor.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import stripe
1212
from stripe import util
1313
from stripe._api_requestor import _api_encode, _APIRequestor
14+
from stripe._customer import Customer
1415
from stripe._request_options import RequestOptions
1516
from stripe._requestor_options import (
1617
RequestorOptions,
@@ -21,6 +22,7 @@
2122
StripeStreamResponse,
2223
StripeStreamResponseAsync,
2324
)
25+
from stripe.v2._deleted_object import DeletedObject
2426
from tests.http_client_mock import HTTPClientMock
2527

2628
VALID_API_METHODS = ("get", "post", "delete")
@@ -471,6 +473,53 @@ def test_methods_with_params_and_streaming_response(
471473
)
472474
http_client_mock.assert_requested(method, abs_url=abs_url)
473475

476+
def test_delete_methods(self, requestor, http_client_mock):
477+
for path in [self.v1_path, self.v2_path]:
478+
method = "delete"
479+
http_client_mock.stub_request(
480+
method,
481+
path=path,
482+
rbody=json.dumps({"id": "abc_123", "object": "customer"}),
483+
rcode=200,
484+
)
485+
486+
resp = requestor.request(method, path, {}, base_address="api")
487+
488+
http_client_mock.assert_requested(method, post_data=None)
489+
490+
if path == self.v1_path:
491+
assert isinstance(resp, Customer)
492+
else:
493+
assert isinstance(resp, DeletedObject)
494+
495+
assert resp.id == "abc_123"
496+
assert resp.object == "customer"
497+
498+
@pytest.mark.anyio
499+
async def test_delete_methods_async(self, requestor, http_client_mock):
500+
for path in [self.v1_path, self.v2_path]:
501+
method = "delete"
502+
http_client_mock.stub_request(
503+
method,
504+
path=path,
505+
rbody=json.dumps({"id": "abc_123", "object": "customer"}),
506+
rcode=200,
507+
)
508+
509+
resp = await requestor.request_async(
510+
method, path, {}, base_address="api"
511+
)
512+
513+
http_client_mock.assert_requested(method, post_data=None)
514+
515+
if path == self.v1_path:
516+
assert isinstance(resp, Customer)
517+
else:
518+
assert isinstance(resp, DeletedObject)
519+
520+
assert resp.id == "abc_123"
521+
assert resp.object == "customer"
522+
474523
def test_uses_headers(self, requestor, http_client_mock):
475524
http_client_mock.stub_request(
476525
"get", path=self.v1_path, rbody="{}", rcode=200

0 commit comments

Comments
 (0)