From f09837a9dbef0c0120979d53108b868a85078945 Mon Sep 17 00:00:00 2001 From: Moul <moul@moul.re> Date: Fri, 29 Apr 2022 23:10:27 +0200 Subject: [PATCH] [enh] #397: Replace ClientInstance() singleton with @functools.lru_cache() verify: Switch from Client(determine_endpoint) to client_instance() which was an experiment, switched since this solution is great! --- silkaj/blockchain_tools.py | 6 +++--- silkaj/blocks.py | 5 ++--- silkaj/cert.py | 6 +++--- silkaj/commands.py | 6 +++--- silkaj/idty_tools.py | 4 ++-- silkaj/membership.py | 6 +++--- silkaj/money.py | 6 +++--- silkaj/network_tools.py | 21 +++++---------------- silkaj/tx_history.py | 4 ++-- silkaj/wot.py | 4 ++-- silkaj/wot_tools.py | 6 +++--- tests/test_membership.py | 4 ++-- tests/test_revocation.py | 11 +++++------ tests/test_unit_tx.py | 2 +- tests/test_verify_blocks.py | 7 +++---- 15 files changed, 42 insertions(+), 56 deletions(-) diff --git a/silkaj/blockchain_tools.py b/silkaj/blockchain_tools.py index 376dca0e..67c98710 100644 --- a/silkaj/blockchain_tools.py +++ b/silkaj/blockchain_tools.py @@ -17,18 +17,18 @@ import functools from duniterpy.api.bma import blockchain -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance @functools.lru_cache(maxsize=1) def get_blockchain_parameters(): - client = ClientInstance().client + client = client_instance() return client(blockchain.parameters) @functools.lru_cache(maxsize=1) def get_head_block(): - client = ClientInstance().client + client = client_instance() return client(blockchain.current) diff --git a/silkaj/blocks.py b/silkaj/blocks.py index f8040db6..521287e3 100644 --- a/silkaj/blocks.py +++ b/silkaj/blocks.py @@ -17,13 +17,12 @@ import logging from click import INT, argument, command, progressbar from duniterpy.api import bma -from duniterpy.api.client import Client from duniterpy.api.errors import DuniterError from duniterpy.documents import Block from duniterpy.key.verifying_key import VerifyingKey from silkaj.constants import BMA_MAX_BLOCKS_CHUNK_SIZE -from silkaj.network_tools import determine_endpoint +from silkaj.network_tools import client_instance from silkaj.tools import message_exit @@ -36,7 +35,7 @@ If nothing specified, the whole blockchain gets verified.", @argument("from_block", default=0, type=INT) @argument("to_block", default=0, type=INT) def verify_blocks_signatures(from_block, to_block): - client = Client(determine_endpoint()) + client = client_instance() to_block = check_passed_blocks_range(client, from_block, to_block) invalid_blocks_signatures = list() chunks_from = range(from_block, to_block + 1, BMA_MAX_BLOCKS_CHUNK_SIZE) diff --git a/silkaj/cert.py b/silkaj/cert.py index de3a3a4f..91e596aa 100644 --- a/silkaj/cert.py +++ b/silkaj/cert.py @@ -28,14 +28,14 @@ from silkaj.blockchain_tools import get_blockchain_parameters, get_head_block from silkaj.constants import ALL, DATE, SUCCESS_EXIT_STATUS from silkaj.crypto_tools import is_pubkey_and_check from silkaj.license import license_approval -from silkaj.network_tools import ClientInstance, send_document +from silkaj.network_tools import client_instance, send_document @click.command("cert", help="Send certification") @click.argument("uid_pubkey_to_certify") @click.pass_context def send_certification(ctx, uid_pubkey_to_certify): - client = ClientInstance().client + client = client_instance() checked_pubkey = is_pubkey_and_check(uid_pubkey_to_certify) if checked_pubkey: @@ -112,7 +112,7 @@ def certification_confirmation( ): cert = list() cert.append(["Cert", "Issuer", "–>", "Recipient: Published: #block-hash date"]) - client = ClientInstance().client + client = client_instance() idty_timestamp = idty_to_certify["meta"]["timestamp"] block_id_idty = get_block_id(idty_timestamp) block = client(bma.blockchain.block, block_id_idty.number) diff --git a/silkaj/commands.py b/silkaj/commands.py index 8b1973b5..72cad11b 100644 --- a/silkaj/commands.py +++ b/silkaj/commands.py @@ -26,7 +26,7 @@ from websocket._exceptions import WebSocketConnectionClosedException from silkaj.blockchain_tools import get_head_block from silkaj.constants import ALL, HOUR -from silkaj.network_tools import ClientInstance, determine_endpoint +from silkaj.network_tools import client_instance, determine_endpoint from silkaj.tools import get_currency_symbol from silkaj.wot_tools import identity_of @@ -83,7 +83,7 @@ def power(nbr, pow=0): help="Display the current Proof of Work difficulty level to generate the next block", ) def difficulties(): - client = ClientInstance().client + client = client_instance() try: ws = client(bma.ws.block) while True: @@ -129,7 +129,7 @@ def list_blocks(number, detailed): current_nbr = head_block["number"] if number == 0: number = head_block["issuersFrame"] - client = ClientInstance().client + client = client_instance() blocks = client(bma.blockchain.blocks, number, current_nbr - number + 1) issuers = list() issuers_dict = dict() diff --git a/silkaj/idty_tools.py b/silkaj/idty_tools.py index 137675f9..00031c89 100644 --- a/silkaj/idty_tools.py +++ b/silkaj/idty_tools.py @@ -26,7 +26,7 @@ from texttable import Texttable from silkaj import wot_tools as wt from silkaj.constants import ALL -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance from silkaj.tui import display_pubkey_and_checksum @@ -34,7 +34,7 @@ def display_identity(idty: Identity): """ Creates a table containing the identity infos """ - client = ClientInstance().client + client = client_instance() id_table = list() id_table.append(["Public key", display_pubkey_and_checksum(idty.pubkey)]) id_table.append(["User ID", idty.uid]) diff --git a/silkaj/membership.py b/silkaj/membership.py index da36ba96..e7ce01fe 100644 --- a/silkaj/membership.py +++ b/silkaj/membership.py @@ -26,7 +26,7 @@ from silkaj import auth, tui, wot from silkaj.blockchain_tools import get_blockchain_parameters, get_head_block from silkaj.constants import DATE, SUCCESS_EXIT_STATUS from silkaj.license import license_approval -from silkaj.network_tools import ClientInstance, send_document +from silkaj.network_tools import client_instance, send_document @click.command( @@ -54,7 +54,7 @@ def send_membership(ctx): license_approval(currency) # Confirmation - client = ClientInstance().client + client = client_instance() display_confirmation_table(identity_uid, key.pubkey, identity_block_id) if not dry_run and not ctx.obj["DISPLAY_DOCUMENT"]: tui.send_doc_confirmation("membership document for this identity") @@ -92,7 +92,7 @@ def display_confirmation_table(identity_uid, pubkey, identity_block_id): between two renewals is not awaited as for the certification """ - client = ClientInstance().client + client = client_instance() identities_requirements = client(bma.wot.requirements, pubkey) for identity_requirements in identities_requirements["identities"]: diff --git a/silkaj/money.py b/silkaj/money.py index b8316021..0bb9ca82 100644 --- a/silkaj/money.py +++ b/silkaj/money.py @@ -29,7 +29,7 @@ from silkaj.crypto_tools import ( is_pubkey_and_check, validate_checksum, ) -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance from silkaj.tools import get_currency_symbol from silkaj.tui import display_amount, display_pubkey_and_checksum @@ -132,7 +132,7 @@ def get_amount_from_pubkey(pubkey): def get_sources(pubkey): - client = ClientInstance().client + client = client_instance() # Sources written into the blockchain sources = client(tx.sources, pubkey) @@ -187,7 +187,7 @@ def get_sources(pubkey): @functools.lru_cache(maxsize=1) def get_ud_value(): - client = ClientInstance().client + client = client_instance() blockswithud = client(blockchain.ud) NBlastUDblock = blockswithud["result"]["blocks"][-1] lastUDblock = client(blockchain.block, NBlastUDblock) diff --git a/silkaj/network_tools.py b/silkaj/network_tools.py index 78ce9519..df951f9a 100644 --- a/silkaj/network_tools.py +++ b/silkaj/network_tools.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with Silkaj. If not, see <https://www.gnu.org/licenses/>. +import functools import re import sys import urllib @@ -24,17 +25,6 @@ from duniterpy.api.client import Client from silkaj import constants -def singleton(class_): - instances = {} - - def getinstance(*args, **kwargs): - if class_ not in instances: - instances[class_] = class_(*args, **kwargs) - return instances[class_] - - return getinstance - - def determine_endpoint(): """ Pass custom endpoint, parse through a regex @@ -77,14 +67,13 @@ Expected format: {host|ipv4|[ipv6]}:{port}{/path}" return ep.endpoint(constants.G1_DEFAULT_ENDPOINT) -@singleton -class ClientInstance: - def __init__(self): - self.client = Client(determine_endpoint()) +@functools.lru_cache(maxsize=1) +def client_instance(): + return Client(determine_endpoint()) def send_document(bma_path, document): - client = ClientInstance().client + client = client_instance() doc_name = document.__class__.__name__ try: client(bma_path, document.signed_raw()) diff --git a/silkaj/tx_history.py b/silkaj/tx_history.py index 5201ba60..238478bf 100644 --- a/silkaj/tx_history.py +++ b/silkaj/tx_history.py @@ -27,7 +27,7 @@ from silkaj import wot_tools as wt from silkaj.constants import ALL, ALL_DIGITAL from silkaj.crypto_tools import check_pubkey_format, validate_checksum from silkaj.money import amount_in_current_base, get_amount_from_pubkey, get_ud_value -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance from silkaj.tools import get_currency_symbol from silkaj.tui import display_pubkey_and_checksum @@ -40,7 +40,7 @@ def transaction_history(pubkey, uids, full_pubkey): if check_pubkey_format(pubkey): pubkey = validate_checksum(pubkey) - client = ClientInstance().client + client = client_instance() ud_value = get_ud_value() currency_symbol = get_currency_symbol() diff --git a/silkaj/wot.py b/silkaj/wot.py index 92377b42..b767619b 100644 --- a/silkaj/wot.py +++ b/silkaj/wot.py @@ -26,7 +26,7 @@ from silkaj import wot_tools as wt from silkaj.blockchain_tools import get_blockchain_parameters from silkaj.constants import DATE from silkaj.crypto_tools import is_pubkey_and_check -from silkaj.network_tools import ClientInstance, exit_on_http_error +from silkaj.network_tools import client_instance, exit_on_http_error from silkaj.tools import message_exit from silkaj.tui import display_pubkey_and_checksum @@ -56,7 +56,7 @@ def received_sent_certifications(uid_pubkey): get id of received and sent certifications display in a table the result with the numbers """ - client = ClientInstance().client + client = client_instance() first_block = client(blockchain.block, 1) time_first_block = first_block["time"] diff --git a/silkaj/wot_tools.py b/silkaj/wot_tools.py index dcc527b4..817e3a6f 100644 --- a/silkaj/wot_tools.py +++ b/silkaj/wot_tools.py @@ -17,7 +17,7 @@ import sys from duniterpy.api.bma import wot -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance def identity_of(pubkey_uid): @@ -26,7 +26,7 @@ def identity_of(pubkey_uid): Not able to get corresponding uid from a non-member identity Able to know if an identity is member or not """ - client = ClientInstance().client + client = client_instance() try: return client(wot.identity_of, pubkey_uid) except ValueError as e: @@ -50,7 +50,7 @@ def wot_lookup(identifier): Return received and sent certifications lists of matching identities if one identity found """ - client = ClientInstance().client + client = client_instance() return (client(wot.lookup, identifier))["results"] diff --git a/tests/test_membership.py b/tests/test_membership.py index e9f40700..d413c00b 100644 --- a/tests/test_membership.py +++ b/tests/test_membership.py @@ -39,7 +39,7 @@ from silkaj import auth, blockchain_tools, membership, wot from silkaj.blockchain_tools import get_blockchain_parameters from silkaj.cli import cli from silkaj.constants import DATE, FAILURE_EXIT_STATUS, SUCCESS_EXIT_STATUS -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance from silkaj.tui import display_pubkey_and_checksum # Values and patches @@ -135,7 +135,7 @@ def test_display_confirmation_table(patched_wot_requirements, monkeypatch, capsy monkeypatch.setattr(bma.blockchain, "parameters", patched_params) monkeypatch.setattr(bma.blockchain, "block", patched_block) - client = ClientInstance().client + client = client_instance() identities_requirements = client(bma.wot.requirements, pubkey) for identity_requirements in identities_requirements["identities"]: if identity_requirements["uid"] == identity_uid: diff --git a/tests/test_revocation.py b/tests/test_revocation.py index a520a475..223bdb05 100644 --- a/tests/test_revocation.py +++ b/tests/test_revocation.py @@ -24,7 +24,6 @@ import click import pytest from click.testing import CliRunner from duniterpy.api import bma -from duniterpy.api.client import Client from duniterpy.api.errors import DuniterError from duniterpy.documents.identity import Identity from duniterpy.documents.revocation import Revocation @@ -35,7 +34,7 @@ from patched.idty_tools import idty1, idty2, idty_block, lookup_one, lookup_two from silkaj import auth, blockchain_tools, idty_tools, revocation, wot from silkaj.cli import cli from silkaj.constants import FAILURE_EXIT_STATUS, SUCCESS_EXIT_STATUS -from silkaj.network_tools import ClientInstance +from silkaj.network_tools import client_instance from silkaj.tui import display_pubkey_and_checksum ### useful function ### @@ -694,7 +693,7 @@ def test_revocation_cli_publish( file = revocation.REVOCATION_LOCAL_PATH # test publication - client = ClientInstance().client + client = client_instance() runner = CliRunner() with runner.isolated_filesystem(): with open(file, "w") as f: @@ -778,7 +777,7 @@ def test_revocation_cli_publish_send_errors( file = revocation.REVOCATION_LOCAL_PATH # test publication - client = ClientInstance().client + client = client_instance() runner = CliRunner() with runner.isolated_filesystem(): with open(file, "w") as f: @@ -862,7 +861,7 @@ def test_revocation_cli_revoke( command = display_dry_options(display, dry_run) command.extend(["revocation", "revoke"]) - client = ClientInstance().client + client = client_instance() result = CliRunner().invoke(cli, args=command, input=user_input) for expect in expected: @@ -912,7 +911,7 @@ def test_revocation_cli_revoke_errors(display, user_input, doc, expected, monkey command = display_dry_options(display, False) command.extend(["revocation", "revoke"]) - client = ClientInstance().client + client = client_instance() result = CliRunner().invoke(cli, args=command, input=user_input) for expect in expected: diff --git a/tests/test_unit_tx.py b/tests/test_unit_tx.py index 2d3620e2..ced3d49d 100644 --- a/tests/test_unit_tx.py +++ b/tests/test_unit_tx.py @@ -1227,7 +1227,7 @@ def test_generate_and_send_transaction( # patched functions monkeypatch.setattr(blockchain_tools, "get_head_block", patched_get_head_block) - # monkeypatch.setattr(network_tools, "ClientInstance", patched_ClientInstance) + # monkeypatch.setattr(network_tools, "client_instance", patched_client_instance) tx.generate_and_send_transaction( key, diff --git a/tests/test_verify_blocks.py b/tests/test_verify_blocks.py index 4fe34a93..3d75c959 100644 --- a/tests/test_verify_blocks.py +++ b/tests/test_verify_blocks.py @@ -16,7 +16,6 @@ import pytest from click.testing import CliRunner from duniterpy.api import bma -from duniterpy.api.client import Client from duniterpy.documents import Block from silkaj import cli @@ -32,7 +31,7 @@ from silkaj.constants import ( FAILURE_EXIT_STATUS, SUCCESS_EXIT_STATUS, ) -from silkaj.network_tools import determine_endpoint +from silkaj.network_tools import client_instance G1_INVALID_BLOCK_SIG = 15144 HEAD_BLOCK = 48000 @@ -47,7 +46,7 @@ def current(self): ) def test_check_passed_blocks_range(from_block, to_block, capsys, monkeypatch): monkeypatch.setattr(bma.blockchain, "current", current) - client = Client(determine_endpoint) + client = client_instance() # https://medium.com/python-pandemonium/testing-sys-exit-with-pytest-10c6e5f7726f with pytest.raises(SystemExit) as pytest_wrapped_e: check_passed_blocks_range(client, from_block, to_block) @@ -104,7 +103,7 @@ def test_get_chunk_size(from_block, to_block, chunks_from, chunk_from): @pytest.mark.parametrize("chunk_size, chunk_from", [(2, 1), (5, 10)]) def test_get_chunks(chunk_size, chunk_from): - client = Client(determine_endpoint()) + client = client_instance() chunk = get_chunk(client, chunk_size, chunk_from) assert chunk[0]["number"] + chunk_size - 1 == chunk[-1]["number"] -- GitLab