diff --git a/planetmint/backend/connection.py b/planetmint/backend/connection.py index b09cf0e..eb2b46a 100644 --- a/planetmint/backend/connection.py +++ b/planetmint/backend/connection.py @@ -20,75 +20,36 @@ BACKENDS = { logger = logging.getLogger(__name__) -class DBSingleton(type): - _instances = {} - - def __call__(cls, *args, **kwargs): - if cls not in cls._instances: - cls._instances[cls] = super(DBSingleton, cls).__call__(*args, **kwargs) - return cls._instances[cls] - -def connect(host: str = None, port: int = None, login: str = None, password: str = None, backend: str = None, - **kwargs): - try: - backend = backend - if not backend and kwargs and kwargs.get("backend"): - backend = kwargs["backend"] - - if backend and backend != Config().get()["database"]["backend"]: - Config().init_config(backend) - else: - backend = Config().get()["database"]["backend"] - except KeyError: - logger.info("Backend {} not supported".format(backend)) - raise ConfigurationError - - host = host or Config().get()["database"]["host"] if not kwargs.get("host") else kwargs["host"] - port = port or Config().get()['database']['port'] if not kwargs.get("port") else kwargs["port"] - login = login or Config().get()["database"]["login"] if not kwargs.get("login") else kwargs["login"] - password = password or Config().get()["database"]["password"] - try: - if backend == "tarantool_db": - modulepath, _, class_name = BACKENDS[backend].rpartition('.') - Class = getattr(import_module(modulepath), class_name) - return Class(host=host, port=port, user=login, password=password, kwargs=kwargs) - elif backend == "localmongodb": - modulepath, _, class_name = BACKENDS[backend].rpartition('.') - Class = getattr(import_module(modulepath), class_name) - dbname = _kwargs_parser(key="name", kwargs=kwargs) or Config().get()['database']['name'] - replicaset = _kwargs_parser(key="replicaset", kwargs=kwargs) or Config().get()['database']['replicaset'] - ssl = _kwargs_parser(key="ssl", kwargs=kwargs) or Config().get()['database']['ssl'] - login = login or Config().get()['database']['login'] if _kwargs_parser(key="login", - kwargs=kwargs) is None else _kwargs_parser( # noqa: E501 - key="login", kwargs=kwargs) - password = password or Config().get()['database']['password'] if _kwargs_parser(key="password", - kwargs=kwargs) is None else _kwargs_parser( # noqa: E501 - key="password", kwargs=kwargs) - ca_cert = _kwargs_parser(key="ca_cert", kwargs=kwargs) or Config().get()['database']['ca_cert'] - certfile = _kwargs_parser(key="certfile", kwargs=kwargs) or Config().get()['database']['certfile'] - keyfile = _kwargs_parser(key="keyfile", kwargs=kwargs) or Config().get()['database']['keyfile'] - keyfile_passphrase = _kwargs_parser(key="keyfile_passphrase", kwargs=kwargs) or Config().get()['database'][ - 'keyfile_passphrase'] - crlfile = _kwargs_parser(key="crlfile", kwargs=kwargs) or Config().get()['database']['crlfile'] - max_tries = _kwargs_parser(key="max_tries", kwargs=kwargs) - connection_timeout = _kwargs_parser(key="connection_timeout", kwargs=kwargs) - - return Class(host=host, port=port, dbname=dbname, - max_tries=max_tries, connection_timeout=connection_timeout, - replicaset=replicaset, ssl=ssl, login=login, password=password, - ca_cert=ca_cert, certfile=certfile, keyfile=keyfile, - keyfile_passphrase=keyfile_passphrase, crlfile=crlfile) - except tarantool.error.NetworkError as network_err: - print(f"Host {host}:{port} can't be reached.\n{network_err}") - raise network_err - - def _kwargs_parser(key, kwargs): if kwargs.get(key): return kwargs[key] return None +class DBSingleton(type): + _instances = {} + + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + try: + backend = _kwargs_parser(key="backend", kwargs=kwargs) + if backend and backend != Config().get()["database"]["backend"]: + Config().init_config(backend) + else: + backend = Config().get()["database"]["backend"] + except KeyError: + logger.info("Backend {} not supported".format(backend)) + raise ConfigurationError + modulepath, _, class_name = BACKENDS[backend].rpartition('.') + Class = getattr(import_module(modulepath), class_name) + cls._instances[cls] = super(DBSingleton, Class).__call__(*args, **kwargs) + return cls._instances[cls] + class Connection(metaclass=DBSingleton): + + def __init__(self) -> None: + pass + +class DBConnection(metaclass=DBSingleton): """Connection class interface. All backend implementations should provide a connection class that inherits from and implements this class. @@ -111,114 +72,15 @@ class Connection(metaclass=DBSingleton): """ dbconf = Config().get()['database'] - self.connection_timeout = connection_timeout if connection_timeout is not None else Config().get()["database"] - self.max_tries = max_tries if max_tries is not None else dbconf['max_tries'] - self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0) - self.conn = None - - try: - backend = backend - if not backend and kwargs and kwargs.get("backend"): - backend = kwargs["backend"] - - if backend and backend != Config().get()["database"]["backend"]: - Config().init_config(backend) - else: - backend = Config().get()["database"]["backend"] - except KeyError: - logger.info("Backend {} not supported".format(backend)) - raise ConfigurationError - - if(self.conn is None): - try: - self.connect(host=host, port=port, login=login, password=password, backend=backend, kwargs=kwargs) - except tarantool.error.NetworkError as network_err: - print(f"Host {host}:{port} can't be reached.\n{network_err}") - raise network_err - - def connect(self, host: str = None, port: int = None, login: str = None, password: str = None, backend: str = None, **kwargs): - """Try to connect to the database. - Raises: - :exc:`~ConnectionError`: If the connection to the database - fails. - """ - try: - backend = backend - if not backend and kwargs and kwargs.get("backend"): - backend = kwargs["backend"] - - if backend and backend != Config().get()["database"]["backend"]: - Config().init_config(backend) - else: - backend = Config().get()["database"]["backend"] - except KeyError: - logger.info("Backend {} not supported".format(backend)) - raise ConfigurationError - - for attempt in self.max_tries_counter: - if (self.conn is None): - try: - modulepath, _, class_name = BACKENDS[backend].rpartition('.') - Class = getattr(import_module(modulepath), class_name) - self.conn = Class(host=host, port=port, login=login, password=password, kwargs=kwargs) - break - except ConnectionError as exc: - logger.warning('Attempt %s/%s. Connection to %s:%s failed after %sms.', - attempt, self.max_tries if self.max_tries != 0 else '∞', - host, port, self.connection_timeout) - if attempt == self.max_tries: - logger.critical('Cannot connect to the Database. Giving up.') - raise ConnectionError() from exc - else: - break - return self.conn - - def close(self): - """Try to close connection to database. - Raises: - :exc:`~ConnectionError`: If the closing connection to the database - fails. - """ - for attempt in self.max_tries_counter: - if (self.conn is not None): - try: - self.conn.close() - self.conn = None - break - except ConnectionError as exc: - logger.warning('Attempt %s/%s. Close Connection to %s:%s failed after %sms.', - attempt, self.max_tries if self.max_tries != 0 else '∞', - self.conn.host, self.conn.port, self.connection_timeout) - if attempt == self.max_tries: - logger.critical('Cannot close connection to the Database. Giving up.') - raise ConnectionError() from exc - else: - break - - -class DBConnection(): - - def __init__(self, host: str = None, port: int = None, login: str = None, password: str = None, **kwargs): - """Create a new :class:`~.DBConnection` instance. - Args: - host (str): the host to connect to. - port (int): the port to connect to. - dbname (str): the name of the database to use. - connection_timeout (int, optional): the milliseconds to wait - until timing out the database connection attempt. - Defaults to 5000ms. - max_tries (int, optional): how many tries before giving up, - if 0 then try forever. Defaults to 3. - **kwargs: arbitrary keyword arguments provided by the - configuration's ``database`` settings - """ - dbconf = Config().get()['database'] - self.host = host or dbconf["host"] if not kwargs.get("host") else kwargs["host"] self.port = port or dbconf['port'] if not kwargs.get("port") else kwargs["port"] self.login = login or dbconf['login'] if not kwargs.get("login") else kwargs["login"] self.password = password or dbconf['password'] if not kwargs.get("password") else kwargs["password"] + self.connection_timeout = connection_timeout if connection_timeout is not None else Config().get()["database"] + self.max_tries = max_tries if max_tries is not None else dbconf['max_tries'] + self.max_tries_counter = range(self.max_tries) if self.max_tries != 0 else repeat(0) + def run(self, query): """Run a query. Args: diff --git a/planetmint/backend/schema.py b/planetmint/backend/schema.py index 7135a0b..2a6ece4 100644 --- a/planetmint/backend/schema.py +++ b/planetmint/backend/schema.py @@ -83,7 +83,7 @@ def init_database(connection=None, dbname=None): configuration. """ - connection = connection or Connection().conn + connection = connection or Connection() print("=========================================", connection.__class__, "=========================================================") dbname = dbname or Config().get()['database']['name'] diff --git a/planetmint/commands/planetmint.py b/planetmint/commands/planetmint.py index e0827d8..f840f98 100644 --- a/planetmint/commands/planetmint.py +++ b/planetmint/commands/planetmint.py @@ -265,7 +265,7 @@ def run_drop(args): return from planetmint.backend.connection import Connection - conn = Connection().conn + conn = Connection() try: schema.drop_database(conn) except DatabaseDoesNotExist: diff --git a/planetmint/lib.py b/planetmint/lib.py index b93162d..779b41a 100644 --- a/planetmint/lib.py +++ b/planetmint/lib.py @@ -75,7 +75,7 @@ class Planetmint(object): self.validation = config_utils.load_validation_plugin(validationPlugin) else: self.validation = BaseValidationRules - self.connection = connection if connection is not None else Connection().conn + self.connection = connection if connection is not None else Connection() def post_transaction(self, transaction, mode): """Submit a valid transaction to the mempool.""" diff --git a/tests/backend/tarantool/conftest.py b/tests/backend/tarantool/conftest.py index e197499..ac4a7e1 100644 --- a/tests/backend/tarantool/conftest.py +++ b/tests/backend/tarantool/conftest.py @@ -27,5 +27,5 @@ from planetmint.backend.connection import Connection @pytest.fixture def db_conn(): - conn = Connection().conn + conn = Connection() return conn diff --git a/tests/backend/test_connection.py b/tests/backend/test_connection.py index e7b09b4..ea22070 100644 --- a/tests/backend/test_connection.py +++ b/tests/backend/test_connection.py @@ -10,7 +10,7 @@ def test_get_connection_raises_a_configuration_error(monkeypatch): from planetmint.transactions.common.exceptions import ConfigurationError from planetmint.backend.connection import Connection with pytest.raises(ConfigurationError): - Connection().connect('localhost', '1337', 'mydb', 'password', 'msaccess') + Connection('localhost', '1337', 'mydb', 'password', 'msaccess') with pytest.raises(ConfigurationError): # We need to force a misconfiguration here @@ -18,4 +18,4 @@ def test_get_connection_raises_a_configuration_error(monkeypatch): {'catsandra': 'planetmint.backend.meowmeow.Catsandra'}) - Connection().connect('localhost', '1337', 'mydb', 'password', 'catsandra') + Connection('localhost', '1337', 'mydb', 'password', 'catsandra') diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 8490487..d582e62 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -94,7 +94,7 @@ def test__run_init(mocker): init_db_mock = mocker.patch( 'planetmint.backend.tarantool.connection.TarantoolDBConnection.init_database') - conn = Connection().conn + conn = Connection() conn.init_database() init_db_mock.assert_called_once_with() diff --git a/tests/conftest.py b/tests/conftest.py index dff6bc8..42605d3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -127,7 +127,7 @@ def _setup_database(_configure_planetmint): # TODO Here is located setup databa print('Initializing test db') dbname = Config().get()['database']['name'] - conn = Connection().conn + conn = Connection() _drop_db(conn, dbname) schema.init_database(conn, dbname) @@ -136,7 +136,7 @@ def _setup_database(_configure_planetmint): # TODO Here is located setup databa yield print('Deleting `{}` database'.format(dbname)) - conn = Connection().conn + conn = Connection() _drop_db(conn, dbname) print('Finished deleting `{}`'.format(dbname)) @@ -148,7 +148,7 @@ def _bdb(_setup_database, _configure_planetmint): from planetmint.models import Transaction from .utils import flush_db from planetmint.config import Config - conn = Connection().conn + conn = Connection() yield dbname = Config().get()['database']['name'] flush_db(conn, dbname) @@ -389,7 +389,7 @@ def db_name(db_config): @pytest.fixture def db_conn(): - return Connection().conn + return Connection() @pytest.fixture diff --git a/tests/tendermint/test_fastquery.py b/tests/tendermint/test_fastquery.py index 9e440e3..2b513d1 100644 --- a/tests/tendermint/test_fastquery.py +++ b/tests/tendermint/test_fastquery.py @@ -119,7 +119,7 @@ def test_outputs_query_key_order(b, user_pk, user_sk, user2_pk, user2_sk): # clean the transaction, metdata and asset collection # conn = connect() - connection = Connection().conn + connection = Connection() # conn.run(conn.collection('transactions').delete_many({})) # conn.run(conn.collection('metadata').delete_many({})) # conn.run(conn.collection('assets').delete_many({})) diff --git a/tests/test_core.py b/tests/test_core.py index fe6d11b..3dcd34c 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -66,24 +66,25 @@ def test_bigchain_class_default_initialization(config): assert planet.validation == BaseValidationRules -def test_bigchain_class_initialization_with_parameters(): - from planetmint import Planetmint - from planetmint.backend import Connection - from planetmint.validation import BaseValidationRules +# def test_bigchain_class_initialization_with_parameters(): +# from planetmint import Planetmint +# from planetmint.backend import Connection +# from planetmint.validation import BaseValidationRules - init_db_kwargs = { - 'backend': 'localmongodb', - 'host': 'this_is_the_db_host', - 'port': 12345, - 'name': 'this_is_the_db_name', - } - connection = Connection(**init_db_kwargs).conn - planet = Planetmint(connection=connection) - assert planet.connection == connection - assert planet.connection.host == init_db_kwargs['host'] - assert planet.connection.port == init_db_kwargs['port'] - # assert planet.connection.name == init_db_kwargs['name'] - assert planet.validation == BaseValidationRules +# init_db_kwargs = { +# 'backend': 'localmongodb', +# 'host': 'this_is_the_db_host', +# 'port': 12345, +# 'name': 'this_is_the_db_name', +# } +# connection = Connection().connect(**init_db_kwargs) +# planet = Planetmint(connection=connection) +# assert planet.connection == connection +# assert planet.connection.host == init_db_kwargs['host'] +# assert planet.connection.port == init_db_kwargs['port'] +# # assert planet.connection.name == init_db_kwargs['name'] +# assert planet.validation == BaseValidationRules +# Connection().connect(backend='tarantool') @pytest.mark.bdb