settingsd is a drop-in replacement for a traditional settings.py
module. It allows settings to be logically
separated into different files, optionally from multiple paths, and reassembled in a predictable order. It's primary use
is enabling production/qa/staging code to run with alternate settings, in a consistent fashion, without introducing
additional overhead during development.
It helps to have a loose understanding of how python packages behave, as well as similar Unix concepts (/etc/sysctl.d
, /etc/pam.d
, etc), but is not necessary. Without delving into implementation details, settingsd aspires
to behave like this:
class ApplicationSettings(type.ModuleType):
__path__ = ['settings.d']
# settings.d/01-apple.py
APPLE_COLOR = 'red'
# settings.d/02-banana.py
BANANA_COLOR = 'yellow'
# settings.d/03-production.py
__path__.insert(0, '/production/settings.d')
# settings.d/04-orange.py (NOT LOADED!)
#ORANGE_COLOR = 'orange'
# /production/settings.d/04-orange.py
ORANGE_COLOR = 'purple'
# settings.d/05-tomato.py
if not TOMATO_COLOR:
# NameErrors transformed into None during assembly
TOMATO_COLOR = 'red'
sys.modules['application.settings'] = ApplicationSettings()
Per above, the flow is roughly:
- Use
__path__
to locate directories to scan - Identify all "modules" and sort by name
- Execute selected "modules" in the same primary namespace
- Convert said namespace to a new
type()
- Create one instance and install into
sys.modules
Setup settingsd from your __init__.py
:
import settingsd
settings = settingsd.install(__name__)
By default, if the enclosing module has a valid __file__
and one is not specified via keyword to install()
, settingsd will use that to compute a default search path. You may control the search path explicitly with:
settings = settingsd.install(__name__, __path__=['settings.d'])
Keywords passed to install()
simply seed the namespace.
settingsd allows you to import descriptors and anything else within part files:
from settingsd.extras.django import ConfigureApps
app = ConfigureApps()
ConfigureApps
is a property "activated" naturally when the namespace is converted to a class:
from application import settings
groups = settings.app.access.Group.objects.all()
Part files behave as if they were executed within a class definition so you are free to define settings-bound methods:
def echo(settings, *args, **kwds):
print((settings, args, kwds))
And the usercode:
from application import settings
groups = settings.echo('hello', who=me)
Special methods are no different:
from settingsd.extras.django import fallback_to_defaults as __getattr__
Usercode:
from application import settings
settings.SOME_DEFAULT_DJANGO_SETTING_YOU_DID_NOT_DEFINE_BUT_WILL_EXIST_ANYWAY