handle sqlalchemy NoSuchModuleError
This commit is contained in:
parent
3f5efef6e5
commit
d41f71bc34
@ -12,7 +12,8 @@ class DependencyException(BaseException):
|
||||
class OperationalException(BaseException):
|
||||
"""
|
||||
Requires manual intervention.
|
||||
This happens when an exchange returns an unexpected error during runtime.
|
||||
This happens when an exchange returns an unexpected error during runtime
|
||||
or given configuration is invalid.
|
||||
"""
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@ import logging
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from freqtrade import OperationalException
|
||||
from freqtrade.arguments import Arguments
|
||||
from freqtrade.configuration import Configuration
|
||||
from freqtrade.freqtradebot import FreqtradeBot
|
||||
@ -47,6 +48,9 @@ def main(sysargv: List[str]) -> None:
|
||||
except KeyboardInterrupt:
|
||||
logger.info('SIGINT received, aborting ...')
|
||||
return_code = 0
|
||||
except OperationalException as e:
|
||||
logger.error(str(e))
|
||||
return_code = 2
|
||||
except BaseException:
|
||||
logger.exception('Fatal exception!')
|
||||
finally:
|
||||
|
@ -11,11 +11,14 @@ import arrow
|
||||
from sqlalchemy import (Boolean, Column, DateTime, Float, Integer, String,
|
||||
create_engine)
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.exc import NoSuchModuleError
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm.scoping import scoped_session
|
||||
from sqlalchemy.orm.session import sessionmaker
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from freqtrade import OperationalException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_CONF = {}
|
||||
@ -43,7 +46,14 @@ def init(config: Dict) -> None:
|
||||
'echo': False,
|
||||
})
|
||||
|
||||
engine = create_engine(db_url, **kwargs)
|
||||
try:
|
||||
engine = create_engine(db_url, **kwargs)
|
||||
except NoSuchModuleError:
|
||||
error = 'Given value for db_url: \'{}\' is no valid database URL! (See {}).'.format(
|
||||
db_url, 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls'
|
||||
)
|
||||
raise OperationalException(error)
|
||||
|
||||
session = scoped_session(sessionmaker(bind=engine, autoflush=True, autocommit=True))
|
||||
Trade.session = session()
|
||||
Trade.query = session.query_property()
|
||||
|
@ -5,7 +5,7 @@ from unittest.mock import MagicMock
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from freqtrade import constants
|
||||
from freqtrade import constants, OperationalException
|
||||
from freqtrade.persistence import Trade, init, clean_dry_run_db
|
||||
|
||||
|
||||
@ -27,13 +27,24 @@ def test_init_custom_db_url(default_conf, mocker):
|
||||
conf = deepcopy(default_conf)
|
||||
|
||||
# Update path to a value other than default, but still in-memory
|
||||
conf.update({'db_url': 'sqlite:////tmp/freqtrade2_test.sqlite'})
|
||||
conf.update({'db_url': 'sqlite:///tmp/freqtrade2_test.sqlite'})
|
||||
create_engine_mock = mocker.patch('freqtrade.persistence.create_engine', MagicMock())
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
init(conf)
|
||||
assert create_engine_mock.call_count == 1
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:////tmp/freqtrade2_test.sqlite'
|
||||
assert create_engine_mock.mock_calls[0][1][0] == 'sqlite:///tmp/freqtrade2_test.sqlite'
|
||||
|
||||
|
||||
def test_init_invalid_db_url(default_conf, mocker):
|
||||
conf = deepcopy(default_conf)
|
||||
|
||||
# Update path to a value other than default, but still in-memory
|
||||
conf.update({'db_url': 'unknown:///some.url'})
|
||||
mocker.patch.dict('freqtrade.persistence._CONF', conf)
|
||||
|
||||
with pytest.raises(OperationalException, match=r'.*no valid database URL*'):
|
||||
init(conf)
|
||||
|
||||
|
||||
def test_init_prod_db(default_conf, mocker):
|
||||
|
Loading…
Reference in New Issue
Block a user