Skip to content

Commit 0930421

Browse files
committed
python-sp-api-24 Need to handle 429 errors (Rate Limit throttled)
1 parent d067dbe commit 0930421

File tree

15 files changed

+208
-18
lines changed

15 files changed

+208
-18
lines changed

docs/exceptions.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
Exceptions
22
==========
33

4-
.. autoclass:: sp_api.base.SellingApiException
5-
64
.. autoclass:: sp_api.base.MissingCredentials
5+
6+
.. autoclass:: sp_api.base.exceptions.SellingApiException
7+
8+
.. autoclass:: sp_api.base.SellingApiBadRequestException
9+
10+
.. autoclass:: sp_api.base.SellingApiForbiddenException
11+
12+
.. autoclass:: sp_api.base.SellingApiNotFoundException
13+
14+
.. autoclass:: sp_api.base.SellingApiRequestThrottledException
15+
16+
.. autoclass:: sp_api.base.SellingApiServerException
17+
18+
.. autoclass:: sp_api.base.SellingApiTemporarilyUnavailableException
19+

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='python-amazon-sp-api',
5-
version='0.1.6',
5+
version='0.1.7',
66
install_requires=[
77
"requests",
88
"six~=1.15.0",

sp_api/api/feeds/feeds.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from sp_api.api.feeds.models.create_feed_response import CreateFeedResponse
99
from sp_api.api.feeds.models.get_feed_document_response import GetFeedDocumentResponse
1010
from sp_api.api.feeds.models.get_feed_response import GetFeedResponse
11-
from sp_api.base import Client, sp_endpoint, Marketplaces, fill_query_params, SellingApiException
11+
from sp_api.base import Client, sp_endpoint, Marketplaces, fill_query_params
1212

1313
import zlib
1414

@@ -97,6 +97,7 @@ def create_feed_document(self, file, content_type='text/tsv', **kwargs) -> Creat
9797
)
9898
if 200 <= upload.status_code < 300:
9999
return response
100+
from sp_api.base.exceptions import SellingApiException
100101
raise SellingApiException(upload.headers)
101102

102103
def submit_feed(self, feed_type, file, content_type='text/tsv', **kwargs) -> [CreateFeedDocumentResponse, CreateFeedResponse]:

sp_api/api/products/products.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,4 @@ def _create_get_pricing_request(self, item_list, item_type, **kwargs):
133133
[urllib.parse.quote_plus(s) for s in item_list])},
134134
'ItemType': item_type,
135135
**({'ItemCondition': kwargs.pop('ItemCondition')} if 'ItemCondition' in kwargs else {}),
136-
'MarketplaceId': self.marketplace_id}).json())
136+
'MarketplaceId': kwargs.get('MarketplaceId', self.marketplace_id)}).json())

sp_api/base/__init__.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
from .client import Client
44
from .helpers import fill_query_params, sp_endpoint, decrypt_aes, encrypt_aes
55
from .marketplaces import Marketplaces
6-
from .client import SellingApiException
6+
from .exceptions import SellingApiException
7+
from .exceptions import SellingApiBadRequestException
8+
from .exceptions import SellingApiNotFoundException
9+
from .exceptions import SellingApiForbiddenException
10+
from .exceptions import SellingApiRequestThrottledException
11+
from .exceptions import SellingApiServerException
12+
from .exceptions import SellingApiTemporarilyUnavailableException
713
from .schedules import Schedules
814
from .report_status import ReportStatus
915
from .sales_enum import FirstDayOfWeek, Granularity, BuyerType
@@ -20,6 +26,12 @@
2026
'fill_query_params',
2127
'sp_endpoint',
2228
'SellingApiException',
29+
'SellingApiBadRequestException',
30+
'SellingApiNotFoundException',
31+
'SellingApiForbiddenException',
32+
'SellingApiBadRequestException',
33+
'SellingApiRequestThrottledException',
34+
'SellingApiTemporarilyUnavailableException',
2335
'Schedules',
2436
'ReportStatus',
2537
'FirstDayOfWeek',

sp_api/base/client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,13 @@
1010

1111
from sp_api.auth import AccessTokenClient, AccessTokenResponse
1212
from .base_client import BaseClient
13+
from .exceptions import get_exception_for_code
1314
from .marketplaces import Marketplaces
1415
from sp_api.base import AWSSigV4
1516

1617
role_cache = TTLCache(maxsize=10, ttl=3600)
1718

1819

19-
class SellingApiException(BaseException):
20-
pass
21-
22-
2320
class Client(BaseClient):
2421
boto3_client = None
2522

@@ -105,8 +102,10 @@ def _request(self, path: str, *, data: dict = None, params: dict = None, headers
105102
auth=self._sign_request())
106103

107104
e = res.json().get('errors', None)
105+
print(e)
108106
if e:
109-
raise SellingApiException(e)
107+
exception = get_exception_for_code(res.status_code)
108+
raise exception(e)
110109
return res
111110

112111
def _request_grantless_operation(self, path: str, *, data: dict = None, params: dict = None):

sp_api/base/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44

55
class MissingCredentials(Exception):
6+
"""
7+
Credentials are missing, see the error output to find possible causes
8+
"""
69
pass
710

811

sp_api/base/exceptions.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
class SellingApiException(BaseException):
2+
"""
3+
Generic Exception
4+
5+
Parameters:
6+
7+
message: str The error message
8+
amzn_code: str Amazon Error Code
9+
error: list Amazon Error list
10+
11+
"""
12+
13+
def __init__(self, error):
14+
try:
15+
self.message = error[0].get('message')
16+
self.amzn_code = error[0].get('code')
17+
except IndexError:
18+
pass
19+
self.error = error
20+
21+
22+
class SellingApiBadRequestException(SellingApiException):
23+
"""
24+
400 Request has missing or invalid parameters and cannot be parsed.
25+
"""
26+
code = 400
27+
28+
def __init__(self, error):
29+
super(SellingApiBadRequestException, self).__init__(error)
30+
31+
32+
class SellingApiForbiddenException(SellingApiException):
33+
"""
34+
403 Indicates access to the resource is forbidden. Possible reasons include Access Denied, Unauthorized, Expired Token, or Invalid Signature.
35+
"""
36+
code = 403
37+
38+
def __init__(self, error):
39+
super(SellingApiForbiddenException, self).__init__(error)
40+
41+
42+
class SellingApiNotFoundException(SellingApiException):
43+
"""
44+
404 The resource specified does not exist.
45+
"""
46+
code = 404
47+
48+
def __init__(self, error):
49+
super(SellingApiNotFoundException, self).__init__(error)
50+
51+
52+
class SellingApiRequestThrottledException(SellingApiException):
53+
"""
54+
429 The frequency of requests was greater than allowed.
55+
"""
56+
code = 429
57+
58+
def __init__(self, error):
59+
super(SellingApiRequestThrottledException, self).__init__(error)
60+
61+
62+
class SellingApiServerException(SellingApiException):
63+
"""
64+
500 An unexpected condition occurred that prevented the server from fulfilling the request.
65+
"""
66+
code = 500
67+
68+
def __init__(self, error):
69+
super(SellingApiServerException, self).__init__(error)
70+
71+
72+
class SellingApiTemporarilyUnavailableException(SellingApiException):
73+
"""
74+
503 Temporary overloading or maintenance of the server.
75+
"""
76+
code = 503
77+
78+
def __init__(self, error):
79+
super(SellingApiTemporarilyUnavailableException, self).__init__(error)
80+
81+
82+
def get_exception_for_code(code: int):
83+
return {
84+
400: SellingApiBadRequestException,
85+
403: SellingApiForbiddenException,
86+
429: SellingApiRequestThrottledException,
87+
500: SellingApiServerException,
88+
503: SellingApiTemporarilyUnavailableException
89+
}.get(code, SellingApiException)

tests/api/catalog/test_catalog.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
from sp_api.api import Catalog
22
from sp_api.base import Marketplaces
3-
4-
5-
6-

tests/api/feeds/test_feeds.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from sp_api.api import Feeds
2+
from sp_api.base import SellingApiBadRequestException, SellingApiServerException
23

34

45
def test_create_feed():
@@ -13,3 +14,18 @@ def test_get_feed():
1314
assert res.payload.get('feedId') == 'FeedId1'
1415
assert res.payload.get('processingStatus') == 'CANCELLED'
1516

17+
18+
def test_get_feed_expect_400():
19+
try:
20+
Feeds().get_feed('badFeedId1')
21+
except SellingApiBadRequestException as br:
22+
assert type(br) == SellingApiBadRequestException
23+
assert br.code == 400
24+
25+
26+
def test_get_feed_expect_500():
27+
try:
28+
Feeds().get_feed('giberish')
29+
except SellingApiServerException as br:
30+
assert type(br) == SellingApiServerException
31+
assert br.code == 500

0 commit comments

Comments
 (0)