From: Henryk Plötz Date: Tue, 21 Aug 2018 07:34:02 +0000 (+0200) Subject: Improve dialog handling: Drastically reduce latancy. X-Git-Tag: v2.0.0~1^2~94 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b3d8a7761871f0555793f80a10f2ea75476bfeb4;p=thirdparty%2Fpython-fints.git Improve dialog handling: Drastically reduce latancy. + Make FinTSDialog re-entrant: Entering the context multiple times will only init()/end() at the outermost layer + Turn FinTSClient into a context manager. Entering it will start a dialog that will be kept open, no need to repeatedly start/end dialogues Example: ```` f = FinTS3PinTanClient(...) with f: accounts = f.get_sepa_accounts() balance = f.get_balance(accounts[0]) statement = f.get_statement(accounts[0]) ```` --- diff --git a/fints/client.py b/fints/client.py index f38c503..b4f86cf 100644 --- a/fints/client.py +++ b/fints/client.py @@ -58,8 +58,9 @@ class FinTS3Client: self.selected_security_function = None self.product_name = 'pyfints' self.product_version = '0.2' + self._standing_dialog = None - def _new_dialog(self, lazy_init=False): + def _get_dialog(self, lazy_init=False): raise NotImplemented() def _new_message(self, dialog: FinTSDialogOLD, segments, tan=None): @@ -68,6 +69,20 @@ class FinTS3Client: def _ensure_system_id(self): raise NotImplemented() + def __enter__(self): + if self._standing_dialog: + raise Error("Cannot double __enter__() {}".format(self)) + self._standing_dialog = self._get_dialog() + self._standing_dialog.__enter__() + + def __exit__(self, exc_type, exc_value, traceback): + if self._standing_dialog: + self._standing_dialog.__exit__(exc_type, exc_value, traceback) + else: + raise Error("Cannot double __exit__() {}".format(self)) + + self._standing_dialog = None + def process_institute_response(self, message): bpa = message.find_segment_first(HIBPA3) if bpa: @@ -101,7 +116,7 @@ class FinTS3Client: :return: List of SEPAAccount objects. """ - with self._new_dialog() as dialog: + with self._get_dialog() as dialog: response = dialog.send(HKSPA1()) self.accounts = [] @@ -120,7 +135,7 @@ class FinTS3Client: :return: A list of mt940.models.Transaction objects """ - with self._new_dialog() as dialog: + with self._get_dialog() as dialog: max_hikazs = self.bpd.find_segment_highest_version('HIKAZS', (5, 6, 7)) if not max_hikazs: raise ValueError('No supported HIKAZS version found') @@ -179,7 +194,7 @@ class FinTS3Client: :return: A mt940.models.Balance object """ - with self._new_dialog() as dialog: + with self._get_dialog() as dialog: max_hisals = self.bpd.find_segment_highest_version('HISALS', (5, 6, 7)) if not max_hisals: raise ValueError('No supported HISALS version found') @@ -208,7 +223,7 @@ class FinTS3Client: :return: List of Holding objects """ # init dialog - dialog = self._new_dialog() + dialog = self._get_dialog() dialog.sync() dialog.init() @@ -356,7 +371,7 @@ class FinTS3Client: :param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``) :return: Returns a TANChallenge object """ - dialog = self._new_dialog() + dialog = self._get_dialog() dialog.sync() dialog.tan_mechs = [tan_method] dialog.init() @@ -403,7 +418,7 @@ class FinTS3Client: :param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``) :return: Returns a TANChallenge object """ - dialog = self._new_dialog() + dialog = self._get_dialog() dialog.sync() dialog.tan_mechs = [tan_method] dialog.init() @@ -445,7 +460,7 @@ class FinTS3Client: :return: List of TANMethod objects """ - dialog = self._new_dialog() + dialog = self._get_dialog() dialog.sync() dialog.init() dialog.end() @@ -462,7 +477,7 @@ class FinTS3Client: :return: str """ - dialog = self._new_dialog() + dialog = self._get_dialog() dialog.sync() dialog.init() @@ -485,7 +500,13 @@ class FinTS3PinTanClient(FinTS3Client): self.connection = FinTSHTTPSConnection(server) super().__init__(bank_identifier=bank_identifier, user_id=user_id, customer_id=customer_id) - def _new_dialog(self, lazy_init=False): + def _get_dialog(self, lazy_init=False): + if lazy_init and self._standing_dialog: + raise Error("Cannot _get_dialog(lazy_init=True) with _standing_dialog") + + if self._standing_dialog: + return self._standing_dialog + if not lazy_init: self._ensure_system_id() @@ -514,7 +535,7 @@ class FinTS3PinTanClient(FinTS3Client): if self.system_id != SYSTEM_ID_UNASSIGNED: return - with self._new_dialog(lazy_init=True) as dialog: + with self._get_dialog(lazy_init=True) as dialog: response = dialog.init( HKSYN3(SynchronisationMode.NEW_SYSTEM_ID), ) diff --git a/fints/dialog.py b/fints/dialog.py index 2d25fc2..80bc025 100644 --- a/fints/dialog.py +++ b/fints/dialog.py @@ -29,14 +29,19 @@ class FinTSDialog: self.need_init = True self.lazy_init = lazy_init self.dialogue_id = DIALOGUE_ID_UNASSIGNED + self._context_count = 0 def __enter__(self): - if not self.lazy_init: - self.init() + if self._context_count == 0: + if not self.lazy_init: + self.init() + self._context_count += 1 return self def __exit__(self, exc_type, exc_value, traceback): - self.end() + self._context_count -= 1 + if self._context_count == 0: + self.end() def init(self, *extra_segments): if self.need_init and not self.open: