Skip to content
Closed
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
1 change: 1 addition & 0 deletions stripe/_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class Account(
"""

OBJECT_NAME: ClassVar[Literal["account"]] = "account"
_has_deleted_version = True

class BusinessProfile(StripeObject):
class AnnualRevenue(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_apple_pay_domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ApplePayDomain(
ListableAPIResource["ApplePayDomain"],
):
OBJECT_NAME: ClassVar[Literal["apple_pay_domain"]] = "apple_pay_domain"
_has_deleted_version = True
created: int
"""
Time at which the object was created. Measured in seconds since the Unix epoch.
Expand Down
1 change: 1 addition & 0 deletions stripe/_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

class Application(StripeObject):
OBJECT_NAME: ClassVar[Literal["application"]] = "application"
_has_deleted_version = True
deleted: Optional[Literal[True]]
"""
Always true for a deleted object
Expand Down
1 change: 1 addition & 0 deletions stripe/_bank_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class BankAccount(
"""

OBJECT_NAME: ClassVar[Literal["bank_account"]] = "bank_account"
_has_deleted_version = True

class FutureRequirements(StripeObject):
class Error(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_card.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Card(DeletableAPIResource["Card"], UpdateableAPIResource["Card"]):
"""

OBJECT_NAME: ClassVar[Literal["card"]] = "card"
_has_deleted_version = True

class Networks(StripeObject):
preferred: Optional[str]
Expand Down
1 change: 1 addition & 0 deletions stripe/_coupon.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Coupon(
"""

OBJECT_NAME: ClassVar[Literal["coupon"]] = "coupon"
_has_deleted_version = True

class AppliesTo(StripeObject):
products: List[str]
Expand Down
1 change: 1 addition & 0 deletions stripe/_customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class Customer(
"""

OBJECT_NAME: ClassVar[Literal["customer"]] = "customer"
_has_deleted_version = True

class Address(StripeObject):
city: Optional[str]
Expand Down
1 change: 1 addition & 0 deletions stripe/_discount.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Discount(StripeObject):
"""

OBJECT_NAME: ClassVar[Literal["discount"]] = "discount"
_has_deleted_version = True

class Source(StripeObject):
coupon: Optional[ExpandableField["Coupon"]]
Expand Down
1 change: 1 addition & 0 deletions stripe/_invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class Invoice(
"""

OBJECT_NAME: ClassVar[Literal["invoice"]] = "invoice"
_has_deleted_version = True

class AutomaticTax(StripeObject):
class Liability(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_invoice_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class InvoiceItem(
"""

OBJECT_NAME: ClassVar[Literal["invoiceitem"]] = "invoiceitem"
_has_deleted_version = True

class Parent(StripeObject):
class SubscriptionDetails(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_person.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Person(UpdateableAPIResource["Person"]):
"""

OBJECT_NAME: ClassVar[Literal["person"]] = "person"
_has_deleted_version = True

class AdditionalTosAcceptances(StripeObject):
class Account(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class Plan(
"""

OBJECT_NAME: ClassVar[Literal["plan"]] = "plan"
_has_deleted_version = True

class Tier(StripeObject):
flat_amount: Optional[int]
Expand Down
1 change: 1 addition & 0 deletions stripe/_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Price(
"""

OBJECT_NAME: ClassVar[Literal["price"]] = "price"
_has_deleted_version = True

class CurrencyOptions(StripeObject):
class CustomUnitAmount(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class Product(
"""

OBJECT_NAME: ClassVar[Literal["product"]] = "product"
_has_deleted_version = True

class MarketingFeature(StripeObject):
name: Optional[str]
Expand Down
1 change: 1 addition & 0 deletions stripe/_product_feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class ProductFeature(StripeObject):
"""

OBJECT_NAME: ClassVar[Literal["product_feature"]] = "product_feature"
_has_deleted_version = True
deleted: Optional[Literal[True]]
"""
Always true for a deleted object
Expand Down
13 changes: 9 additions & 4 deletions stripe/_stripe_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ def default(self, o: Any) -> Any:

_retrieve_params: Mapping[str, Any]
_previous: Optional[Mapping[str, Any]]
# overridden on a per-resource basis in codegen
_has_deleted_version = False

def __init__(
self,
Expand Down Expand Up @@ -143,10 +145,8 @@ def last_response(self) -> Optional[StripeResponse]:
return self._last_response

def update(self, update_dict: Mapping[str, Any]) -> None:
for k in update_dict:
self._unsaved_values.add(k)

self._data.update(update_dict)
for k, v in update_dict.items():
self[k] = v

if not TYPE_CHECKING:

Expand Down Expand Up @@ -213,6 +213,11 @@ def __getitem__(self, k: str) -> Any:
"available on this object are: %s"
% (k, k, ", ".join(list(self._data.keys())))
)
elif k == "deleted" and self._has_deleted_version:
# certain objects have a `deleted` property that's None or true.
# Because of the way missing property access works, you couldn't write `if customer.deleted` because that was either true or an error.
# so to support this check specifically, we return the default value rather than erroring
return None
else:
from stripe._invoice import Invoice

Expand Down
1 change: 1 addition & 0 deletions stripe/_subscription_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class SubscriptionItem(
"""

OBJECT_NAME: ClassVar[Literal["subscription_item"]] = "subscription_item"
_has_deleted_version = True

class BillingThresholds(StripeObject):
usage_gte: Optional[int]
Expand Down
1 change: 1 addition & 0 deletions stripe/_tax_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TaxId(
"""

OBJECT_NAME: ClassVar[Literal["tax_id"]] = "tax_id"
_has_deleted_version = True

class Owner(StripeObject):
account: Optional[ExpandableField["Account"]]
Expand Down
1 change: 1 addition & 0 deletions stripe/_webhook_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class WebhookEndpoint(
"""

OBJECT_NAME: ClassVar[Literal["webhook_endpoint"]] = "webhook_endpoint"
_has_deleted_version = True
api_version: Optional[str]
"""
The API version events are rendered as for this webhook endpoint.
Expand Down
1 change: 1 addition & 0 deletions stripe/apps/_secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Secret(CreateableAPIResource["Secret"], ListableAPIResource["Secret"]):
"""

OBJECT_NAME: ClassVar[Literal["apps.secret"]] = "apps.secret"
_has_deleted_version = True

class Scope(StripeObject):
type: Literal["account", "user"]
Expand Down
1 change: 1 addition & 0 deletions stripe/radar/_value_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class ValueList(
"""

OBJECT_NAME: ClassVar[Literal["radar.value_list"]] = "radar.value_list"
_has_deleted_version = True
alias: str
"""
The name of the value list for use in rules.
Expand Down
1 change: 1 addition & 0 deletions stripe/radar/_value_list_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ValueListItem(
OBJECT_NAME: ClassVar[Literal["radar.value_list_item"]] = (
"radar.value_list_item"
)
_has_deleted_version = True
created: int
"""
Time at which the object was created. Measured in seconds since the Unix epoch.
Expand Down
1 change: 1 addition & 0 deletions stripe/terminal/_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class Configuration(
OBJECT_NAME: ClassVar[Literal["terminal.configuration"]] = (
"terminal.configuration"
)
_has_deleted_version = True

class BbposWisepad3(StripeObject):
splashscreen: Optional[ExpandableField["File"]]
Expand Down
1 change: 1 addition & 0 deletions stripe/terminal/_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Location(
"""

OBJECT_NAME: ClassVar[Literal["terminal.location"]] = "terminal.location"
_has_deleted_version = True

class Address(StripeObject):
city: Optional[str]
Expand Down
1 change: 1 addition & 0 deletions stripe/terminal/_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class Reader(
"""

OBJECT_NAME: ClassVar[Literal["terminal.reader"]] = "terminal.reader"
_has_deleted_version = True

class Action(StripeObject):
class CollectInputs(StripeObject):
Expand Down
1 change: 1 addition & 0 deletions stripe/test_helpers/_test_clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TestClock(
OBJECT_NAME: ClassVar[Literal["test_helpers.test_clock"]] = (
"test_helpers.test_clock"
)
_has_deleted_version = True

class StatusDetails(StripeObject):
class Advancing(StripeObject):
Expand Down
29 changes: 29 additions & 0 deletions tests/test_stripe_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import pytest

import stripe
from stripe._customer import Customer
from stripe._invoice import Invoice
from stripe._stripe_object import StripeObject
from stripe.billing._alert import Alert

# We use this because it has a map, "restriction.currency_options" from string -> CurrencyOptions nested class.
SAMPLE_PROMOTION_CODE = json.loads(
Expand Down Expand Up @@ -313,6 +315,33 @@ def test_deletion_metadata(self):
with pytest.raises(KeyError):
obj.metadata["key"]

def test_non_deleted_deletable_resource(self):
"""
if it's possible for an object to be deleted, you should be able to read th
"""
customer = Customer()
assert customer.deleted is None
assert hasattr(customer, "deleted")
# this is a little confusing. since we're faking that this property exist, checks that access the underlying data disagree with property access
assert "deleted" not in customer

def test_deleted_property_reads(self):
"""
certain objects have a `deleted` property that's None or true. Because of the way missing property access works, you couldn't write `if customer.deleted` because that was either true or an error.

Instead, we now initialize that property on objects that can be `deleted`, so the check works as expected
"""
customer = Customer.construct_from({"deleted": True}, None)
assert customer.deleted
assert hasattr(customer, "deleted")
assert "deleted" in customer

def test_no_deleted_property_fails(self):
# an alert can never be `deleted`, so this should always error
alert = Alert()
with pytest.raises(AttributeError):
alert.deleted

def test_copy(self):
nested = StripeObject.construct_from({"value": "bar"}, "mykey")
obj = StripeObject.construct_from(
Expand Down
Loading