commit ec9f3f61aacac58352b011d1a288741d86eb9489
Author: nolash <dev@holbrook.no>
Date: Tue, 18 Aug 2020 10:46:41 +0200
Initial commit
Diffstat:
6 files changed, 227 insertions(+), 0 deletions(-)
diff --git a/confini/__init__.py b/confini/__init__.py
@@ -0,0 +1,15 @@
+from confini.config import Config, set_current, config_from_environment
+
+
+# TODO workaround for global sempo code smell, can't get around it unless manipulate attributes in the package itself
+#SENTRY_SERVER_DSN = None
+#ETH_CHAIN_ID = 42
+#ETH_GAS_PRICE = 1000000000
+#ETH_GAS_LIMIT = 60000
+#ETH_CHECK_TRANSACTION_RETRIES = 0
+#ETH_CHECK_TRANSACTION_RETRIES_TIME_LIMIT = 0
+#ETH_CHECK_TRANSACTION_BASE_TIME = 0
+#REDIS_URL = 'redis://'
+#ETH_HTTP_PROVIDER = 'http://localhost:8545'
+#ETH_DATABASE_URI = 'postgresql://postgres:postgres@localhost:8545/eth_worker'
+#SYNCRONOUS_TASK_TIMEOUT = 1
diff --git a/confini/config.py b/confini/config.py
@@ -0,0 +1,141 @@
+#!/usr/bin/python
+
+import logging
+import sys
+import os
+import tempfile
+import configparser
+
+logg = logging.getLogger()
+
+current_config = None
+
+
+def set_current(conf, description=''):
+ global current_config
+ logg.debug('setting current config ({})'.format(description))
+ current_config = conf
+
+
+class Config:
+
+ parser = configparser.ConfigParser(strict=True)
+
+ def __init__(self, config_dir):
+ if not os.path.isdir(config_dir):
+ raise OSError('{} is not a directory'.format(config_dir))
+ self.dir = os.path.realpath(config_dir)
+ self.required = {}
+ self.censored = {}
+ self.store = {}
+
+
+ def add(self, value, constant_name):
+ self.store[constant_name] = value
+
+
+ def censor(self, identifier, section=None):
+ constant_name = ''
+ if section != None:
+ constant_name = Config.to_constant_name(identifier, section)
+ else:
+ constant_name = identifier
+ self.censored[constant_name] = True
+
+
+ def require(self, directive, section):
+ if self.required.get(section) == None:
+ self.required[section] = []
+ self.required[section].append(directive)
+
+
+ def validate(self):
+ for k in self.required.keys():
+ for v in self.required[k]:
+ try:
+ _ = self.parser[k][v]
+ except:
+ return False
+ return True
+
+
+ @staticmethod
+ def to_constant_name(directive, section):
+ return '{}_{}'.format(section.upper(), directive.upper())
+
+
+ def _process_env(self):
+ for s in self.parser.sections():
+ for k in self.parser[s]:
+ cn = Config.to_constant_name(k, s)
+ self.add(os.environ.get(cn, self.parser[s][k]), cn)
+
+
+ def process(self, set_as_current=False):
+ """Concatenates all .ini files in the config directory attribute and parses them to memory
+ """
+ tmp = tempfile.NamedTemporaryFile(delete=False)
+ tmpname = tmp.name
+ for filename in os.listdir(self.dir):
+ if not '.ini' in filename:
+ continue
+ f = open(os.path.join(self.dir, filename), 'rb')
+ while 1:
+ data = f.read()
+ if not data:
+ break
+ tmp.write(data)
+ f.close()
+ tmp.close()
+ self.parser.read(tmpname)
+ os.unlink(tmpname)
+ self._process_env()
+ if set_as_current:
+ set_current(self, description=self.dir)
+
+
+ def get(self, k):
+ return self.store.get(k)
+
+
+ def __str__(self):
+ ls = []
+ for k in self.store.keys():
+ v = ''
+ try:
+ _ = self.censored[k]
+ v = '***'
+ except:
+ v = self.store[k]
+
+ ls.append('{} = {}'.format(k, v))
+
+ return '\n'.join(ls)
+
+
+ def __repr__(self):
+ return "<Config '{}'>".format(self.dir)
+
+
+
+def config_from_environment():
+ config_dir = config_dir_from_environment()
+ c = Config(config_dir)
+ c.process()
+ return c
+
+
+def config_dir_from_environment():
+ return os.environ.get('CIC_CONFIG_DIR')
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ sys.stderr.write('usage: config.py <config_dir>')
+ sys.exit(1)
+ c = Config(sys.argv[1])
+ c.process()
+ print(repr(c))
+ print(c)
+
+
diff --git a/setup.py b/setup.py
@@ -0,0 +1,17 @@
+from setuptools import setup
+
+setup(
+ name='confini',
+ version='0.0.1',
+ description='Parse, verify and merge all ini files in a single directory',
+ author='Louis Holbrook',
+ author_email='dev@holbrook.no',
+ packages=[
+ 'confini',
+ ],
+ scripts = [
+ 'scripts/parse.py',
+ ],
+ data_files = [('', ['LICENSE.txt'])],
+ url='https://holbrook.no',
+ )
diff --git a/test/files/bar.ini b/test/files/bar.ini
@@ -0,0 +1,5 @@
+[BAR]
+foo = oof
+
+[XYZZY]
+bert = ernie
diff --git a/test/files/foo.ini b/test/files/foo.ini
@@ -0,0 +1,3 @@
+[FOO]
+bar = 42
+baz = 029a
diff --git a/test/test_basic.py b/test/test_basic.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+
+import os
+import unittest
+import logging
+
+from confini import Config
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+class TestBasic(unittest.TestCase):
+
+ wd = os.path.dirname(__file__)
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_parse_two_files(self):
+ inidir = os.path.join(self.wd, 'files')
+ c = Config(inidir)
+ c.process()
+ c.require('BERT', 'XYZZY')
+ expect = {
+ 'FOO_BAR': '42',
+ 'FOO_BAZ': '029a',
+ 'BAR_FOO': 'oof',
+ 'XYZZY_BERT': 'ernie',
+ }
+ self.assertDictEqual(expect, c.store)
+
+
+ def test_require(self):
+ inidir = os.path.join(self.wd, 'files')
+ c = Config(inidir)
+ c.require('BERT', 'XYZZY')
+ self.assertTrue(c.validate())
+ c.require('ERNIE', 'XYZZY')
+ self.assertFalse(c.validate())
+ logg.debug(c)
+
+if __name__ == '__main__':
+ unittest.main()