Changeset - a3c9fe09a78f
[Not reviewed]
0 4 0
Lance Edgar (lance) - 2 months ago 2024-08-15 10:57:01
lance@edbob.org
fix: let wuttjamaican configure app db engines
4 files changed with 85 insertions and 64 deletions:
0 comments (0 inline, 0 general)
rattail/config.py
Show inline comments
 
@@ -85,9 +85,12 @@ class RattailConfig(WuttaConfig):
 

	
 
    def __init__(self, *args, **kwargs):
 
        kwargs.setdefault('appname', 'rattail')
 
        defaults = kwargs.setdefault('defaults', {})
 
        super().__init__(*args, **kwargs)
 

	
 
        if hasattr(self, 'appdb_engine'):
 
            from rattail.db import Session
 
            Session.configure(bind=self.appdb_engine)
 

	
 
        # this is false, unless/until it becomes true
 
        self.versioning_has_been_enabled = False
 

	
rattail/db/__init__.py
Show inline comments
 
@@ -143,12 +143,13 @@ class ConfigExtension(BaseExtension):
 

	
 
        if Session:
 
            from rattail.db.config import configure_session
 
            from wuttjamaican.db import get_engines
 

	
 
            # Add Rattail database connection info to config.
 
            config.rattail_engines = get_engines(config, 'rattail.db')
 
            config.rattail_engine = config.rattail_engines.get('default')
 
            Session.configure(bind=config.rattail_engine, rattail_config=config)
 
            # TODO: deprecate / remove these
 
            config.rattail_engines = config.appdb_engines
 
            config.rattail_engine = config.appdb_engine
 

	
 
            # TODO: eventually this should not be needed (?)
 
            Session.configure(rattail_config=config)
 

	
 
            # TODO: This should be removed, it sets 'record changes' globally.
 
            configure_session(config, Session)
tests/db/test_init.py
Show inline comments
 
# -*- coding: utf-8; -*-
 

	
 
import os
 
import shutil
 
import tempfile
 
from unittest import TestCase
 

	
 
from rattail import db
 
from rattail.config import RattailConfig
 
from wuttjamaican.testing import FileConfigTestCase
 

	
 

	
 
class TestConfigExtension(TestCase):
 

	
 
    def setUp(self):
 
        self.tempdir = tempfile.mkdtemp()
 
class TestConfigExtension(FileConfigTestCase):
 

	
 
    def tearDown(self):
 
        if db.Session:
 
            db.Session.configure(bind=None, rattail_config=None)
 
        shutil.rmtree(self.tempdir)
 

	
 
    def write_file(self, fname, content):
 
        path = os.path.join(self.tempdir, fname)
 
        with open(path, 'wt') as f:
 
            f.write(content)
 
        return path
 
        self.teardown_files()
 

	
 
    def test_configure_empty(self):
 
        config = RattailConfig()
 
@@ -42,20 +31,29 @@ class TestConfigExtension(TestCase):
 

	
 
    def test_configure_connections(self):
 
        default_path = self.write_file('default.sqlite', '')
 
        default_url = 'sqlite:///{}'.format(default_path)
 
        default_url = f'sqlite:///{default_path}'
 
        host_path = self.write_file('host.sqlite', '')
 
        host_url = 'sqlite:///{}'.format(host_path)
 
        host_url = f'sqlite:///{host_path}'
 

	
 
        config = RattailConfig()
 
        config.setdefault('rattail.db', 'keys', 'default, host')
 
        config.setdefault('rattail.db', 'default.url', default_url)
 
        config.setdefault('rattail.db', 'host.url', host_url)
 
        db.ConfigExtension().configure(config)
 
        config = RattailConfig(defaults={
 
            'rattail.db.keys': 'default, host',
 
            'rattail.db.default.url': default_url,
 
            'rattail.db.host.url': host_url,
 
        })
 

	
 
        # nb. possibly running with 'nodb' scenario here
 
        ext = db.ConfigExtension()
 
        ext.configure(config)
 
        if db.Session:
 

	
 
            # ensure rattail_engines (deprecated)
 
            self.assertEqual(len(config.rattail_engines), 2)
 
            self.assertEqual(str(config.rattail_engines['default'].url), default_url)
 
            self.assertEqual(str(config.rattail_engines['host'].url), host_url)
 
            self.assertEqual(str(config.rattail_engine.url), default_url)
 
            session = db.Session()
 
            self.assertIs(session.bind, config.appdb_engine)
 
            self.assertIs(session.bind, config.rattail_engine)
 

	
 

	
 
try:
tests/test_config.py
Show inline comments
 
@@ -12,12 +12,31 @@ import pytest
 
from wuttjamaican.testing import FileConfigTestCase
 
from wuttjamaican.exc import ConfigurationError
 

	
 
from rattail import config
 
from rattail import config as mod, db
 
from rattail.app import AppHandler
 

	
 

	
 
class TestRattailConfig(FileConfigTestCase):
 

	
 
    def make_config(self, **kwargs):
 
        return mod.RattailConfig(**kwargs)
 

	
 
    def test_constructor(self):
 

	
 
        # no db by default
 
        config = self.make_config()
 
        if db.Session:
 
            session = db.Session()
 
            self.assertIsNone(session.bind)
 

	
 
        # default db
 
        config = self.make_config(defaults={
 
            'rattail.db.default.url': 'sqlite://',
 
        })
 
        if db.Session:
 
            session = db.Session()
 
            self.assertEqual(str(session.bind.url), 'sqlite://')
 

	
 
    def test_prioritized_files(self):
 
        first = self.write_file('first.conf', """\
 
[foo]
 
@@ -29,7 +48,7 @@ bar = 1
 
require = %(here)s/first.conf
 
""")
 

	
 
        myconfig = config.RattailConfig(files=[second])
 
        myconfig = self.make_config(files=[second])
 
        files = myconfig.prioritized_files
 
        self.assertEqual(len(files), 2)
 
        self.assertEqual(files[0], second)
 
@@ -42,13 +61,13 @@ require = %(here)s/first.conf
 
            pytest.skip("test is not relevant without sqlalchemy")
 

	
 
        # default func
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertEqual(myconfig.default_engine_maker_spec, 'rattail.db.config:make_engine_from_config')
 
        make_engine = myconfig.get_engine_maker()
 
        self.assertIs(make_engine, make_engine_from_config)
 

	
 
    def test_setdefault(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # nb. the tests below are effectively testing the custom get()
 
        # method in addition to setdefault()
 
@@ -75,7 +94,7 @@ require = %(here)s/first.conf
 
        self.assertRaises(ValueError, myconfig.get, 'foo', 'bar', 'blarg', 'blast')
 

	
 
    def test_get(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        myconfig.setdefault('foo.bar', 'baz')
 

	
 
        # can pass section + option
 
@@ -89,13 +108,13 @@ require = %(here)s/first.conf
 
        self.assertRaises(ValueError, myconfig.get)
 

	
 
    def test_getbool(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertFalse(myconfig.getbool('foo.bar'))
 
        myconfig.setdefault('foo.bar', 'true')
 
        self.assertTrue(myconfig.getbool('foo.bar'))
 

	
 
    def test_get_date(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertIsNone(myconfig.get_date('foo.date'))
 
        myconfig.setdefault('foo.date', '2023-11-20')
 
        value = myconfig.get_date('foo.date')
 
@@ -103,7 +122,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(value, datetime.date(2023, 11, 20))
 

	
 
    def test_getdate(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertIsNone(myconfig.getdate('foo.date'))
 
        myconfig.setdefault('foo.date', '2023-11-20')
 
        value = myconfig.getdate('foo.date')
 
@@ -111,29 +130,29 @@ require = %(here)s/first.conf
 
        self.assertEqual(value, datetime.date(2023, 11, 20))
 

	
 
    def test_getint(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertIsNone(myconfig.getint('foo.bar'))
 
        myconfig.setdefault('foo.bar', '42')
 
        self.assertEqual(myconfig.getint('foo.bar'), 42)
 

	
 
    def test_getlist(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertIsNone(myconfig.getlist('foo.bar'))
 
        myconfig.setdefault('foo.bar', 'hello world')
 
        self.assertEqual(myconfig.getlist('foo.bar'), ['hello', 'world'])
 

	
 
    def test_parse_bool(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertTrue(myconfig.parse_bool('true'))
 
        self.assertFalse(myconfig.parse_bool('false'))
 

	
 
    def test_parse_list(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        self.assertEqual(myconfig.parse_list(None), [])
 
        self.assertEqual(myconfig.parse_list('hello world'), ['hello', 'world'])
 

	
 
    def test_make_list_string(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        value = myconfig.make_list_string(['foo', 'bar'])
 
        self.assertEqual(value, 'foo, bar')
 
@@ -145,18 +164,18 @@ require = %(here)s/first.conf
 
        self.assertEqual(value, "\"you don't\", say")
 

	
 
    def test_get_app(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        app = myconfig.get_app()
 
        self.assertIsInstance(app, AppHandler)
 
        self.assertIs(type(app), AppHandler)
 

	
 
    def test_beaker_invalidate_setting(self):
 
        # TODO: this doesn't really test anything, just gives coverage
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        myconfig.beaker_invalidate_setting('foo')
 

	
 
    def test_node_type(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if node type not defined
 
        self.assertRaises(ConfigurationError, myconfig.node_type)
 
@@ -175,18 +194,18 @@ require = %(here)s/first.conf
 
            pytest.skip("test is not relevant without sqlalchemy")
 

	
 
        # default is rattail.db.model
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        model = myconfig.get_model()
 
        self.assertIs(model, sys.modules['rattail.db.model'])
 

	
 
        # or config may specify
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 
        myconfig.setdefault('rattail.model', 'rattail.trainwreck.db.model')
 
        model = myconfig.get_model()
 
        self.assertIs(model, sys.modules['rattail.trainwreck.db.model'])
 

	
 
    def test_get_enum(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # default is rattail.enum
 
        enum = myconfig.get_enum()
 
@@ -204,7 +223,7 @@ require = %(here)s/first.conf
 
        except ImportError:
 
            pytest.skip("test is not relevant without sqlalchemy")
 

	
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if not defined
 
        self.assertRaises(ConfigurationError, myconfig.get_trainwreck_model)
 
@@ -215,7 +234,7 @@ require = %(here)s/first.conf
 
        self.assertIs(model, sys.modules['rattail.trainwreck.db.model'])
 

	
 
    def test_versioning_enabled(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # false by default
 
        self.assertFalse(myconfig.versioning_enabled())
 
@@ -225,7 +244,7 @@ require = %(here)s/first.conf
 
        self.assertTrue(myconfig.versioning_enabled())
 

	
 
    def test_app_package(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if not defined
 
        self.assertRaises(ConfigurationError, myconfig.app_package)
 
@@ -238,7 +257,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.app_package(), 'bar')
 

	
 
    def test_app_title(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # default title
 
        self.assertEqual(myconfig.app_title(), 'Rattail')
 
@@ -248,7 +267,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.app_title(), 'Foo')
 

	
 
    def test_node_title(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # default title
 
        self.assertEqual(myconfig.app_title(), 'Rattail')
 
@@ -258,7 +277,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.node_title(), 'Foo (node)')
 

	
 
    def test_running_from_source(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # false by default
 
        self.assertFalse(myconfig.running_from_source())
 
@@ -268,7 +287,7 @@ require = %(here)s/first.conf
 
        self.assertTrue(myconfig.running_from_source())
 

	
 
    def test_demo(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # false by default
 
        self.assertFalse(myconfig.demo())
 
@@ -278,7 +297,7 @@ require = %(here)s/first.conf
 
        self.assertTrue(myconfig.demo())
 

	
 
    def test_appdir(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # can be none if required is false
 
        self.assertIsNone(myconfig.appdir(require=False))
 
@@ -294,7 +313,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.appdir(), '/foo/bar/baz')
 

	
 
    def test_datadir(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if not defined
 
        self.assertRaises(ConfigurationError, myconfig.datadir)
 
@@ -307,7 +326,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.datadir(), '/foo/bar/baz')
 

	
 
    def test_workdir(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if not defined
 
        self.assertRaises(ConfigurationError, myconfig.workdir)
 
@@ -320,7 +339,7 @@ require = %(here)s/first.conf
 
        self.assertEqual(myconfig.workdir(), '/foo/bar/baz')
 

	
 
    def test_batch_filedir(self):
 
        myconfig = config.RattailConfig()
 
        myconfig = self.make_config()
 

	
 
        # error if not defined
 
        self.assertRaises(ConfigurationError, myconfig.batch_filedir)
 
@@ -348,14 +367,14 @@ class TestRattailDefaultFiles(FileConfigTestCase):
 

	
 
                # generic files by default
 
                mockos.path.exists.return_value = False
 
                files = config.rattail_default_files('rattail')
 
                files = mod.rattail_default_files('rattail')
 
                generic_default_files.assert_called_once_with('rattail')
 
                self.assertEqual(files, [generic])
 

	
 
                # but if quiet.conf exists, will return that
 
                generic_default_files.reset_mock()
 
                mockos.path.exists.return_value = True
 
                files = config.rattail_default_files('rattail')
 
                files = mod.rattail_default_files('rattail')
 
                generic_default_files.assert_not_called()
 
                self.assertEqual(files, [quiet])
 

	
 
@@ -367,18 +386,18 @@ class TestMakeConfig(FileConfigTestCase):
 
        myfile = self.write_file('my.conf', '')
 

	
 
        # generic files by default
 
        myconfig = config.make_config(default_files=[generic])
 
        myconfig = mod.make_config(default_files=[generic])
 
        self.assertEqual(myconfig.files_read, [generic])
 

	
 
        # can specify single primary file
 
        myconfig = config.make_config(myfile, default_files=[generic])
 
        myconfig = mod.make_config(myfile, default_files=[generic])
 
        self.assertEqual(myconfig.files_read, [myfile])
 

	
 
        # can specify primary files as list
 
        myconfig = config.make_config([myfile], default_files=[generic])
 
        myconfig = mod.make_config([myfile], default_files=[generic])
 
        self.assertEqual(myconfig.files_read, [myfile])
 

	
 
        # can specify primary files via env
 
        myconfig = config.make_config(env={'RATTAIL_CONFIG_FILES': myfile},
 
                                      default_files=[generic])
 
        myconfig = mod.make_config(env={'RATTAIL_CONFIG_FILES': myfile},
 
                                   default_files=[generic])
 
        self.assertEqual(myconfig.files_read, [myfile])
0 comments (0 inline, 0 general)