Skip to content

Commit

Permalink
Add ErrorObject to StripeError exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
ob-stripe committed Sep 24, 2019
1 parent 463b53a commit 74a5099
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions stripe/api_resources/__init__.py
Expand Up @@ -2,6 +2,7 @@

# flake8: noqa

from stripe.api_resources.error_object import ErrorObject, OAuthErrorObject
from stripe.api_resources.list_object import ListObject

from stripe.api_resources import checkout
Expand Down
69 changes: 69 additions & 0 deletions stripe/api_resources/error_object.py
@@ -0,0 +1,69 @@
from __future__ import absolute_import, division, print_function

from stripe.util import merge_dicts
from stripe.stripe_object import StripeObject


class ErrorObject(StripeObject):
def refresh_from(
self,
values,
api_key=None,
partial=False,
stripe_version=None,
stripe_account=None,
last_response=None,
):
# Unlike most other API resources, the API will omit attributes in
# error objects when they have a null value. We manually set default
# values here to facilitate generic error handling.
values = merge_dicts(
{
"charge": None,
"code": None,
"decline_code": None,
"doc_url": None,
"message": None,
"param": None,
"payment_intent": None,
"payment_method": None,
"setup_intent": None,
"source": None,
"type": None,
},
values,
)
return super(ErrorObject, self).refresh_from(
values,
api_key,
partial,
stripe_version,
stripe_account,
last_response,
)


class OAuthErrorObject(StripeObject):
def refresh_from(
self,
values,
api_key=None,
partial=False,
stripe_version=None,
stripe_account=None,
last_response=None,
):
# Unlike most other API resources, the API will omit attributes in
# error objects when they have a null value. We manually set default
# values here to facilitate generic error handling.
values = merge_dicts(
{"error": None, "error_description": None}, values
)
return super(OAuthErrorObject, self).refresh_from(
values,
api_key,
partial,
stripe_version,
stripe_account,
last_response,
)
11 changes: 11 additions & 0 deletions stripe/error.py
@@ -1,5 +1,7 @@
from __future__ import absolute_import, division, print_function

import stripe
from stripe.api_resources.error_object import ErrorObject
from stripe.six import python_2_unicode_compatible


Expand Down Expand Up @@ -32,6 +34,7 @@ def __init__(
self.headers = headers or {}
self.code = code
self.request_id = self.headers.get("request-id", None)
self.error = self.construct_error_object()

def __str__(self):
msg = self._message or "<empty message>"
Expand All @@ -56,6 +59,14 @@ def __repr__(self):
self.request_id,
)

def construct_error_object(self):
if self.json_body is None or "error" not in self.json_body:
return None

return ErrorObject.construct_from(
self.json_body["error"], stripe.api_key
)


class APIError(StripeError):
pass
Expand Down
8 changes: 8 additions & 0 deletions stripe/oauth_error.py
@@ -1,5 +1,7 @@
from __future__ import absolute_import, division, print_function

import stripe
from stripe.api_resources.error_object import OAuthErrorObject
from stripe.error import StripeError


Expand All @@ -17,6 +19,12 @@ def __init__(
description, http_body, http_status, json_body, headers, code
)

def construct_error_object(self):
if self.json_body is None:
return None

return OAuthErrorObject.construct_from(self.json_body, stripe.api_key)


class InvalidClientError(OAuthError):
pass
Expand Down
6 changes: 6 additions & 0 deletions stripe/util.py
Expand Up @@ -205,6 +205,12 @@ def populate_headers(idempotency_key):
return None


def merge_dicts(x, y):
z = x.copy()
z.update(y)
return z


class class_method_variant(object):
def __init__(self, class_method_name):
self.class_method_name = class_method_name
Expand Down
8 changes: 8 additions & 0 deletions tests/test_error.py
Expand Up @@ -52,6 +52,14 @@ def test_repr(self):
"request_id='123')"
)

def test_error_object(self):
err = error.StripeError(
"message", json_body={"error": {"code": "some_error"}}
)
assert err.error is not None
assert err.error.code == "some_error"
assert err.error.charge is None


class TestStripeErrorWithParamCode(object):
def test_repr(self):
Expand Down
14 changes: 14 additions & 0 deletions tests/test_oauth_error.py
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-

from __future__ import absolute_import, division, print_function

from stripe import oauth_error


class TestOAuthError(object):
def test_error_object(self):
err = oauth_error.OAuthError(
"message", "description", json_body={"error": "some_oauth_error"}
)
assert err.error is not None
assert err.error.error == "some_oauth_error"

0 comments on commit 74a5099

Please sign in to comment.