From 55cdd42ccd6f858093b8d944ab2eec7cb786e5eb Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Mon, 20 Feb 2017 10:51:01 +0100 Subject: [PATCH 01/13] use error code instead of string when raising pin exception --- figo/figo.py | 16 ++++++++++++---- figo/models.py | 5 ++++- tests/test_session.py | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index f2f039c..43a3313 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -139,12 +139,13 @@ class FigoException(Exception): They consist of a code-like `error` and a human readable `error_description`. """ - def __init__(self, error, error_description): + def __init__(self, error, error_description, code=None): """Create a Exception with a error code and error description.""" message = u"%s (%s)" % (error_description, error) super(FigoException, self).__init__(message) # XXX(dennis.lutter): not needed internally but left here for backwards compatibility + self.code = code self.error = error self.error_description = error_description @@ -152,7 +153,14 @@ def __init__(self, error, error_description): def from_dict(cls, dictionary): """Helper function creating an exception instance from the dictionary returned by the server.""" - return cls(dictionary['error']['message'], dictionary['error']['description']) + if 'code' in dictionary['error']: + code = ['code'] + else: + code = None + + return cls(dictionary['error']['message'], + dictionary['error']['description'], + code) class FigoPinException(FigoException): @@ -484,9 +492,9 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, ) if task_state.is_erroneous: - if any([msg in task_state.message for msg in ["Zugangsdaten", "credentials"]]): + if task_state.error['code'] == 10000: raise FigoPinException(country, credentials, bank_code, iban, save_pin) - raise FigoException("", task_state.message) + raise FigoException("", task_state.message, task_state.error['code']) return task_state def add_account_and_sync_with_new_pin(self, pin_exception, new_pin): diff --git a/figo/models.py b/figo/models.py index 4b3ad38..8f59762 100644 --- a/figo/models.py +++ b/figo/models.py @@ -634,7 +634,7 @@ class TaskState(ModelBase): __dump_attributes__ = ["account_id", "message", "is_waiting_for_pin", "is_waiting_for_response", "is_erroneous", - "is_ended", "challenge"] + "is_ended", "challenge", "error"] account_id = None """Account ID of currently processed account""" @@ -659,6 +659,9 @@ class TaskState(ModelBase): challenge = None """Challenge object""" + error = None + """Error dict if error occurred""" + def __str__(self, *args, **kwargs): """Short String representation of a TaskState.""" return "TaskState: '{self.message}' erroneous: {self.is_erroneous} " \ diff --git a/tests/test_session.py b/tests/test_session.py index 3879f3d..7fd8028 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -66,6 +66,7 @@ def test_sync_uri(demo_session): def test_get_mail_from_user(demo_session): assert demo_session.user.email == "demo@figo.me" + @pytest.mark.skip(reason="race condition on travis") def test_create_update_delete_notification(demo_session): """ From d6146cc7087f988041a9a9efb323614cc65e2b31 Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Mon, 20 Feb 2017 18:24:59 +0100 Subject: [PATCH 02/13] add test for wrong pin on postbank --- figo/figo.py | 12 +++--- tests/conftest.py | 7 ++++ tests/test_writing_methods.py | 69 +++++++++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 15 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index 43a3313..9df7b45 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -154,13 +154,11 @@ def from_dict(cls, dictionary): """Helper function creating an exception instance from the dictionary returned by the server.""" if 'code' in dictionary['error']: - code = ['code'] + code = dictionary['error']['code'] else: code = None - return cls(dictionary['error']['message'], - dictionary['error']['description'], - code) + return cls(dictionary['error']['message'], dictionary['error']['description'], code) class FigoPinException(FigoException): @@ -484,7 +482,7 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, logger.debug('task "%s"', task_state) if task_state.is_ended or task_state.is_erroneous: break - sleep(0.5) + sleep(2) else: raise FigoException( 'could not sync', @@ -492,9 +490,9 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, ) if task_state.is_erroneous: - if task_state.error['code'] == 10000: + if task_state.error and task_state.error['code'] == 10000: raise FigoPinException(country, credentials, bank_code, iban, save_pin) - raise FigoException("", task_state.message, task_state.error['code']) + raise FigoException("", task_state.message) return task_state def add_account_and_sync_with_new_pin(self, pin_exception, new_pin): diff --git a/tests/conftest.py b/tests/conftest.py index 823bbf9..052bbf6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,13 +22,17 @@ 'ssl_fingerprint': os.getenv('FIGO_SSL_FINGERPRINT', DEMO_CREDENTIALS['ssl_fingerprint']), } + def is_demo(credentials): return credentials['client_id'] == DEMO_CREDENTIALS['client_id'] + PASSWORD = 'some_words' + DEMO_TOKEN = 'ASHWLIkouP2O6_bgA2wWReRhletgWKHYjLqDaqb0LFfamim9RjexTo22ujRIP_cjLiRiSyQXyt2kM1eXU2XLFZQ0Hro15HikJQT_eNeT_9XQ' + @pytest.fixture(scope='session') def figo_connection(): return FigoConnection(CREDENTIALS['client_id'], @@ -37,10 +41,12 @@ def figo_connection(): api_endpoint=CREDENTIALS['api_endpoint'], fingerprints=[CREDENTIALS['ssl_fingerprint']]) + @pytest.fixture def new_user_id(): return "{0}testuser@example.com".format(uuid.uuid4()) + @pytest.yield_fixture def figo_session(figo_connection, new_user_id): if is_demo(CREDENTIALS): @@ -54,6 +60,7 @@ def figo_session(figo_connection, new_user_id): session.remove_user() + @pytest.yield_fixture(scope='module') def demo_session(): # TODO(Valentin): we need to run `test_session` (both read-only) against production API diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 2a5e886..9638779 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -1,9 +1,11 @@ +# -*- coding:utf-8 -*- + import time -from uuid import uuid4 import pytest +from mock import patch -from figo.figo import FigoPinException +from figo.figo import FigoException, FigoPinException from figo.models import TaskToken, TaskState, Service, LoginSettings CREDENTIALS = ["figo", "figo"] @@ -32,9 +34,57 @@ def t_05_add_account(figo_session): def test_050_add_account_and_sync_wrong_pin(figo_session): wrong_credentials = [CREDENTIALS[0], "123456"] - with pytest.raises(FigoPinException): - figo_session.add_account_and_sync("de", wrong_credentials, BANK_CODE) - assert len(figo_session.accounts) == 0 + try: + with pytest.raises(FigoException): + figo_session.add_account_and_sync("de", wrong_credentials, BANK_CODE) + assert len(figo_session.accounts) == 0 + except FigoException as figo_exception: + # BBB(Valentin): prevent demo account from complaining - it returns no code on error + if "Please use demo account credentials" not in figo_exception.error_description: + raise + + +def test_add_account_and_sync_wrong_pin_postbank(figo_session): + """ + Check that `FigoPinException` is raised correctly on given task state, which occurs + when attempting to add an account to Postbank with syntactically correct (9-digit login), but + invalid credentials. Note that syntactically incorrect credentials return code `20000` and a + different message. + """ + + mock_task_state = { + "is_ended": True, + "account_id": "A2248267.0", + "is_waiting_for_pin": False, + "is_erroneous": True, + "message": "Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " + "Bitteüberprüfen Sie Ihre Benutzerkennung.", + "error": { + "code": 10000, + "group": "user", + "name": "Login credentials are invalid", + "message": "9050 Die Nachricht enthält Fehler.; 9800 Dialog abgebrochen; " + "9010 Initialisierung fehlgeschlagen, Auftrag nicht bearbeitet.; " + "3920 Zugelassene Zwei-Schritt-Verfahren für den Benutzer.; " + "9010 PIN/TAN Prüfung fehlgeschlagen; " + "9931 Anmeldename oder PIN ist falsch.", + "data": {}, + "description": "Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " + "Bitte überprüfen Sie Ihre Benutzerkennung." + }, + "challenge": {}, + "is_waiting_for_response": False + } + + with patch.object(figo_session, 'get_task_state') as mock_state: + with patch.object(figo_session, 'add_account') as mock_account: + + mock_state.return_value = TaskState.from_dict(figo_session, mock_task_state) + mock_account.return_value = None + + with pytest.raises(FigoPinException): + figo_session.add_account_and_sync("de", None, None) + assert len(figo_session.accounts) == 0 def test_051_add_account_and_sync_wrong_and_correct_pin(figo_session): @@ -44,9 +94,12 @@ def test_051_add_account_and_sync_wrong_and_correct_pin(figo_session): task_state = figo_session.add_account_and_sync("de", wrong_credentials, BANK_CODE) except FigoPinException as pin_exception: task_state = figo_session.add_account_and_sync_with_new_pin(pin_exception, CREDENTIALS[1]) - time.sleep(5) - assert isinstance(task_state, TaskState) - assert len(figo_session.accounts) == 3 + assert isinstance(task_state, TaskState) + assert len(figo_session.accounts) == 3 + except FigoException as figo_exception: + # BBB(Valentin): prevent demo account from complaining - it returns no code on error + if "Please use demo account credentials" not in figo_exception.error_description: + raise @pytest.mark.skip(reason="test expects state of account, that are not prepared at the moment") From 0d6533694653f5c4b419aea20373ae83418cb863 Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Tue, 21 Mar 2017 00:25:57 +0100 Subject: [PATCH 03/13] implement lad1337's comments --- figo/figo.py | 9 +++------ tests/test_writing_methods.py | 3 ++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index 9df7b45..c1165b7 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -153,12 +153,9 @@ def __init__(self, error, error_description, code=None): def from_dict(cls, dictionary): """Helper function creating an exception instance from the dictionary returned by the server.""" - if 'code' in dictionary['error']: - code = dictionary['error']['code'] - else: - code = None - - return cls(dictionary['error']['message'], dictionary['error']['description'], code) + return cls(dictionary['error']['message'], + dictionary['error']['description'], + dictionary['error'].get('code')) class FigoPinException(FigoException): diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 9638779..71c0e44 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -82,8 +82,9 @@ def test_add_account_and_sync_wrong_pin_postbank(figo_session): mock_state.return_value = TaskState.from_dict(figo_session, mock_task_state) mock_account.return_value = None - with pytest.raises(FigoPinException): + with pytest.raises(FigoPinException) as e: figo_session.add_account_and_sync("de", None, None) + assert e.value.code == 1000 assert len(figo_session.accounts) == 0 From f3d72c77eed6911455cc7eb85d9ddf7e9f88bf81 Mon Sep 17 00:00:00 2001 From: Deniz Saner Date: Wed, 3 May 2017 09:15:35 +0200 Subject: [PATCH 04/13] Added error code to FigoException --- .gitignore | 3 +++ figo/figo.py | 1 + 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d7bc619..4b51a87 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ htmlcov/* .mr.developer.cfg .project .pydevproject + +# Mac OSX +*.DS_Store diff --git a/figo/figo.py b/figo/figo.py index 3c58aec..b94fa0f 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -136,6 +136,7 @@ def __init__(self, error, error_description): # XXX(dennis.lutter): not needed internally but left here for backwards compatibility self.error = error + self.code = code self.error_description = error_description @classmethod From 97f6e6d7057045948400a7fa8477bdd168f5e784 Mon Sep 17 00:00:00 2001 From: Deniz Saner Date: Wed, 3 May 2017 09:21:03 +0200 Subject: [PATCH 05/13] Added `code` in init function and extended `from_dict` class method --- figo/figo.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index b94fa0f..1672a00 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -123,27 +123,30 @@ def _query_api_object(self, model, path, data=None, method="GET", collection_nam return [model.from_dict(self, dict_entry) for dict_entry in response[collection_name]] -class FigoException(Exception): +class FigoException(Exception):#pragma: no cover """Base class for all exceptions transported via the figo connect API. They consist of a code-like `error` and a human readable `error_description`. """ - def __init__(self, error, error_description): + def __init__(self, error, error_description, code): """Create a Exception with a error code and error description.""" - message = u"%s (%s)" % (error_description, error) - super(FigoException, self).__init__(message) + super(FigoException, self).__init__() - # XXX(dennis.lutter): not needed internally but left here for backwards compatibility self.error = error - self.code = code self.error_description = error_description + self.code = code + + def __str__(self): + """String representation of the FigoException.""" + return "FigoException: %s(%s)" % (repr(self.error_description), repr(self.error)) @classmethod def from_dict(cls, dictionary): """Helper function creating an exception instance from the dictionary returned by the server.""" - return cls(dictionary['error']['message'], dictionary['error']['description']) + return cls(dictionary['error']['message'], dictionary['error']['description'], dictionary['error']['code']) + class FigoPinException(FigoException): From f0b1b96545445c443718b5f610afcfe72029e370 Mon Sep 17 00:00:00 2001 From: Deniz Saner Date: Wed, 3 May 2017 09:23:16 +0200 Subject: [PATCH 06/13] Removed pragma no cover --- figo/figo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/figo/figo.py b/figo/figo.py index 1672a00..498867d 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -123,7 +123,7 @@ def _query_api_object(self, model, path, data=None, method="GET", collection_nam return [model.from_dict(self, dict_entry) for dict_entry in response[collection_name]] -class FigoException(Exception):#pragma: no cover +class FigoException(Exception): """Base class for all exceptions transported via the figo connect API. They consist of a code-like `error` and a human readable `error_description`. From 41ea4ae9f3ed8cdb2267da5cdbf72f192bbdb14a Mon Sep 17 00:00:00 2001 From: Deniz Saner Date: Wed, 3 May 2017 10:19:24 +0200 Subject: [PATCH 07/13] #37 - Fixed Integration tests: Added `90000` as attribute for http related errors and changed `assert len(services) == 28` to `assert len(services) == 27` as this was apperently altered. --- figo/figo.py | 16 ++++++++-------- tests/test_session.py | 1 - tests/test_writing_methods.py | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index 498867d..5eb59d7 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -38,13 +38,12 @@ ERROR_MESSAGES = { - 400: {'message': "bad request", 'description': "Bad request"}, - 401: {'message': "unauthorized", 'description': "Missing, invalid or expired access token."}, - 403: {'message': "forbidden", 'description': "Insufficient permission."}, - 404: {'message': "not_found", 'description': "Not found."}, - 405: {'message': "method_not_allowed", 'description': "Unexpected request method."}, - 503: {'message': "service_unavailable", 'description': "Exceeded rate limit."} - + 400: {'message': "bad request", 'description': "Bad request", 'code': 90000}, + 401: {'message': "unauthorized", 'description': "Missing, invalid or expired access token.", 'code': 90000}, + 403: {'message': "forbidden", 'description': "Insufficient permission.", 'code': 90000}, + 404: {'message': "not_found", 'description': "Not found.", 'code': 90000}, + 405: {'message': "method_not_allowed", 'description': "Unexpected request method.", 'code': 90000}, + 503: {'message': "service_unavailable", 'description': "Exceeded rate limit.", 'code': 90000}, } USER_AGENT = "python_figo/1.5.4" @@ -98,7 +97,8 @@ def _request_api(self, path, data=None, method="GET"): response.status_code) return {'error': { 'message': "internal_server_error", - 'description': "We are very sorry, but something went wrong"}} + 'description': "We are very sorry, but something went wrong", + 'code': 90000}} def _request_with_exception(self, path, data=None, method="GET"): diff --git a/tests/test_session.py b/tests/test_session.py index 3879f3d..cb4f6ac 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -213,7 +213,6 @@ def test_start_process(demo_session): with pytest.raises(FigoException): demo_session.start_process(process_token) - def test_create_process(demo_session): # Access token with process=rw needed process = Process(demo_session, email="demo@demo.de", password="figo", diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 2a5e886..0663d60 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -12,7 +12,7 @@ def test_03_get_supported_payment_services(figo_session): services = figo_session.get_supported_payment_services("de") - assert len(services) == 28 + assert len(services) == 27 assert isinstance(services[0], Service) From c582735ed4d7d45805a59ea474a1e52ac058e69e Mon Sep 17 00:00:00 2001 From: Deniz Saner Date: Mon, 8 May 2017 16:46:17 +0200 Subject: [PATCH 08/13] Implemented changes on #37 requested by @fricklerhandwerk --- .gitignore | 3 --- figo/figo.py | 20 ++++++++++++++------ figo/models.py | 5 ++++- tests/test_session.py | 1 + 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 4b51a87..d7bc619 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,3 @@ htmlcov/* .mr.developer.cfg .project .pydevproject - -# Mac OSX -*.DS_Store diff --git a/figo/figo.py b/figo/figo.py index 5eb59d7..8f6e6bf 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -129,23 +129,31 @@ class FigoException(Exception): They consist of a code-like `error` and a human readable `error_description`. """ - def __init__(self, error, error_description, code): + def __init__(self, error, error_description, code = None): """Create a Exception with a error code and error description.""" super(FigoException, self).__init__() + # XXX(dennis.lutter): not needed internally but left here for backwards compatibility self.error = error self.error_description = error_description self.code = code def __str__(self): """String representation of the FigoException.""" - return "FigoException: %s(%s)" % (repr(self.error_description), repr(self.error)) + return "FigoException: {}({})" .format(self.error_description, self.error) @classmethod def from_dict(cls, dictionary): """Helper function creating an exception instance from the dictionary returned by the server.""" - return cls(dictionary['error']['message'], dictionary['error']['description'], dictionary['error']['code']) + if 'code' in dictionary['error']: + code = ['code'] + else: + code = None + + return cls(dictionary['error']['message'], + dictionary['error']['description'], + code) @@ -166,7 +174,7 @@ def __init__(self, country, credentials, bank_code, iban, save_pin): def __str__(self): """String representation of the FigoPinException.""" - return "FigoPinException: %s(%s)" % (repr(self.error_description), repr(self.error)) + return "FigoPinException: {}({})".format(self.error_description, self.error) class FigoConnection(FigoObject): @@ -465,8 +473,8 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, sleep(0.5) else: raise FigoException( - 'could not sync', - 'task was not finished after {0} tries'.format(self.sync_poll_retry) + "could not sync", + "task was not finished after {0} tries".format(self.sync_poll_retry) ) if task_state.is_erroneous: diff --git a/figo/models.py b/figo/models.py index 4b3ad38..4b6e9dd 100644 --- a/figo/models.py +++ b/figo/models.py @@ -634,7 +634,7 @@ class TaskState(ModelBase): __dump_attributes__ = ["account_id", "message", "is_waiting_for_pin", "is_waiting_for_response", "is_erroneous", - "is_ended", "challenge"] + "is_ended", "challenge", "error"] account_id = None """Account ID of currently processed account""" @@ -659,6 +659,9 @@ class TaskState(ModelBase): challenge = None """Challenge object""" + error = None + """ Dict populated in case of an error""" + def __str__(self, *args, **kwargs): """Short String representation of a TaskState.""" return "TaskState: '{self.message}' erroneous: {self.is_erroneous} " \ diff --git a/tests/test_session.py b/tests/test_session.py index cb4f6ac..3879f3d 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -213,6 +213,7 @@ def test_start_process(demo_session): with pytest.raises(FigoException): demo_session.start_process(process_token) + def test_create_process(demo_session): # Access token with process=rw needed process = Process(demo_session, email="demo@demo.de", password="figo", From 589273e4e0918696ede88cbad22d98f33a71a81d Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Wed, 10 May 2017 11:33:53 +0200 Subject: [PATCH 09/13] use complete unicode strings --- figo/models.py | 6 +++--- tests/test_writing_methods.py | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/figo/models.py b/figo/models.py index 3d434cb..1ada16b 100644 --- a/figo/models.py +++ b/figo/models.py @@ -702,15 +702,15 @@ class TaskState(ModelBase): def __str__(self, *args, **kwargs): """Short String representation of a TaskState.""" string = (u"TaskState: '{self.message}' " - "(is_erroneous: {self.is_erroneous}, " - "is_ended: {self.is_ended})") + u"(is_erroneous: {self.is_erroneous}, " + u"is_ended: {self.is_ended})") # BBB(Valentin): All strings come in UTF-8 from JSON. But: # - python2.6: encode knows no kwargs # - python2.7: `u"{0}".format(x)` returns `unicode`, `__str__()` excpects `str` (ASCII) # - python3.x: encode returns `bytes`,`__str__` expects `str` (UTF-8) # This is really ugly, but works in all pythons. - return str(string.format(self=self).encode('ascii','replace')) + return str(string.format(self=self).encode('ascii', 'replace')) class Challenge(ModelBase): diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 71c0e44..738f44d 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -1,4 +1,4 @@ -# -*- coding:utf-8 -*- +# coding:utf-8 import time @@ -54,23 +54,23 @@ def test_add_account_and_sync_wrong_pin_postbank(figo_session): mock_task_state = { "is_ended": True, - "account_id": "A2248267.0", + "account_id": u"A2248267.0", "is_waiting_for_pin": False, "is_erroneous": True, - "message": "Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " - "Bitteüberprüfen Sie Ihre Benutzerkennung.", + "message": u"Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " + u"Bitte überprüfen Sie Ihre Benutzerkennung.", "error": { "code": 10000, - "group": "user", - "name": "Login credentials are invalid", - "message": "9050 Die Nachricht enthält Fehler.; 9800 Dialog abgebrochen; " - "9010 Initialisierung fehlgeschlagen, Auftrag nicht bearbeitet.; " - "3920 Zugelassene Zwei-Schritt-Verfahren für den Benutzer.; " - "9010 PIN/TAN Prüfung fehlgeschlagen; " - "9931 Anmeldename oder PIN ist falsch.", + "group": u"user", + "name": u"Login credentials are invalid", + "message": u"9050 Die Nachricht enthält Fehler.; 9800 Dialog abgebrochen; " + u"9010 Initialisierung fehlgeschlagen, Auftrag nicht bearbeitet.; " + u"3920 Zugelassene Zwei-Schritt-Verfahren für den Benutzer.; " + u"9010 PIN/TAN Prüfung fehlgeschlagen; " + u"9931 Anmeldename oder PIN ist falsch.", "data": {}, - "description": "Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " - "Bitte überprüfen Sie Ihre Benutzerkennung." + "description": u"Die Anmeldung zum Online-Zugang Ihrer Bank ist fehlgeschlagen. " + u"Bitte überprüfen Sie Ihre Benutzerkennung." }, "challenge": {}, "is_waiting_for_response": False From 9c14d333ef26d8a6af88e5fee19753b8668dba21 Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Wed, 10 May 2017 11:34:22 +0200 Subject: [PATCH 10/13] add generic error data to FigoPinException --- figo/figo.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/figo/figo.py b/figo/figo.py index ef84428..4baa150 100644 --- a/figo/figo.py +++ b/figo/figo.py @@ -176,10 +176,13 @@ class FigoPinException(FigoException): """This exception is thrown if the wrong pin was submitted to a task. It contains information about current state of the task.""" - def __init__(self, country, credentials, bank_code, iban, save_pin): + def __init__(self, country, credentials, bank_code, iban, save_pin, + error="Wrong PIN", + error_description="You've entered a wrong PIN, please provide a new one.", + code=None, + ): """Initialiase an Exception for a wrong PIN which contains information about the task.""" - self.error = "Wrong PIN" - self.error_description = "You've entered a wrong PIN, please provide a new one." + super(FigoPinException, self).__init__(error, error_description, code) self.country = country self.credentials = credentials @@ -502,7 +505,7 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, task_token = self.add_account(country, credentials, bank_code, iban, save_pin) for _ in range(self.sync_poll_retry): task_state = self.get_task_state(task_token) - logger.info("Adding account {0}/{1}: {2}".format(bank_code,iban,task_state.message)) + logger.info("Adding account {0}/{1}: {2}".format(bank_code, iban, task_state.message)) logger.debug(str(task_state)) if task_state.is_ended or task_state.is_erroneous: break @@ -515,7 +518,10 @@ def add_account_and_sync(self, country, credentials, bank_code=None, iban=None, if task_state.is_erroneous: if task_state.error and task_state.error['code'] == 10000: - raise FigoPinException(country, credentials, bank_code, iban, save_pin) + raise FigoPinException(country, credentials, bank_code, iban, save_pin, + error=task_state.error['name'], + error_description=task_state.error['description'], + code=task_state.error['code']) raise FigoException("", task_state.message) return task_state From d12a1257bb9d5d1fab00e37f2cb1995c1b7882ce Mon Sep 17 00:00:00 2001 From: fricklerhandwerk Date: Wed, 10 May 2017 11:34:43 +0200 Subject: [PATCH 11/13] expect the right error code in test --- tests/test_writing_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 738f44d..5cb469d 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -84,7 +84,7 @@ def test_add_account_and_sync_wrong_pin_postbank(figo_session): with pytest.raises(FigoPinException) as e: figo_session.add_account_and_sync("de", None, None) - assert e.value.code == 1000 + assert e.value.code == 10000 assert len(figo_session.accounts) == 0 From c963d51af021f8cd19fc6b0240c675c4b8dffb61 Mon Sep 17 00:00:00 2001 From: berend Date: Wed, 10 May 2017 17:30:07 +0200 Subject: [PATCH 12/13] not asserting a fixed value for number of services. More than 10 seems ok. --- tests/test_writing_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 9507fcb..0c5c56f 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -14,7 +14,7 @@ def test_03_get_supported_payment_services(figo_session): services = figo_session.get_supported_payment_services("de") - assert len(services) == 27 + assert len(services) > 10 # this a changing value, this tests, that some are returned assert isinstance(services[0], Service) From 6332f5f31bb3d3013ed436c84740e5002557ec37 Mon Sep 17 00:00:00 2001 From: berend Date: Fri, 12 May 2017 10:42:30 +0200 Subject: [PATCH 13/13] improve comment --- tests/test_writing_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_writing_methods.py b/tests/test_writing_methods.py index 0c5c56f..3d6ab7f 100644 --- a/tests/test_writing_methods.py +++ b/tests/test_writing_methods.py @@ -14,7 +14,7 @@ def test_03_get_supported_payment_services(figo_session): services = figo_session.get_supported_payment_services("de") - assert len(services) > 10 # this a changing value, this tests, that some are returned + assert len(services) > 10 # this a changing value, this tests that at least some are returned assert isinstance(services[0], Service)