Commit 9a2e25c3 by John Eskew

Add derived/derived_dict_entry/derive_settings and tests.

- Enables a method of deriving Django settings from other Django
  settings after all other Django settings are stable.
parent 9c85fcad
"""
Allows the registration of Django/Python settings that are derived from other settings
via callable methods/lambdas. The derivation time can be controlled to happen after all
other settings have been set. The derived setting can also be overridden by setting the
derived setting to an actual value.
"""
import six
import sys
# Global list holding all settings which will be derived.
__DERIVED = []
def derived(*settings):
"""
Registers settings which are derived from other settings.
Can be called multiple times to add more derived settings.
Args:
settings (list): List of setting names to register.
"""
__DERIVED.extend(settings)
def derived_dict_entry(setting_dict, key):
"""
Registers a setting which is a dictionary and needs a derived value for a particular key.
Can be called multiple times to add more derived settings.
Args:
setting_dict (str): Name of setting which contains a dictionary.
key (str): Name of key in the setting dictionary which will be derived.
"""
__DERIVED.append((setting_dict, key))
def derive_settings(module_name):
"""
Derives all registered settings and sets them onto a particular module.
Skips deriving settings that are set to a value.
Args:
module_name (str): Name of module to which the derived settings will be added.
"""
module = sys.modules[module_name]
for derived in __DERIVED:
if isinstance(derived, six.string_types):
setting = getattr(module, derived)
if callable(setting):
setting_val = setting(module)
setattr(module, derived, setting_val)
elif isinstance(derived, tuple):
# If a tuple, two elements are expected - else ignore.
if len(derived) == 2:
# Both elements are expected to be strings.
# The first string is the attribute which is expected to be a dictionary.
# The second string is a key in that dictionary containing a derived setting.
setting = getattr(module, derived[0])[derived[1]]
if callable(setting):
setting_val = setting(module)
getattr(module, derived[0]).update({derived[1]: setting_val})
def clear_for_tests():
"""
Clears all settings to be derived. For tests only.
"""
global __DERIVED
__DERIVED = []
"""
Tests for derived.py
"""
import sys
from unittest import TestCase
from openedx.core.lib.derived import derived, derive_settings, clear_for_tests
class TestDerivedSettings(TestCase):
"""
Test settings that are derived from other settings.
"""
def setUp(self):
super(TestDerivedSettings, self).setUp()
clear_for_tests()
self.module = sys.modules[__name__]
self.module.SIMPLE_VALUE = 'paneer'
self.module.DERIVED_VALUE = lambda settings: 'mutter ' + settings.SIMPLE_VALUE
self.module.ANOTHER_DERIVED_VALUE = lambda settings: settings.DERIVED_VALUE + ' with naan'
self.module.UNREGISTERED_DERIVED_VALUE = lambda settings: settings.SIMPLE_VALUE + ' is cheese'
derived('DERIVED_VALUE', 'ANOTHER_DERIVED_VALUE')
self.module.DICT_VALUE = {}
self.module.DICT_VALUE['test_key'] = lambda settings: settings.DERIVED_VALUE * 3
derived(('DICT_VALUE', 'test_key'))
def test_derived_settings_are_derived(self):
derive_settings(__name__)
self.assertEqual(self.module.DERIVED_VALUE, 'mutter paneer')
self.assertEqual(self.module.ANOTHER_DERIVED_VALUE, 'mutter paneer with naan')
def test_unregistered_derived_settings(self):
derive_settings(__name__)
self.assertTrue(callable(self.module.UNREGISTERED_DERIVED_VALUE))
def test_derived_settings_overridden(self):
self.module.DERIVED_VALUE = 'aloo gobi'
derive_settings(__name__)
self.assertEqual(self.module.DERIVED_VALUE, 'aloo gobi')
self.assertEqual(self.module.ANOTHER_DERIVED_VALUE, 'aloo gobi with naan')
def test_derived_dict_settings(self):
derive_settings(__name__)
self.assertEqual(self.module.DICT_VALUE['test_key'], 'mutter paneermutter paneermutter paneer')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment