Skip to content

Commit bbe5c74

Browse files
committed
feat: add api v1 standard error response
1 parent be8d637 commit bbe5c74

File tree

2 files changed

+50
-38
lines changed

2 files changed

+50
-38
lines changed

tests/unit/base/test_version.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
from tests import IntegrationTestCase
66
from tests.holodeck import Request
77
from twilio.base.api_v1_version import ApiV1Version
8-
from twilio.base.exceptions import TwilioRestException, TwilioServiceException
8+
from twilio.base.exceptions import TwilioServiceException
99
from twilio.base.page import Page
10-
from twilio.base.version import Version
1110
from twilio.http.response import Response
1211

1312

@@ -155,9 +154,7 @@ def test_exception_rfc9457_compliant(self):
155154
self.assertEqual(exception.status, 400)
156155
self.assertEqual(exception.code, 20001)
157156
self.assertEqual(exception.detail, "The 'PhoneNumber' parameter is required.")
158-
self.assertEqual(
159-
exception.instance, "/api/v1/accounts/AC123/calls/CA456"
160-
)
157+
self.assertEqual(exception.instance, "/api/v1/accounts/AC123/calls/CA456")
161158
self.assertEqual(exception.method, "POST")
162159
self.assertEqual(exception.uri, "/test")
163160

@@ -225,14 +222,11 @@ def test_exception_with_error_payload_parameter(self):
225222
"title": "Invalid parameter",
226223
"status": 400,
227224
"code": 20001,
228-
"detail": "Pre-parsed error payload"
225+
"detail": "Pre-parsed error payload",
229226
}
230227

231228
exception = ApiV1Version.exception(
232-
method="POST",
233-
uri="/test",
234-
response=response,
235-
error_payload=error_payload
229+
method="POST", uri="/test", response=response, error_payload=error_payload
236230
)
237231

238232
self.assertIsInstance(exception, TwilioServiceException)
@@ -307,7 +301,9 @@ def test_parse_delete_with_rfc9457_error(self):
307301

308302
exception = context.exception
309303
self.assertEqual(exception.title, "Forbidden")
310-
self.assertEqual(exception.detail, "You do not have permission to delete this resource")
304+
self.assertEqual(
305+
exception.detail, "You do not have permission to delete this resource"
306+
)
311307

312308
def test_parse_create_with_rfc9457_error(self):
313309
"""Test that _parse_create raises TwilioServiceException for RFC-9457 errors"""

twilio/base/exceptions.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import sys
3-
from typing import Optional, List, Dict, Any
3+
from typing import Optional, List, Dict
44

55

66
class TwilioException(Exception):
@@ -145,47 +145,63 @@ def yellow(words: str) -> str:
145145
"\n{red_error} {request_was}\n\n{http_line}\n\n{twilio_returned}\n".format(
146146
red_error=red("HTTP Error"),
147147
request_was=white("Your request was:"),
148-
http_line=teal("%s %s" % (self.method, self.uri)) if self.uri else teal("(no URI)"),
148+
http_line=(
149+
teal("%s %s" % (self.method, self.uri))
150+
if self.uri
151+
else teal("(no URI)")
152+
),
149153
twilio_returned=white("Twilio returned the following information:"),
150154
)
151155
]
152156

153157
# Title and detail
154-
msg_parts.append("\n{title_label}: {title}\n".format(
155-
title_label=white("Title"),
156-
title=blue(self.title),
157-
))
158+
msg_parts.append(
159+
"\n{title_label}: {title}\n".format(
160+
title_label=white("Title"),
161+
title=blue(self.title),
162+
)
163+
)
158164

159165
if self.detail:
160-
msg_parts.append("{detail_label}: {detail}\n".format(
161-
detail_label=white("Detail"),
162-
detail=blue(self.detail),
163-
))
166+
msg_parts.append(
167+
"{detail_label}: {detail}\n".format(
168+
detail_label=white("Detail"),
169+
detail=blue(self.detail),
170+
)
171+
)
164172

165173
# Code and status
166-
msg_parts.append("{code_label}: {code} | {status_label}: {status}\n".format(
167-
code_label=white("Error Code"),
168-
code=blue(str(self.code)),
169-
status_label=white("Status"),
170-
status=blue(str(self.status)),
171-
))
174+
msg_parts.append(
175+
"{code_label}: {code} | {status_label}: {status}\n".format(
176+
code_label=white("Error Code"),
177+
code=blue(str(self.code)),
178+
status_label=white("Status"),
179+
status=blue(str(self.status)),
180+
)
181+
)
172182

173183
# Validation errors if present
174184
if self.errors:
175-
msg_parts.append("\n{validation_label}:\n".format(
176-
validation_label=white("Validation Errors"),
177-
))
185+
msg_parts.append(
186+
"\n{validation_label}:\n".format(
187+
validation_label=white("Validation Errors"),
188+
)
189+
)
178190
for error in self.errors:
179-
msg_parts.append(" {pointer}: {detail}\n".format(
180-
pointer=yellow(error.get("pointer", "(unknown field)")),
181-
detail=error.get("detail", "(no detail)"),
182-
))
191+
msg_parts.append(
192+
" {pointer}: {detail}\n".format(
193+
pointer=yellow(error.get("pointer", "(unknown field)")),
194+
detail=error.get("detail", "(no detail)"),
195+
)
196+
)
183197

184198
# Documentation link
185-
msg_parts.append("\n{more_info}\n\n{uri}\n\n".format(
186-
more_info=white("More information may be available here:"),
187-
uri=blue(self.type),
188-
))
199+
msg_parts.append(
200+
"\n{more_info}\n\n{uri}\n\n".format(
201+
more_info=white("More information may be available here:"),
202+
uri=blue(self.type),
203+
)
204+
)
189205

190206
return "".join(msg_parts)
191207
else:

0 commit comments

Comments
 (0)