Skip to content

Commit 78390d2

Browse files
committed
Merge branch 'release/1.14.1'
2 parents 2ba6b48 + 41357ad commit 78390d2

40 files changed

+1500
-1055
lines changed

.github/ISSUE_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
[//]: # (If there is a traceback please share it in a quote! You can do this by pasting the traceback text, highlighting it and pressing the quote button.)
1212

1313
## SDK version and environment
14-
- Tested on [0.12.4](https://github.com/bunq/sdk_python/releases/tag/0.12.4)
14+
- Tested on [1.14.1](https://github.com/bunq/sdk_python/releases/tag/1.14.1)
1515
- [ ] Sandbox
1616
- [ ] Production
1717

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
## This PR closes/fixes the following issues:
66
[//]: # (If for some reason your pull request does not require a test case you can just mark this box as checked and explain why it does not require a test case.)
7-
- Closes bunq/sdk_php#
7+
- Closes bunq/sdk_python#
88
- [ ] Tested

CHANGELOG.md

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# Changelog
22

3+
## [Unreleased](https://github.com/bunq/sdk_python/tree/HEAD)
4+
5+
[Full Changelog](https://github.com/bunq/sdk_python/compare/1.14.0...HEAD)
6+
7+
**Implemented enhancements:**
8+
9+
- Add a test for oauth\_authorization\_uri [\#145](https://github.com/bunq/sdk_python/issues/145)
10+
- Update tests with Type Hints \(and other small Type Hint improvements\) [\#139](https://github.com/bunq/sdk_python/issues/139)
11+
- Complete OAuth/PSD2 implementation [\#136](https://github.com/bunq/sdk_python/issues/136)
12+
- Allow for a looser range of runtime dependency versions in conformance with semver backward compatibility guarantees [\#107](https://github.com/bunq/sdk_python/issues/107)
13+
- Updated dependencies, and made them more flexible [\#146](https://github.com/bunq/sdk_python/pull/146) ([angelomelonas](https://github.com/angelomelonas))
14+
- Added type hints for tests [\#141](https://github.com/bunq/sdk_python/pull/141) ([angelomelonas](https://github.com/angelomelonas))
15+
16+
**Fixed bugs:**
17+
18+
- Add missing \_user\_payment\_service\_provider variable with the value None to session\_server [\#135](https://github.com/bunq/sdk_python/pull/135) ([siccovansas](https://github.com/siccovansas))
19+
20+
**Closed issues:**
21+
22+
- Breaking changes since v1.13.0 [\#142](https://github.com/bunq/sdk_python/issues/142)
23+
- Is this repository even maintained? [\#140](https://github.com/bunq/sdk_python/issues/140)
24+
- AttributeError: 'SessionServer' object has no attribute '\_user\_payment\_service\_provider' [\#134](https://github.com/bunq/sdk_python/issues/134)
25+
- cannot import name 'ApiContext' from 'bunq.sdk.context' [\#132](https://github.com/bunq/sdk_python/issues/132)
26+
- The CHANGELOG is out of date [\#131](https://github.com/bunq/sdk_python/issues/131)
27+
- Error in class conversion since BillingInvoice does not exist [\#124](https://github.com/bunq/sdk_python/issues/124)
28+
29+
**Merged pull requests:**
30+
31+
- Update CHANGELOG with breaking changes [\#143](https://github.com/bunq/sdk_python/pull/143) ([angelomelonas](https://github.com/angelomelonas))
32+
- sdk\_python\#136 complete Oauth/PSD2 implementation [\#138](https://github.com/bunq/sdk_python/pull/138) ([angelomelonas](https://github.com/angelomelonas))
33+
- update setup.py: only python 3.7 is supported. [\#133](https://github.com/bunq/sdk_python/pull/133) ([csdenboer](https://github.com/csdenboer))
34+
35+
## [1.14.0](https://github.com/bunq/sdk_python/tree/1.14.0) (2020-08-04)
36+
37+
[Full Changelog](https://github.com/bunq/sdk_python/compare/1.13.1...1.14.0)
38+
339
## [1.13.1](https://github.com/bunq/sdk_python/tree/1.13.1) (2020-02-21)
440

541
[Full Changelog](https://github.com/bunq/sdk_python/compare/1.13.0...1.13.1)
@@ -267,10 +303,10 @@
267303
- Add proxy support to Python SDK [\#16](https://github.com/bunq/sdk_python/issues/16)
268304
- Break the SDK's dependence on the bunq.conf file [\#11](https://github.com/bunq/sdk_python/issues/11)
269305
- Response is missing response headers and pagination [\#9](https://github.com/bunq/sdk_python/issues/9)
306+
- cleanup tests \[\#18\] [\#19](https://github.com/bunq/sdk_python/pull/19) ([dnl-blkv](https://github.com/dnl-blkv))
270307
- Changed test class name [\#14](https://github.com/bunq/sdk_python/pull/14) ([OGKevin](https://github.com/OGKevin))
271308
- Load and Save an ApiContext from and to JSON Data [\#13](https://github.com/bunq/sdk_python/pull/13) ([PJUllrich](https://github.com/PJUllrich))
272309
- \#9 Introduce BunqResponse [\#10](https://github.com/bunq/sdk_python/pull/10) ([dnl-blkv](https://github.com/dnl-blkv))
273-
- Readme for tests [\#5](https://github.com/bunq/sdk_python/pull/5) ([OGKevin](https://github.com/OGKevin))
274310

275311
**Closed issues:**
276312

@@ -287,7 +323,7 @@
287323
**Implemented enhancements:**
288324

289325
- Submit this as package to PyPi [\#2](https://github.com/bunq/sdk_python/issues/2)
290-
- cleanup tests \[\#18\] [\#19](https://github.com/bunq/sdk_python/pull/19) ([dnl-blkv](https://github.com/dnl-blkv))
326+
- Readme for tests [\#5](https://github.com/bunq/sdk_python/pull/5) ([OGKevin](https://github.com/OGKevin))
291327
- Uploaded to PyPi [\#4](https://github.com/bunq/sdk_python/pull/4) ([OGKevin](https://github.com/OGKevin))
292328
- Add first series of unit-tests [\#1](https://github.com/bunq/sdk_python/pull/1) ([OGKevin](https://github.com/OGKevin))
293329

CONTRIBUTING.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
### How to contribute to the bunq Python SDK 😎
22

33
#### Want to add a new amazing feature to our SDK? 🚀
4-
- First let’s discuss the feature that you would like to add. [Open a new issue](https://github.com/bunq/bunq-Python/issues/new), describe the feature and explain why you think it should be added.
4+
- First let’s discuss the feature that you would like to add. [Open a new issue](https://github.com/bunq/sdk_python/issues/new), describe the feature and explain why you think it should be added.
55
- Once we agree on the new feature, open a new GitHub pull request and include all the relevant information to get your code approved!
66

77
#### Did you find a bug? 🐛
8-
- Before opening a new issue check if the bug hasn't already been reported by searching on GitHub under [issues](https://github.com/bunq/bunq-Python/issues).
9-
- If it hasn't already been reported you can [open a new issue](https://github.com/bunq/bunq-Python/issues/new). Make sure you include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behaviour that is not occurring.
8+
- Before opening a new issue check if the bug hasn't already been reported by searching on GitHub under [issues](https://github.com/bunq/sdk_python/issues).
9+
- If it hasn't already been reported you can [open a new issue](https://github.com/bunq/sdk_python/issues/new). Make sure you include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behaviour that is not occurring.
1010
- If you wrote a patch that fixes a bug, open a new GitHub pull request and make sure to clearly describe the problem and your awesome solution.
1111

1212
#### Do you have questions about the source code?

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.14.0
1+
1.14.1

bunq/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Type, Any
1+
from typing import Type
22

33
from bunq.sdk.context.api_environment_type import ApiEnvironmentType
44
from bunq.sdk.context.installation_context import InstallationContext
@@ -42,11 +42,11 @@ def initialize_converter() -> None:
4242
converter.register_adapter(datetime.datetime, DateTimeAdapter)
4343
converter.register_adapter(Pagination, PaginationAdapter)
4444

45-
def register_anchor_adapter(class_to_register: Type[Any]) -> None:
45+
def register_anchor_adapter(class_to_register: Type[T]) -> None:
4646
if issubclass(class_to_register, AnchorObjectInterface):
4747
converter.register_adapter(class_to_register, AnchorObjectAdapter)
4848

49-
def get_class(class_string_to_get: str) -> Type[Any]:
49+
def get_class(class_string_to_get: str) -> Type[T]:
5050
if hasattr(object_, class_string_to_get):
5151
return getattr(object_, class_string_to_get)
5252

bunq/sdk/context/api_context.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ def create_for_psd2(cls,
8484
service_provider_credential = api_context.__initialize_psd2_credential(
8585
certificate,
8686
private_key,
87-
all_chain_certificate)
87+
all_chain_certificate
88+
)
8889

8990
api_context._api_key = service_provider_credential.token_value
9091

bunq/sdk/http/anonymous_api_client.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from typing import Dict
2+
3+
import requests
4+
5+
from bunq.sdk.context.api_context import ApiContext
6+
from bunq.sdk.http.api_client import ApiClient
7+
from bunq.sdk.http.bunq_response_raw import BunqResponseRaw
8+
from bunq.sdk.security import security
9+
10+
11+
class AnonymousApiClient(ApiClient):
12+
13+
def __init__(self, api_context: ApiContext) -> None:
14+
super().__init__(api_context)
15+
16+
def post(self,
17+
uri_relative: str,
18+
request_bytes: bytes,
19+
custom_headers: Dict[str, str]) -> BunqResponseRaw:
20+
return self._request(
21+
self.METHOD_POST,
22+
uri_relative,
23+
request_bytes,
24+
{},
25+
custom_headers
26+
)
27+
28+
def _request(self,
29+
method: str,
30+
uri_relative: str,
31+
request_bytes: bytes,
32+
params: Dict[str, str],
33+
custom_headers: Dict[str, str]) -> BunqResponseRaw:
34+
from bunq.sdk.context.bunq_context import BunqContext
35+
36+
uri_relative_with_params = self._append_params_to_uri(uri_relative, params)
37+
if uri_relative not in self._URIS_NOT_REQUIRING_ACTIVE_SESSION:
38+
if self._api_context.ensure_session_active():
39+
BunqContext.update_api_context(self._api_context)
40+
41+
all_headers = self._get_all_headers(
42+
request_bytes,
43+
custom_headers
44+
)
45+
46+
response = requests.request(
47+
method,
48+
uri_relative_with_params,
49+
data=request_bytes,
50+
headers=all_headers,
51+
proxies={self.FIELD_PROXY_HTTPS: self._api_context.proxy_url},
52+
)
53+
54+
self._assert_response_success(response)
55+
56+
if self._api_context.installation_context is not None:
57+
security.validate_response(
58+
self._api_context.installation_context.public_key_server,
59+
response.status_code,
60+
response.content,
61+
response.headers
62+
)
63+
64+
return BunqResponseRaw(response.content, response.headers)

bunq/sdk/http/api_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class ApiClient:
5959
HEADER_RESPONSE_ID_LOWER_CASED = 'x-bunq-client-response-id'
6060

6161
# Default header values
62-
USER_AGENT_BUNQ = 'bunq-sdk-python/1.14.0'
62+
USER_AGENT_BUNQ = 'bunq-sdk-python/1.14.1'
6363
GEOLOCATION_ZERO = '0 0 0 0 NL'
6464
LANGUAGE_EN_US = 'en_US'
6565
REGION_NL_NL = 'nl_NL'

bunq/sdk/http/http_util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Dict
2+
3+
4+
class HttpUtil:
5+
QUERY_FORMAT = '{}={}'
6+
QUERY_DELIMITER = '&'
7+
8+
@classmethod
9+
def create_query_string(cls, all_parameter: Dict[str, str]):
10+
encoded_parameters = []
11+
12+
for parameter, value in all_parameter.items():
13+
encoded_parameters.append(cls.QUERY_FORMAT.format(parameter, value))
14+
15+
return cls.QUERY_DELIMITER.join(encoded_parameters)

bunq/sdk/json/converter.py

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import typing
88
import warnings
99
from types import ModuleType
10-
from typing import Type, Optional, Callable, Generator, Any, Dict, Match, List, Union, Generic
10+
from typing import Type, Optional, Callable, Generator, Dict, Match, List, Union, Generic
1111

1212
from bunq.sdk.exception.bunq_exception import BunqException
1313
from bunq.sdk.util.type_alias import T, JsonValue
@@ -74,14 +74,14 @@ def register_custom_adapter(cls,
7474
cls._custom_deserializers[class_name] = adapter
7575

7676
@classmethod
77-
def _get_serializer(cls, cls_for: Type[Any]) -> type:
77+
def _get_serializer(cls, cls_for: Type[T]) -> type:
7878
if cls_for.__name__ in cls._custom_serializers:
7979
return cls._custom_serializers[cls_for.__name__]
8080

8181
return JsonAdapter
8282

8383
@classmethod
84-
def _get_deserializer(cls, cls_for: Type[Any]) -> Type[JsonAdapter]:
84+
def _get_deserializer(cls, cls_for: Type[T]) -> Type[JsonAdapter]:
8585
if cls_for.__name__ in cls._custom_deserializers:
8686
return cls._custom_deserializers[cls_for.__name__]
8787

@@ -121,7 +121,7 @@ def _deserialize_default(cls,
121121
@classmethod
122122
def _is_deserialized(cls,
123123
cls_target: Type[T],
124-
obj: Any) -> bool:
124+
obj: T) -> bool:
125125
if cls_target is None:
126126
return True
127127

@@ -151,7 +151,7 @@ def _deserialize_dict(cls,
151151

152152
@classmethod
153153
def _deserialize_dict_attributes(cls,
154-
cls_context: Type[Any],
154+
cls_context: Type[T],
155155
dict_: Dict) -> Dict:
156156
dict_deserialized = {}
157157

@@ -243,7 +243,7 @@ def _str_to_type(cls,
243243
@classmethod
244244
def _str_to_type_from_member_module(cls,
245245
module_: ModuleType,
246-
string: str) -> Type[Any]:
246+
string: str) -> Type[T]:
247247
"""
248248
249249
:raise: BunqException when could not find the class for the string.
@@ -307,7 +307,7 @@ def can_serialize(cls) -> bool:
307307
return True
308308

309309
@classmethod
310-
def serialize(cls, obj: Any) -> JsonValue:
310+
def serialize(cls, obj: T) -> JsonValue:
311311
cls._initialize()
312312
serializer = cls._get_serializer(type(obj))
313313

@@ -317,7 +317,7 @@ def serialize(cls, obj: Any) -> JsonValue:
317317
return serializer.serialize(obj)
318318

319319
@classmethod
320-
def _serialize_default(cls, obj: Any) -> JsonValue:
320+
def _serialize_default(cls, obj: T) -> JsonValue:
321321
if obj is None or cls._is_primitive(obj):
322322
return obj
323323
elif cls._is_bytes(obj):
@@ -330,19 +330,19 @@ def _serialize_default(cls, obj: Any) -> JsonValue:
330330
return cls._serialize_dict(dict_)
331331

332332
@classmethod
333-
def _is_primitive(cls, obj: Any) -> bool:
333+
def _is_primitive(cls, obj: T) -> bool:
334334
return cls._is_type_primitive(type(obj))
335335

336336
@classmethod
337-
def _is_type_primitive(cls, type_: Type[Any]) -> bool:
337+
def _is_type_primitive(cls, type_: Type[T]) -> bool:
338338
return type_ in {int, str, bool, float}
339339

340340
@classmethod
341-
def _is_bytes(cls, obj: Any) -> bool:
341+
def _is_bytes(cls, obj: T) -> bool:
342342
return cls._is_bytes_type(type(obj))
343343

344344
@classmethod
345-
def _is_bytes_type(cls, type_: Type[Any]) -> bool:
345+
def _is_bytes_type(cls, type_: Type[T]) -> bool:
346346
return type_.__name__ in cls._TYPE_NAMES_BYTES
347347

348348
@classmethod
@@ -356,7 +356,7 @@ def _serialize_list(cls, list_: List) -> List:
356356
return list_serialized
357357

358358
@classmethod
359-
def _get_obj_raw(cls, obj: Any) -> Dict:
359+
def _get_obj_raw(cls, obj: T) -> Dict:
360360
return obj if type(obj) == dict else obj.__dict__
361361

362362
@classmethod
@@ -375,32 +375,22 @@ def _serialize_dict(cls, dict_: Dict) -> Dict:
375375

376376

377377
class ValueTypes:
378-
"""
379-
:type _main: type|None
380-
:type _sub: type|None
381-
"""
382-
383378
def __init__(self,
384-
main: Type[Any] = None,
385-
sub: Type[Any] = None) -> None:
379+
main: Type[T] = None,
380+
sub: Type[T] = None) -> None:
386381
self._main = main
387382
self._sub = sub
388383

389384
@property
390-
def main(self) -> Type[Any]:
385+
def main(self) -> Type[T]:
391386
return self._main
392387

393388
@property
394-
def sub(self) -> Type[Any]:
389+
def sub(self) -> Type[T]:
395390
return self._sub
396391

397392

398393
class ValueSpecs:
399-
"""
400-
:type _name: str|None
401-
:type _types: ValueTypes|None
402-
"""
403-
404394
def __init__(self,
405395
name: str = None,
406396
types: ValueTypes = None) -> None:
@@ -444,11 +434,11 @@ def deserialize(cls: Type[T], obj_raw: JsonValue) -> T:
444434
return JsonAdapter.deserialize(cls, obj_raw)
445435

446436

447-
def class_to_json(obj: Any) -> JsonValue:
437+
def class_to_json(obj: T) -> JsonValue:
448438
obj_raw = serialize(obj)
449439

450440
return json.dumps(obj_raw, indent=_JSON_INDENT, sort_keys=True)
451441

452442

453-
def serialize(obj_cls: Any) -> JsonValue:
443+
def serialize(obj_cls: T) -> JsonValue:
454444
return JsonAdapter.serialize(obj_cls)

bunq/sdk/json/session_server_adapter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def deserialize(cls,
5757
),
5858
cls._ATTRIBUTE_USER_COMPANY: None,
5959
cls._ATTRIBUTE_USER_PERSON: None,
60+
cls._ATTRIBUTE_USER_PAYMENT_SERVER_PROVIDER: None,
6061
}
6162

6263
user_dict_wrapped = array[cls._INDEX_USER]

0 commit comments

Comments
 (0)