Changeset - f32c9da676e1
[Not reviewed]
0 5 1
Lance Edgar (lance) - 4 months ago 2024-07-04 07:27:28
lance@edbob.org
fix: change how we override default app handler, engine maker

per upstream changes. this ensures we avoid the app handler when first
creating the engines, so that config extensions may override the
default app handler without being ignored.
6 files changed with 105 insertions and 86 deletions:
0 comments (0 inline, 0 general)
rattail/app.py
Show inline comments
 
@@ -1445,61 +1445,6 @@ class AppHandler(WuttaAppHandler):
 

	
 
        return prettify(field)
 

	
 
    def make_engine_from_config(
 
            self,
 
            config_dict,
 
            prefix='sqlalchemy.',
 
            **kwargs):
 
        """
 
        This is the same as
 
        :meth:`wuttjamaican:wuttjamaican.app.AppHandler.make_engine_from_config()`
 
        except Rattail may customize the engine a bit further:
 

	
 
        The engine can be told to "record changes" for sake of
 
        datasync; for instance:
 

	
 
        .. code-block:: ini
 

	
 
           [rattail.db]
 
           default.url = sqlite:///
 
           default.record_changes = true
 

	
 
        And/or the engine can be told to log its SQLAlchemy connection
 
        pool status:
 

	
 
        .. code-block:: ini
 

	
 
           [rattail.db]
 
           default.url = sqlite:///
 
           default.log_pool_status = true
 
        """
 
        config_dict = dict(config_dict)
 

	
 
        # stash flag for recording changes
 
        record_changes = False
 
        key = f'{prefix}record_changes'
 
        if key in config_dict:
 
            record_changes = self.config.parse_bool(config_dict.pop(key))
 

	
 
        # stash flag for logging db pool status
 
        log_pool_status = False
 
        key = f'{prefix}log_pool_status'
 
        if key in config_dict:
 
            log_pool_status = self.config.parse_bool(config_dict.pop(key))
 

	
 
        # make engine per usual
 
        engine = super().make_engine_from_config(config_dict,
 
                                                 prefix=prefix,
 
                                                 **kwargs)
 

	
 
        # then apply flags from stash
 
        if record_changes:
 
            engine.rattail_record_changes = True
 
        if log_pool_status:
 
            engine.rattail_log_pool_status = log_pool_status
 

	
 
        return engine
 

	
 
    def get_session(self, obj):
 
        """
 
        Returns the SQLAlchemy session with which the given object is
rattail/config.py
Show inline comments
 
@@ -80,11 +80,12 @@ class RattailConfig(WuttaConfig):
 
       been enabled for the running app.  This gets set when
 
       :func:`~rattail.db.config.configure_versioning()` happens.
 
    """
 
    default_app_handler_spec = 'rattail.app:AppHandler'
 
    default_engine_maker_spec = 'rattail.db.config:make_engine_from_config'
 

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

	
 
        # this is false, unless/until it becomes true
rattail/db/config.py
Show inline comments
 
@@ -27,6 +27,9 @@ Database Configuration
 
import logging
 
import warnings
 

	
 
from wuttjamaican.util import parse_bool
 
from wuttjamaican.db.conf import make_engine_from_config as wutta_make_engine_from_config
 

	
 
from rattail.exceptions import SQLAlchemyNotInstalled
 

	
 

	
 
@@ -101,3 +104,56 @@ def configure_versioning(config, force=False, manager=None, plugins=None, **kwar
 
            raise RuntimeError("Versioning is enabled and configured, but is not functional!  "
 
                               "This probably means the code import sequence is faulty somehow.  "
 
                               "Please investigate ASAP.")
 

	
 

	
 
def make_engine_from_config(
 
        config_dict,
 
        prefix='sqlalchemy.',
 
        **kwargs):
 
    """
 
    This is the same as
 
    :func:`wuttjamaican:wuttjamaican.db.conf.make_engine_from_config()`
 
    except Rattail may customize the engine a bit further:
 

	
 
    The engine can be told to "record changes" for sake of
 
    datasync; for instance:
 

	
 
    .. code-block:: ini
 

	
 
       [rattail.db]
 
       default.url = sqlite:///
 
       default.record_changes = true
 

	
 
    And/or the engine can be told to log its SQLAlchemy connection
 
    pool status:
 

	
 
    .. code-block:: ini
 

	
 
       [rattail.db]
 
       default.url = sqlite:///
 
       default.log_pool_status = true
 
    """
 
    config_dict = dict(config_dict)
 

	
 
    # stash flag for recording changes
 
    record_changes = False
 
    key = f'{prefix}record_changes'
 
    if key in config_dict:
 
        record_changes = parse_bool(config_dict.pop(key))
 

	
 
    # stash flag for logging db pool status
 
    log_pool_status = False
 
    key = f'{prefix}log_pool_status'
 
    if key in config_dict:
 
        log_pool_status = parse_bool(config_dict.pop(key))
 

	
 
    # make engine per usual
 
    engine = wutta_make_engine_from_config(config_dict, prefix=prefix, **kwargs)
 

	
 
    # then apply flags from stash
 
    if record_changes:
 
        engine.rattail_record_changes = True
 
    if log_pool_status:
 
        engine.rattail_log_pool_status = log_pool_status
 

	
 
    return engine
tests/db/test_config.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8; -*-
 

	
 
from unittest import TestCase
 

	
 
from rattail.db import config as conf
 

	
 

	
 
class TestMakeEngineFromConfig(TestCase):
 

	
 
    def test_record_changes(self):
 

	
 
        # no attribute is set by default
 
        engine = conf.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
        })
 
        self.assertRaises(AttributeError, getattr, engine, 'rattail_record_changes')
 

	
 
        # but if flag is true, attr is set
 
        engine = conf.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
            'sqlalchemy.record_changes': 'true'
 
        })
 
        self.assertTrue(engine.rattail_record_changes)
 

	
 
    def test_log_pool_status(self):
 

	
 
        # no attribute is set by default
 
        engine = conf.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
        })
 
        self.assertRaises(AttributeError, getattr, engine, 'rattail_log_pool_status')
 

	
 
        # but if flag is true, attr is set
 
        engine = conf.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
            'sqlalchemy.log_pool_status': 'true'
 
        })
 
        self.assertTrue(engine.rattail_log_pool_status)
tests/test_app.py
Show inline comments
 
@@ -69,36 +69,6 @@ class TestAppHandler(TestCase):
 
        self.assertEqual(self.app.get_title(), "Bar")
 
        self.assertEqual(self.app.get_title(default="Foo"), "Bar")
 

	
 
    def test_make_engine_from_config_record_changes(self):
 

	
 
        # no attribute is set by default
 
        engine = self.app.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
        })
 
        self.assertRaises(AttributeError, getattr, engine, 'rattail_record_changes')
 

	
 
        # but if flag is true, attr is set
 
        engine = self.app.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
            'sqlalchemy.record_changes': 'true'
 
        })
 
        self.assertTrue(engine.rattail_record_changes)
 

	
 
    def test_make_engine_from_config_log_pool_status(self):
 

	
 
        # no attribute is set by default
 
        engine = self.app.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
        })
 
        self.assertRaises(AttributeError, getattr, engine, 'rattail_log_pool_status')
 

	
 
        # but if flag is true, attr is set
 
        engine = self.app.make_engine_from_config({
 
            'sqlalchemy.url': 'sqlite://',
 
            'sqlalchemy.log_pool_status': 'true'
 
        })
 
        self.assertTrue(engine.rattail_log_pool_status)
 

	
 
    def test_get_timezone(self):
 

	
 
        # unconfigured zone causes error
tests/test_config.py
Show inline comments
 
@@ -12,6 +12,7 @@ from wuttjamaican.exc import ConfigurationError
 

	
 
from rattail import config
 
from rattail.app import AppHandler
 
from rattail.db.config import make_engine_from_config
 

	
 

	
 
class TestRattailConfig(FileConfigTestCase):
 
@@ -33,6 +34,14 @@ require = %(here)s/first.conf
 
        self.assertEqual(files[0], second)
 
        self.assertEqual(files[1], first)
 

	
 
    def test_get_engine_maker(self):
 

	
 
        # default func
 
        myconfig = config.RattailConfig()
 
        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()
 

	
0 comments (0 inline, 0 general)