Last active
August 1, 2020 22:16
-
-
Save glenfant/90004df7b2734c20b5741983d93745c4 to your computer and use it in GitHub Desktop.
How to provide a default configuration which individual points may be overriden in a custom configuration file (to improve and explain)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
================ | |
euscans.settings | |
================ | |
Provides settings customization and public configuration object | |
[DEPRECATED] I released the ``pyflexconfig`` package on PyPI that rationalizes and improves this boilerplate. | |
https://pypi.org/project/pyflexconfig/ | |
""" | |
from argparse import Namespace | |
import logging.config | |
import os | |
from euscans import LOG | |
from .utils import execfile, CommandBase | |
this_directory = os.path.dirname(os.path.abspath(__file__)) | |
default_settings_file = os.path.join(this_directory, 'defaultsettings.py') | |
assert os.path.isfile(default_settings_file), "Broken package: File '{}' is missing".format(default_settings_file) | |
def get_config(*files): | |
"""Provides a :class:`argparse.Namespace` configuration object that merges | |
all uppercase globals in Python ``files`` that don't start with '_' | |
Note: | |
Values from a file override values of same name provided by a previous file. | |
Args: | |
files (Iterable(str)): Paths to all config files | |
Returns: | |
argparse.Namespace: Merged configuration data | |
Examples: | |
Preparation | |
>>> import os, tempfile | |
>>> CONFIG1 = '''DATA1 = 10 | |
... ignored = 100 | |
... _IGNORED = 1000''' | |
>>> CONFIG2 = '''DATA1 = 100 | |
... EXTRA = 100''' | |
>>> config1, path_config1 = tempfile.mkstemp('.py') | |
>>> with os.fdopen(config1, 'w') as config1: | |
... _ = config1.write(CONFIG1) | |
>>> config2, path_config2 = tempfile.mkstemp('.py') | |
>>> with os.fdopen(config2, 'w') as config2: | |
... _ = config2.write(CONFIG2) | |
Make the conf. | |
>>> conf = get_config(path_config1, path_config2) | |
>>> conf.DATA1 | |
100 | |
>>> conf.EXTRA | |
100 | |
>>> hasattr(conf, 'ignored') | |
False | |
>>> hasattr(conf, '_IGNORED') | |
False | |
Cleaning... | |
>>> os.unlink(path_config1) | |
>>> os.unlink(path_config2) | |
""" | |
conf_globals = {} | |
conf_locals = {} | |
for file_ in files: | |
execfile(file_, conf_globals, conf_locals) | |
conf_locals = {name: value for name, value in conf_locals.items() | |
if name.isupper() and not name.startswith('_')} | |
return Namespace(**conf_locals) | |
conf = None | |
def bootstrap(): | |
"""Bootstraps the global ``conf`` object | |
""" | |
global conf | |
# One shot function in process | |
if conf is not None: | |
return | |
is_file = os.path.isfile | |
# Standard settings | |
settings_files = (default_settings_file,) | |
# Custom settings | |
custom_settings_file = os.environ.get('EUSCANS_CONFIG_FILE') | |
if custom_settings_file is not None: | |
assert is_file(custom_settings_file), "Custom settings file '{}' does not exist".format(custom_settings_file) | |
settings_files += (custom_settings_file,) | |
LOG.debug("Reading the settings from %s", settings_files) | |
conf = get_config(*settings_files) | |
logging.config.dictConfig(conf.LOGGING) | |
return | |
class DumpConfigCommand(CommandBase): | |
name = 'dumpsettings' | |
help = "Prints the default settings to stdout. Which may be edited to make your custom settings" | |
def run(self, args, extra_args): | |
with open(default_settings_file, 'r') as fh: | |
for line in fh: | |
stripped = line.strip() | |
if stripped.startswith('#') or len(stripped) == 0: | |
print(line, end='') | |
else: | |
print('#'+line, end='') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment