Skip to content

Commit 226bf71

Browse files
committed
Merge branch 'release-0.12.0'
2 parents 3d934ba + 8949bde commit 226bf71

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+8680
-5994
lines changed

.gitattributes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
bunq/sdk/model/generated linguist-generated=true
1+
bunq/sdk/model/generated/* linguist-generated=true

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,6 @@ bunq.conf
8989
bunq-test.conf
9090
**/tmp
9191
config.json
92-
tests/connectQr.png
92+
connectQr.png
9393
.DS_Store
9494
bunq_sdk.egg-info

EXCEPTIONS.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
## Exceptions
2+
When you make a request via the SDK, there is a chance of request failing
3+
due to various reasons. When such a failure happens, an exception
4+
corresponding to the error occurred is raised.
5+
6+
7+
----
8+
#### Possible Exceptions
9+
* `BadRequestException` If the request returns with status code `400`
10+
* `UnauthorizedException` If the request returns with status code `401`
11+
* `ForbiddenException` If the request returns with status code `403`
12+
* `NotFoundException` If the request returns with status code `404`
13+
* `MethodNotAllowedException` If the request returns with status code `405`
14+
* `TooManyRequestsException` If the request returns with status code `429`
15+
* `PleaseContactBunqException` If the request returns with status code `500`.
16+
If you get this exception, please contact us preferably via the support chat in the bunq app.
17+
* `UnknownApiErrorException` If none of the above mentioned exceptions are raised,
18+
this exception will be raised instead.
19+
20+
For more information regarding these errors, please take a look on the documentation
21+
page here: https://doc.bunq.com/api/1/page/errors
22+
23+
---
24+
#### Base exception
25+
All the exceptions have the same base exception which looks like this:
26+
```python
27+
class ApiException(Exception):
28+
def __init__(self, message, response_code):
29+
pass
30+
31+
@property
32+
def message(self):
33+
"""
34+
:rtype: str
35+
"""
36+
37+
return self._message
38+
39+
@property
40+
def response_code(self):
41+
"""
42+
:rtype: int
43+
"""
44+
45+
return self._response_code
46+
```
47+
This means that each exception will have the response code and the error message
48+
related to the specific exception that has been raised.
49+
50+
---
51+
#### Exception handling
52+
Because we raise different exceptions for each error, you can catch an error
53+
if you expect it to be raised.
54+
55+
```python
56+
from bunq.sdk.exception import BadRequestException
57+
from bunq.sdk.context import ApiEnvironmentType, ApiContext
58+
59+
API_KEY = "Some invalid API key"
60+
DESCRIPTION = "This wil raise a BadRequestException"
61+
62+
try:
63+
# Make a call that might raise an exception
64+
ApiContext(ApiEnvironmentType.SANDBOX, API_KEY, DESCRIPTION)
65+
except BadRequestException as error:
66+
# Do something if exception is raised
67+
print(error.response_code)
68+
print(error.message) # or just print(error)
69+
```

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,7 @@ Please do not forget to set the `_API_KEY` constant in
183183

184184
Information regarding the test cases can be found in the [README.md](./tests/README.md)
185185
located in [test](/tests)
186+
187+
## Exceptions
188+
The SDK can raise multiple exceptions. For an overview of these exceptions please
189+
take a look at [EXCEPTIONS.md](./EXCEPTIONS.md)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.11.0
1+
0.12.0

bunq/__init__.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1-
from bunq.sdk.json import registry
1+
from bunq.sdk.json import converter
22

3-
registry.initialize()
3+
4+
def initialize_converter():
5+
"""
6+
:rtype: None
7+
"""
8+
9+
import datetime
10+
11+
from bunq.sdk import client
12+
from bunq.sdk import context
13+
from bunq.sdk.model import core
14+
from bunq.sdk.json import adapters
15+
from bunq.sdk.json import converter
16+
from bunq.sdk.model.generated import object_
17+
18+
converter.register_adapter(core.Installation, adapters.InstallationAdapter)
19+
converter.register_adapter(
20+
core.SessionServer,
21+
adapters.SessionServerAdapter
22+
)
23+
converter.register_adapter(
24+
context.InstallationContext,
25+
adapters.InstallationContextAdapter
26+
)
27+
converter.register_adapter(
28+
context.ApiEnvironmentType,
29+
adapters.ApiEnvironmentTypeAdapter
30+
)
31+
converter.register_adapter(float, adapters.FloatAdapter)
32+
converter.register_adapter(object_.Geolocation, adapters.GeolocationAdapter)
33+
converter.register_adapter(
34+
object_.MonetaryAccountReference,
35+
adapters.MonetaryAccountReferenceAdapter
36+
)
37+
converter.register_adapter(object_.ShareDetail, adapters.ShareDetailAdapter)
38+
converter.register_adapter(datetime.datetime, adapters.DateTimeAdapter)
39+
converter.register_adapter(client.Pagination, adapters.PaginationAdapter)
40+
41+
42+
converter.set_initializer_function(initialize_converter)

bunq/sdk/client.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
import requests
66

7-
from bunq.sdk import context
87
from bunq.sdk import exception
98
from bunq.sdk import security
9+
from bunq.sdk.exception_factory import ExceptionFactory
1010
from bunq.sdk.json import converter
1111

1212

1313
class ApiClient(object):
1414
"""
15-
:type _api_context: context.ApiContext
15+
:type _api_context: bunq.sdk.context.ApiContext
1616
"""
1717

1818
# HTTPS type of proxy, the only used at bunq
@@ -31,7 +31,7 @@ class ApiClient(object):
3131
HEADER_AUTHENTICATION = 'X-Bunq-Client-Authentication'
3232

3333
# Default header values
34-
_USER_AGENT_BUNQ = 'bunq-sdk-python/0.11.0'
34+
_USER_AGENT_BUNQ = 'bunq-sdk-python/0.12.0'
3535
_GEOLOCATION_ZERO = '0 0 0 0 NL'
3636
_LANGUAGE_EN_US = 'en_US'
3737
_REGION_NL_NL = 'nl_NL'
@@ -201,7 +201,7 @@ def _assert_response_success(self, response):
201201
"""
202202

203203
if response.status_code != self._STATUS_CODE_OK:
204-
raise exception.ApiException(
204+
raise ExceptionFactory.create_exception_for_response(
205205
response.status_code,
206206
self._fetch_error_messages(response)
207207
)
@@ -372,6 +372,18 @@ def pagination(self):
372372

373373
return self._pagination
374374

375+
@classmethod
376+
def cast_from_bunq_response(cls, bunq_response):
377+
"""
378+
:type bunq_response: BunqResponse
379+
"""
380+
381+
return cls(
382+
bunq_response.value,
383+
bunq_response.headers,
384+
bunq_response.pagination
385+
)
386+
375387

376388
class Pagination(object):
377389
"""

bunq/sdk/context.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import aenum
44
from Cryptodome.PublicKey import RSA
55

6-
from bunq.sdk import model
6+
from bunq.sdk.model import core
77
from bunq.sdk import security
88
from bunq.sdk.json import converter
9-
from bunq.sdk.model import generated
9+
from bunq.sdk.model.generated import endpoint
1010

1111

1212
class ApiEnvironmentType(aenum.AutoNumberEnum):
@@ -95,7 +95,7 @@ def _initialize_installation(self):
9595
"""
9696

9797
private_key_client = security.generate_rsa_private_key()
98-
installation = model.Installation.create(
98+
installation = core.Installation.create(
9999
self,
100100
security.public_key_to_string(private_key_client.publickey())
101101
).value
@@ -119,12 +119,12 @@ def _register_device(self, device_description,
119119
:rtype: None
120120
"""
121121

122-
generated.DeviceServer.create(
122+
endpoint.DeviceServer.create(
123123
self,
124124
{
125-
generated.DeviceServer.FIELD_DESCRIPTION: device_description,
126-
generated.DeviceServer.FIELD_SECRET: self.api_key,
127-
generated.DeviceServer.FIELD_PERMITTED_IPS: permitted_ips,
125+
endpoint.DeviceServer.FIELD_DESCRIPTION: device_description,
126+
endpoint.DeviceServer.FIELD_SECRET: self.api_key,
127+
endpoint.DeviceServer.FIELD_PERMITTED_IPS: permitted_ips,
128128
}
129129
)
130130

@@ -133,7 +133,7 @@ def _initialize_session(self):
133133
:rtype: None
134134
"""
135135

136-
session_server = model.SessionServer.create(self).value
136+
session_server = core.SessionServer.create(self).value
137137
token = session_server.token.token
138138
expiry_time = self._get_expiry_timestamp(session_server)
139139

@@ -142,7 +142,7 @@ def _initialize_session(self):
142142
@classmethod
143143
def _get_expiry_timestamp(cls, session_server):
144144
"""
145-
:type session_server: model.SessionServer
145+
:type session_server: core.SessionServer
146146
147147
:rtype: datetime.datetime
148148
"""
@@ -155,7 +155,7 @@ def _get_expiry_timestamp(cls, session_server):
155155
@classmethod
156156
def _get_session_timeout_seconds(cls, session_server):
157157
"""
158-
:type session_server: model.SessionServer
158+
:type session_server: core.SessionServer
159159
160160
:rtype: int
161161
"""
@@ -210,7 +210,7 @@ def _delete_session(self):
210210
:rtype: None
211211
"""
212212

213-
generated.Session.delete(self, self._SESSION_ID_DUMMY)
213+
endpoint.Session.delete(self, self._SESSION_ID_DUMMY)
214214

215215
@property
216216
def environment_type(self):
@@ -300,7 +300,7 @@ def restore(cls, path=None):
300300

301301
with open(path, cls._FILE_MODE_READ) as file_:
302302
return cls.from_json(file_.read())
303-
303+
304304
@classmethod
305305
def from_json(cls, json_str):
306306
"""

bunq/sdk/exception.py

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,22 @@
11
class ApiException(Exception):
2-
"""
3-
:type _response_code: int
4-
"""
5-
6-
# Constants for formatting messages
7-
_FORMAT_RESPONSE_CODE_LINE = 'HTTP Response Code: {}'
8-
_GLUE_ERROR_MESSAGES = '\n'
9-
10-
def __init__(self, response_code, messages):
2+
def __init__(self, message, response_code):
113
"""
4+
:type message: str
125
:type response_code: int
13-
:type messages: list[str]
146
"""
157

16-
super(ApiException, self).__init__(
17-
self.generate_message_error(response_code, messages)
18-
)
8+
self._message = message
199
self._response_code = response_code
2010

21-
def generate_message_error(self, response_code, messages):
22-
"""
23-
:type response_code: int
24-
:type messages: list[str]
25-
26-
:rtype: str
27-
"""
28-
29-
line_response_code = self._FORMAT_RESPONSE_CODE_LINE \
30-
.format(response_code)
31-
32-
return self.glue_messages([line_response_code] + messages)
11+
super(ApiException, self).__init__(message)
3312

34-
def glue_messages(self, messages):
13+
@property
14+
def message(self):
3515
"""
36-
:type messages: list[str]
37-
3816
:rtype: str
3917
"""
4018

41-
return self._GLUE_ERROR_MESSAGES.join(messages)
19+
return self._message
4220

4321
@property
4422
def response_code(self):
@@ -52,3 +30,35 @@ def response_code(self):
5230
class BunqException(Exception):
5331
def __init__(self, message):
5432
super(BunqException, self).__init__(message)
33+
34+
35+
class UnknownApiErrorException(ApiException):
36+
pass
37+
38+
39+
class BadRequestException(ApiException):
40+
pass
41+
42+
43+
class UnauthorizedException(ApiException):
44+
pass
45+
46+
47+
class ForbiddenException(ApiException):
48+
pass
49+
50+
51+
class NotFoundException(ApiException):
52+
pass
53+
54+
55+
class MethodNotAllowedException(ApiException):
56+
pass
57+
58+
59+
class TooManyRequestsException(ApiException):
60+
pass
61+
62+
63+
class PleaseContactBunqException(ApiException):
64+
pass

0 commit comments

Comments
 (0)