From 67dfb41837c39647d36aad7418b582ef7bf5bed3 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 13:06:00 +0200 Subject: [PATCH 1/8] Added functionality to the ApiContext to save and restore a context to and from JSON data --- bunq/sdk/context.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index f2778dd..9a75236 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -254,9 +254,10 @@ def session_context(self): return self._session_context - def save(self, path=None): + def save(self, path=None, to_json=False): """ :type path: str + :type to_json: bool :rtype: None """ @@ -264,13 +265,17 @@ def save(self, path=None): if path is None: path = self._PATH_API_CONTEXT_DEFAULT + if to_json: + return converter.class_to_json(self) + with open(path, self._FILE_MODE_WRITE) as file: file.write(converter.class_to_json(self)) @classmethod - def restore(cls, path=None): + def restore(cls, path=None, json_data=None): """ :type path: str + :type json_data: str :rtype: ApiContext """ @@ -278,6 +283,9 @@ def restore(cls, path=None): if path is None: path = cls._PATH_API_CONTEXT_DEFAULT + if json_data is not None: + return converter.json_to_class(ApiContext, json_data) + with open(path, cls._FILE_MODE_READ) as file: return converter.json_to_class(ApiContext, file.read()) From d4994dede8a4135d983b8db9360fe08602ef15ef Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 13:11:21 +0200 Subject: [PATCH 2/8] Add a clarification of the example config.json to the Test Readme --- tests/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/README.md b/tests/README.md index 8215f8f..b2ea44f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -37,6 +37,16 @@ of a configuration file is located at [`tests/assets/config.example.json`](./ass In order to make use of the configuration file, please copy the example to the same directory, fill in your sandbox user data and rename the copy to config.json. +Note: +* `MONETARY_ACCOUNT_ID` and `MONETARY_ACCOUNT_ID2` must be of same user +* `CounterPartyOther` must be of another Sandbox user +* You can create a `CASH_REGISTER_ID` on doc.bunq.com + 1. Add your **Developer Key** to `settings` + 2. Upload an image to the `Attachment Public` endpoint + 3. Create an `Avatar` with the returned UUID + 4. Use the Avatar's UUID to create a `Cash Register` + 5. Copy the Cash Register's ID to the `config.json` + ## Execution You can run the tests via command line: From f732248641967b0ffb1a9dad4f9afd2e841a8105 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 14:09:31 +0200 Subject: [PATCH 3/8] Added unittests for the ApiContext.save() and ApiContext.restore() functions in order to test whether modifying them in the last commit broke them or not. --- bunq/sdk/context.py | 7 +- tests/model/generated/test_api_context.py | 85 +++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/model/generated/test_api_context.py diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index 9a75236..626c763 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -259,7 +259,7 @@ def save(self, path=None, to_json=False): :type path: str :type to_json: bool - :rtype: None + :rtype: Union[None, str] """ if path is None: @@ -289,6 +289,11 @@ def restore(cls, path=None, json_data=None): with open(path, cls._FILE_MODE_READ) as file: return converter.json_to_class(ApiContext, file.read()) + def __eq__(self, other): + return self.token == other.token \ + and self.api_key == other.api_key \ + and self.environment_type == other.environment_type + class InstallationContext(object): """ diff --git a/tests/model/generated/test_api_context.py b/tests/model/generated/test_api_context.py new file mode 100644 index 0000000..afb8cb3 --- /dev/null +++ b/tests/model/generated/test_api_context.py @@ -0,0 +1,85 @@ +import os + +from bunq.sdk.context import ApiContext +from bunq.sdk.json import converter +from tests.bunq_test import BunqSdkTestCase + + +class ApiContextTest(BunqSdkTestCase): + """ + Tests: + ApiContext + """ + + _TMP_FILE_PATH = '/context-save-test.conf' + + @classmethod + def setUpClass(cls): + cls._FILE_MODE_READ = ApiContext._FILE_MODE_READ + cls._API_CONTEXT = cls._get_api_context() + cls._TMP_FILE_PATH_FULL = (cls._get_directory_test_root() + + cls._TMP_FILE_PATH) + + def test_api_context_save(self): + """ + Converts an ApiContext to JSON data, saves the same ApiContext to a + temporary file, and compares whether the JSON data is equal to the + data in the file. + + Removes the temporary file before assertion. + """ + + context_json = converter.class_to_json(self._API_CONTEXT) + + self._API_CONTEXT.save(self._TMP_FILE_PATH_FULL) + + with open(self._TMP_FILE_PATH_FULL, self._FILE_MODE_READ) as file: + context_retrieved = file.read() + + os.remove(self._TMP_FILE_PATH_FULL) + + self.assertEqual(context_retrieved, context_json) + + def test_api_context_restore(self): + """ + Saves an ApiContext to a temporary file, restores an ApiContext from + that file, and compares whether the api_keys, tokens, and environment + types are equal in the ApiContext and the restored ApiContext. + + Removes the temporary file before assertion. + """ + + self._API_CONTEXT.save(self._TMP_FILE_PATH_FULL) + api_context_restored = ApiContext.restore(self._TMP_FILE_PATH_FULL) + + os.remove(self._TMP_FILE_PATH_FULL) + + self.assertEqual(api_context_restored, self._API_CONTEXT) + + def test_api_context_save_json(self): + """ + Converts an ApiContext to JSON data, saves the ApiContext using the + ApiContext.save() function with the to_JSON flag set to True, and + compares whether the JSON data equals the returned JSON data from the + ApiContext.save() function. + """ + + context_json = converter.class_to_json(self._API_CONTEXT) + context_saved = self._API_CONTEXT.save(to_json=True) + + self.assertEqual(context_saved, context_json) + + def test_api_context_restore_json(self): + """ + Saves an ApiContext with the ApiContext.save() function with the + to_JSON flag set to True, restores an ApiContext from the JSON data + returned from the ApiContext.save() function, and checks that the + api_key, token, and environment type variables of the restored + ApiContext are equal to the respective variables in the original + ApiContext. + """ + + context_json = self._API_CONTEXT.save(to_json=True) + api_context_restored = self._API_CONTEXT.restore(json_data=context_json) + + self.assertEqual(api_context_restored, self._API_CONTEXT) From eb969c0020acde9db2ebff92d5655efecd9f4de2 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 14:57:28 +0200 Subject: [PATCH 4/8] Extracted a to_json and from_json function from ApiContext.save() and ApiContext.restore() Added beautiful braces to ApiContext.__eq__() Updated the unittests for ApiContext accordingly --- bunq/sdk/context.py | 46 ++++++++++++++--------- tests/model/generated/test_api_context.py | 10 ++--- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index 626c763..7d61deb 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -254,28 +254,41 @@ def session_context(self): return self._session_context - def save(self, path=None, to_json=False): + def to_json(self): + """ + Serializes an ApiInstance to JSON data + + :return: str + """ + return converter.class_to_json(self) + + @classmethod + def from_json(cls, data): + """ + Creates an ApiContext instance from JSON data + + :param data: str + :return: ApiContext + """ + return converter.json_to_class(ApiContext, data) + + def save(self, path=None): """ :type path: str - :type to_json: bool - :rtype: Union[None, str] + :rtype: None, str """ if path is None: path = self._PATH_API_CONTEXT_DEFAULT - if to_json: - return converter.class_to_json(self) - - with open(path, self._FILE_MODE_WRITE) as file: - file.write(converter.class_to_json(self)) + with open(path, self._FILE_MODE_WRITE) as file_: + file_.write(self.to_json()) @classmethod - def restore(cls, path=None, json_data=None): + def restore(cls, path=None): """ :type path: str - :type json_data: str :rtype: ApiContext """ @@ -283,16 +296,13 @@ def restore(cls, path=None, json_data=None): if path is None: path = cls._PATH_API_CONTEXT_DEFAULT - if json_data is not None: - return converter.json_to_class(ApiContext, json_data) - - with open(path, cls._FILE_MODE_READ) as file: - return converter.json_to_class(ApiContext, file.read()) + with open(path, cls._FILE_MODE_READ) as file_: + return cls.from_json(file_.read()) def __eq__(self, other): - return self.token == other.token \ - and self.api_key == other.api_key \ - and self.environment_type == other.environment_type + return (self.token == other.token and + self.api_key == other.api_key and + self.environment_type == other.environment_type) class InstallationContext(object): diff --git a/tests/model/generated/test_api_context.py b/tests/model/generated/test_api_context.py index afb8cb3..ed44d13 100644 --- a/tests/model/generated/test_api_context.py +++ b/tests/model/generated/test_api_context.py @@ -33,8 +33,8 @@ def test_api_context_save(self): self._API_CONTEXT.save(self._TMP_FILE_PATH_FULL) - with open(self._TMP_FILE_PATH_FULL, self._FILE_MODE_READ) as file: - context_retrieved = file.read() + with open(self._TMP_FILE_PATH_FULL, self._FILE_MODE_READ) as file_: + context_retrieved = file_.read() os.remove(self._TMP_FILE_PATH_FULL) @@ -65,7 +65,7 @@ def test_api_context_save_json(self): """ context_json = converter.class_to_json(self._API_CONTEXT) - context_saved = self._API_CONTEXT.save(to_json=True) + context_saved = self._API_CONTEXT.to_json() self.assertEqual(context_saved, context_json) @@ -79,7 +79,7 @@ def test_api_context_restore_json(self): ApiContext. """ - context_json = self._API_CONTEXT.save(to_json=True) - api_context_restored = self._API_CONTEXT.restore(json_data=context_json) + context_json = self._API_CONTEXT.to_json() + api_context_restored = self._API_CONTEXT.from_json(context_json) self.assertEqual(api_context_restored, self._API_CONTEXT) From 60a4579b3be864296371b05eeaa303f06f493d16 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 15:11:35 +0200 Subject: [PATCH 5/8] Formatted the docstrings --- bunq/sdk/context.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index 7d61deb..ddbce6b 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -258,7 +258,7 @@ def to_json(self): """ Serializes an ApiInstance to JSON data - :return: str + :rtype: str """ return converter.class_to_json(self) @@ -267,8 +267,9 @@ def from_json(cls, data): """ Creates an ApiContext instance from JSON data - :param data: str - :return: ApiContext + :type data: str + + :rtype: ApiContext """ return converter.json_to_class(ApiContext, data) From 592b44c8c1dd07c5ed0eb2ad743d7e3010d72ec9 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 15:23:19 +0200 Subject: [PATCH 6/8] Deleted str from docstring in save() --- bunq/sdk/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index ddbce6b..9c07f17 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -277,7 +277,7 @@ def save(self, path=None): """ :type path: str - :rtype: None, str + :rtype: None """ if path is None: From 60440e0dd726491570b435de29131d7199c41e83 Mon Sep 17 00:00:00 2001 From: Peter Ullrich Date: Tue, 15 Aug 2017 16:49:47 +0200 Subject: [PATCH 7/8] Making PRs is fun! --- bunq/sdk/context.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index 9c07f17..34311f8 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -256,21 +256,23 @@ def session_context(self): def to_json(self): """ - Serializes an ApiInstance to JSON data + Serializes an ApiContext to JSON string :rtype: str """ + return converter.class_to_json(self) @classmethod def from_json(cls, data): """ - Creates an ApiContext instance from JSON data + Creates an ApiContext instance from JSON string. :type data: str :rtype: ApiContext """ + return converter.json_to_class(ApiContext, data) def save(self, path=None): From 7e62a69177c80888585fbadd2224d84d64ddbc51 Mon Sep 17 00:00:00 2001 From: Daniil Belyakov Date: Tue, 15 Aug 2017 17:22:06 +0200 Subject: [PATCH 8/8] Little cleanup --- bunq/sdk/context.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/bunq/sdk/context.py b/bunq/sdk/context.py index 34311f8..f685ed2 100644 --- a/bunq/sdk/context.py +++ b/bunq/sdk/context.py @@ -254,27 +254,6 @@ def session_context(self): return self._session_context - def to_json(self): - """ - Serializes an ApiContext to JSON string - - :rtype: str - """ - - return converter.class_to_json(self) - - @classmethod - def from_json(cls, data): - """ - Creates an ApiContext instance from JSON string. - - :type data: str - - :rtype: ApiContext - """ - - return converter.json_to_class(ApiContext, data) - def save(self, path=None): """ :type path: str @@ -288,6 +267,15 @@ def save(self, path=None): with open(path, self._FILE_MODE_WRITE) as file_: file_.write(self.to_json()) + def to_json(self): + """ + Serializes an ApiContext to JSON string. + + :rtype: str + """ + + return converter.class_to_json(self) + @classmethod def restore(cls, path=None): """ @@ -301,6 +289,18 @@ def restore(cls, path=None): with open(path, cls._FILE_MODE_READ) as file_: return cls.from_json(file_.read()) + + @classmethod + def from_json(cls, json_str): + """ + Creates an ApiContext instance from JSON string. + + :type json_str: str + + :rtype: ApiContext + """ + + return converter.json_to_class(ApiContext, json_str) def __eq__(self, other): return (self.token == other.token and