diff options
| author | Richard Marmorstein <richardm@stripe.com> | 2024-02-08 11:55:24 -0800 |
|---|---|---|
| committer | Richard Marmorstein <richardm@stripe.com> | 2024-02-08 11:55:24 -0800 |
| commit | 4628a0807b15c513848449550f9c4f9081ccdcd4 (patch) | |
| tree | 2a3583a4922baf763bb0de4c29cdd5343b58bb8b | |
| parent | bd1c58726ebcfd32fe3a3ab62c92b8565d190a4f (diff) | |
Introduce stripe.absent_as_none
| -rw-r--r-- | stripe/__init__.py | 1 | ||||
| -rw-r--r-- | stripe/_stripe_object.py | 2 | ||||
| -rw-r--r-- | tests/test_stripe_object.py | 99 |
3 files changed, 46 insertions, 56 deletions
diff --git a/stripe/__init__.py b/stripe/__init__.py index 71b054df..eed3eafb 100644 --- a/stripe/__init__.py +++ b/stripe/__init__.py @@ -42,6 +42,7 @@ max_network_retries: int = 0 ca_bundle_path: str = os.path.join( os.path.dirname(__file__), "data", "ca-certificates.crt" ) +absent_as_none: bool = False # Set to either 'debug' or 'info', controls console logging log: Optional[Literal["debug", "info"]] = None diff --git a/stripe/_stripe_object.py b/stripe/_stripe_object.py index 74b07a3c..a6ddc3cf 100644 --- a/stripe/_stripe_object.py +++ b/stripe/_stripe_object.py @@ -169,6 +169,8 @@ class StripeObject(Dict[str, Any]): k = self._field_remappings[k] return self[k] except KeyError as err: + if stripe.absent_as_none: + return None raise AttributeError(*err.args) def __delattr__(self, k): diff --git a/tests/test_stripe_object.py b/tests/test_stripe_object.py index 94780da1..f7c04524 100644 --- a/tests/test_stripe_object.py +++ b/tests/test_stripe_object.py @@ -2,10 +2,12 @@ import datetime import json import pickle from copy import copy, deepcopy +from typing import Any import pytest import stripe +from stripe._stripe_object import StripeObject SAMPLE_INVOICE = json.loads( @@ -93,15 +95,13 @@ SAMPLE_INVOICE = json.loads( class TestStripeObject(object): def test_initializes_with_parameters(self): - obj = stripe.stripe_object.StripeObject( - "foo", "bar", myparam=5, yourparam="boo" - ) + obj = StripeObject("foo", "bar", myparam=5, yourparam="boo") assert obj.id == "foo" assert obj.api_key == "bar" def test_access(self): - obj = stripe.stripe_object.StripeObject("myid", "mykey", myparam=5) + obj = StripeObject("myid", "mykey", myparam=5) # Empty with pytest.raises(AttributeError): @@ -131,7 +131,7 @@ class TestStripeObject(object): obj.foo = "" def test_refresh_from(self, mocker): - obj = stripe.stripe_object.StripeObject.construct_from( + obj = StripeObject.construct_from( {"foo": "bar", "trans": "me"}, "mykey" ) @@ -168,7 +168,7 @@ class TestStripeObject(object): assert obj.trans == 4 def test_passing_nested_refresh(self): - obj = stripe.stripe_object.StripeObject.construct_from( + obj = StripeObject.construct_from( {"foos": {"type": "list", "data": [{"id": "nested"}]}}, "key", stripe_account="acct_foo", @@ -182,23 +182,17 @@ class TestStripeObject(object): assert nested.stripe_account == "acct_foo" def test_refresh_from_nested_object(self): - obj = stripe.stripe_object.StripeObject.construct_from( - SAMPLE_INVOICE, "key" - ) + obj = StripeObject.construct_from(SAMPLE_INVOICE, "key") assert len(obj.lines) == 1 assert isinstance(obj.lines, stripe.ListObject) assert isinstance(obj.lines.data[0], stripe.InvoiceLineItem) - assert isinstance( - obj.lines.data[0].price, stripe.stripe_object.StripeObject - ) + assert isinstance(obj.lines.data[0].price, StripeObject) assert isinstance(obj.lines.data[0].price, stripe.Price) assert obj.lines.data[0].price.billing_scheme == "per_unit" def test_refresh_from_nested_object_can_be_paged(self): - obj = stripe.stripe_object.StripeObject.construct_from( - SAMPLE_INVOICE, "key" - ) + obj = StripeObject.construct_from(SAMPLE_INVOICE, "key") assert len(obj.lines) == 1 assert isinstance(obj.lines, stripe.ListObject) @@ -207,16 +201,12 @@ class TestStripeObject(object): assert seen == ["il_1LSiex2eZvKYlo2CZ5IspTNx"] assert isinstance(obj.lines.data[0], stripe.InvoiceLineItem) - assert isinstance( - obj.lines.data[0].price, stripe.stripe_object.StripeObject - ) + assert isinstance(obj.lines.data[0].price, StripeObject) assert isinstance(obj.lines.data[0].price, stripe.Price) assert obj.lines.data[0].price.billing_scheme == "per_unit" def test_to_json(self): - obj = stripe.stripe_object.StripeObject.construct_from( - SAMPLE_INVOICE, "key" - ) + obj = StripeObject.construct_from(SAMPLE_INVOICE, "key") self.check_invoice_data(json.loads(str(obj))) @@ -235,7 +225,7 @@ class TestStripeObject(object): ) def test_repr(self): - obj = stripe.stripe_object.StripeObject("foo", "bar", myparam=5) + obj = StripeObject("foo", "bar", myparam=5) obj["object"] = "\u4e00boo\u1f00" obj.date = datetime.datetime.fromtimestamp(1511136000) @@ -247,7 +237,7 @@ class TestStripeObject(object): assert '"date": 1511136000' in res def test_pickling(self): - obj = stripe.stripe_object.StripeObject("foo", "bar", myparam=5) + obj = StripeObject("foo", "bar", myparam=5) obj["object"] = "boo" obj.refresh_from( @@ -272,7 +262,7 @@ class TestStripeObject(object): assert newobj.emptystring == "" def test_deletion(self): - obj = stripe.stripe_object.StripeObject("id", "key") + obj = StripeObject("id", "key") obj.coupon = "foo" assert obj.coupon == "foo" @@ -285,7 +275,7 @@ class TestStripeObject(object): assert obj.coupon == "foo" def test_deletion_metadata(self): - obj = stripe.stripe_object.StripeObject.construct_from( + obj = StripeObject.construct_from( {"metadata": {"key": "value"}}, "mykey" ) @@ -296,10 +286,8 @@ class TestStripeObject(object): obj.metadata["key"] def test_copy(self): - nested = stripe.stripe_object.StripeObject.construct_from( - {"value": "bar"}, "mykey" - ) - obj = stripe.stripe_object.StripeObject.construct_from( + nested = StripeObject.construct_from({"value": "bar"}, "mykey") + obj = StripeObject.construct_from( {"empty": "", "value": "foo", "nested": nested}, "mykey", stripe_account="myaccount", @@ -318,10 +306,8 @@ class TestStripeObject(object): assert id(nested) == id(copied.nested) def test_deepcopy(self): - nested = stripe.stripe_object.StripeObject.construct_from( - {"value": "bar"}, "mykey" - ) - obj = stripe.stripe_object.StripeObject.construct_from( + nested = StripeObject.construct_from({"value": "bar"}, "mykey") + obj = StripeObject.construct_from( {"empty": "", "value": "foo", "nested": nested}, "mykey", stripe_account="myaccount", @@ -340,13 +326,9 @@ class TestStripeObject(object): assert id(nested) != id(copied.nested) def test_to_dict_recursive(self): - foo = stripe.stripe_object.StripeObject.construct_from( - {"value": "foo"}, "mykey" - ) - bar = stripe.stripe_object.StripeObject.construct_from( - {"value": "bar"}, "mykey" - ) - obj = stripe.stripe_object.StripeObject.construct_from( + foo = StripeObject.construct_from({"value": "foo"}, "mykey") + bar = StripeObject.construct_from({"value": "bar"}, "mykey") + obj = StripeObject.construct_from( {"empty": "", "value": "foobar", "nested": [foo, bar]}, "mykey" ) @@ -356,36 +338,30 @@ class TestStripeObject(object): "value": "foobar", "nested": [{"value": "foo"}, {"value": "bar"}], } - assert not isinstance( - d["nested"][0], stripe.stripe_object.StripeObject - ) - assert not isinstance( - d["nested"][1], stripe.stripe_object.StripeObject - ) + assert not isinstance(d["nested"][0], StripeObject) + assert not isinstance(d["nested"][1], StripeObject) def test_serialize_empty_string_unsets(self): - class SerializeToEmptyString(stripe.stripe_object.StripeObject): + class SerializeToEmptyString(StripeObject): def serialize(self, previous): return "" nested = SerializeToEmptyString.construct_from( {"value": "bar"}, "mykey" ) - obj = stripe.stripe_object.StripeObject.construct_from( - {"nested": nested}, "mykey" - ) + obj = StripeObject.construct_from({"nested": nested}, "mykey") assert obj.serialize(None) == {"nested": ""} def test_field_name_remapping(self): - class Foo(stripe.stripe_object.StripeObject): + class Foo(StripeObject): _field_remappings = {"getter_name": "data_name"} obj = Foo.construct_from({"data_name": "foo"}, "mykey") assert obj.getter_name == "foo" def test_sends_request_with_api_key(self, http_client_mock): - obj = stripe.stripe_object.StripeObject("id", "key") + obj = StripeObject("id", "key") http_client_mock.stub_request( "get", @@ -400,9 +376,7 @@ class TestStripeObject(object): ) def test_refresh_from_creates_new_requestor(self): - obj = stripe.stripe_object.StripeObject.construct_from( - {}, key="origkey" - ) + obj = StripeObject.construct_from({}, key="origkey") orig_requestor = obj._requestor assert obj.api_key == "origkey" @@ -415,7 +389,7 @@ class TestStripeObject(object): assert orig_requestor.api_key == "origkey" def test_can_update_api_key(self, http_client_mock): - obj = stripe.stripe_object.StripeObject("id", "key") + obj = StripeObject("id", "key") http_client_mock.stub_request( "get", @@ -431,3 +405,16 @@ class TestStripeObject(object): api_key="key2", stripe_account=None, ) + + def test_absent_as_none(self): + obj: Any = StripeObject.construct_from({}, None) + raised_attribute_error = False + try: + obj.bar + except AttributeError as e: + raised_attribute_error = True + assert "bar" in str(e) + assert raised_attribute_error + + stripe.absent_as_none = True + assert obj.bar is None |
