confini

Parse and merge multiple ini files in python3
git clone git://git.defalsify.org/python-confini.git
Log | Files | Refs | README | LICENSE

commit a3ffb115308a21c423b32cfd47456d417aede3a4
parent 91e5da36959712f9f1de3fda4ca5474d80eb1756
Author: nolash <dev@holbrook.no>
Date:   Mon, 12 Jul 2021 09:38:14 +0200

Add missing test files and pgp crypt files

Diffstat:
A.gitignore | 6++++++
Aconfini/crypt/pgp.py | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Arun_tests.sh | 10++++++++++
Msetup.py | 1+
Atests/files/bar.ini | 5+++++
Atests/files/crypt/baz.asc | 14++++++++++++++
Atests/files/crypt/foo.ini | 4++++
Atests/files/default/foo.ini | 3+++
Atests/files/foo.ini | 3+++
Atests/files/multi/one/bar.ini | 2++
Atests/files/multi/one/foo.ini | 4++++
Atests/files/multi/three/foo.ini | 5+++++
Atests/files/multi/two/bar.ini | 2++
Atests/files/multi/two/foo.ini | 4++++
Atests/files/translate/foo.ini | 10++++++++++
Atests/test_basic.py | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/test_enc.py | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/test_env.py | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/test_multi.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/test_translate.py | 49+++++++++++++++++++++++++++++++++++++++++++++++++
20 files changed, 460 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,6 @@ +build/ +*.egg-info/ +dist/ +__pycache__ +*.pyc +gmon.out diff --git a/confini/crypt/pgp.py b/confini/crypt/pgp.py @@ -0,0 +1,53 @@ +# standard imports +import logging +import re +import os + +# external imports +import gnupg + +# local imports +from confini.error import DecryptError + + +logg = logging.getLogger(__name__) + +gpg = gnupg.GPG( + verbose=False, + use_agent=True, + ) +gpg.encoding = 'utf-8' + + + +class PGPDecrypter: + + def __init__(self, base_dir='.'): + self.base_dir = base_dir + + + def decrypt(self, k, v, src_dir=None): + if src_dir == None: + src_dir = self.base_dir + + if type(v).__name__ != 'str': + logg.debug('entry {} is not type str'.format(k)) + return (v, False) + + m = re.match(r'^\!gpg\((.*)\)', v) + if m != None: + filename = m.group(1) + if filename[0] != '/': + filename = os.path.join(src_dir, filename) + f = open(filename, 'rb') + logg.debug('decrypting entry {} in file {}'.format(k, f)) + d = gpg.decrypt_file(f) + if not d.ok: + raise DecryptError() + v = str(d) + f.close() + + return (v, m != None) + + def __str__(self): + return 'gpg decrypter' diff --git a/run_tests.sh b/run_tests.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e +set -x +export PYTHONPATH=$PYTHONPATH:. +for f in `ls tests/*.py`; do + python $f +done +set +x +set +e diff --git a/setup.py b/setup.py @@ -19,6 +19,7 @@ setup( packages=[ 'confini', 'confini.runnable', + 'confini.crypt', ], url='https://gitlab.com/nolash/python-confini', ) diff --git a/tests/files/bar.ini b/tests/files/bar.ini @@ -0,0 +1,5 @@ +[BAR] +foo = oof + +[XYZZY] +bert = ernie diff --git a/tests/files/crypt/baz.asc b/tests/files/crypt/baz.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP MESSAGE----- + +hQGMA8Ll7MXhlLGLAQv/Skj9eYN9MuR2JLIFJ7V2BYgpdakukamW6dCEwr1dyWbq +Uj0UurqSCJBg3qvDQvK2K/UU1ez2+Sot8i/rQY5Q7t9Daxlzp4PombtYw0R3dxLE +bcNCEv7tIr1VjW8cRvkgKc9CamcI2zcUDt2DGq+c9w8Hxn+N7KRF1ZZLGvb7nnTU +ugMyrQb8ILJDyw7ifjgjQFSeh5Kfg+tQAKaPTk7ydCqCXaODd1dCNE1IK/ebl8kT +gGm0db20lcNG9MOmmumD22hTovlouv1WcybpQGzNsogkiJxMRgCQ2DRRAxWOLyam +71iEcCb3w/xf+YISUSWkD+H1W0+2i0X6RTIVNYs/tEnI9/DypKV4wPWcsWbLsVqO +u8wodH5Kk3f/gwVd90wjmpYMrRCIL0/GOfMn8IglN58lOMEtopRtll/CbM8XcRUc +5vsCIcrBiZiwq6bfQxyPSVmpOsxz24BMvU537bVf5qI7KpFn5L5Gjo/Sy1Xq4rpT +avEBM1lXrRbEqXz/fd2J0j4BInKLK3yaAkBq0pFYvCFsHOB/7n0SUkOZcFBXxGGb +sDj+VuQr5hdhJbgyl0ZhsUvHaJQzKFn2N4cW8RQwmw== +=qkyQ +-----END PGP MESSAGE----- diff --git a/tests/files/crypt/foo.ini b/tests/files/crypt/foo.ini @@ -0,0 +1,4 @@ +[FOO] +bar = 42 +baz = !gpg(baz.asc) +xyzzy = diff --git a/tests/files/default/foo.ini b/tests/files/default/foo.ini @@ -0,0 +1,3 @@ +[FOO] +bar = xyzzy +baz = diff --git a/tests/files/foo.ini b/tests/files/foo.ini @@ -0,0 +1,3 @@ +[FOO] +bar = 42 +baz = 029a diff --git a/tests/files/multi/one/bar.ini b/tests/files/multi/one/bar.ini @@ -0,0 +1,2 @@ +[bar] +one = two diff --git a/tests/files/multi/one/foo.ini b/tests/files/multi/one/foo.ini @@ -0,0 +1,4 @@ +[FOO] +bar = xyzzy +baz = +bah = diff --git a/tests/files/multi/three/foo.ini b/tests/files/multi/three/foo.ini @@ -0,0 +1,5 @@ +[FOO] +bar = plugh +baz = 42 +bah = +mah = nah diff --git a/tests/files/multi/two/bar.ini b/tests/files/multi/two/bar.ini @@ -0,0 +1,2 @@ +[bar] +one = three diff --git a/tests/files/multi/two/foo.ini b/tests/files/multi/two/foo.ini @@ -0,0 +1,4 @@ +[FOO] +bar = plugh +baz = 42 +bah = diff --git a/tests/files/translate/foo.ini b/tests/files/translate/foo.ini @@ -0,0 +1,10 @@ +[true] +a = true +b = True +c = 1 + +[false] +a = false +b = False +c = 0 +d = diff --git a/tests/test_basic.py b/tests/test_basic.py @@ -0,0 +1,95 @@ +#!/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_default(self): + inidir = os.path.join(self.wd, 'files/default') + c = Config(inidir) + c.process() + r = c.get('FOO_BAR', 'plugh') + self.assertEqual(r, 'xyzzy') + r = c.get('FOO_BAZ', 'plugh') + self.assertEqual(r, 'plugh') + r = c.get('FOO_BAZ') + self.assertEqual(r, None) + with self.assertRaises(KeyError): + r = c.get('FOO_BAZBAZ') + + + def test_parse_two(self): + inidir = os.path.join(self.wd, 'files/default') + c = Config(inidir, override_dirs=[inidir]) + c.process() + r = c.get('FOO_BAR', 'plugh') + self.assertEqual(r, 'xyzzy') + r = c.get('FOO_BAZ', 'plugh') + self.assertEqual(r, 'plugh') + r = c.get('FOO_BAZ') + self.assertEqual(r, None) + with self.assertRaises(KeyError): + r = c.get('FOO_BAZBAZ') + + + def test_overwrite_guard(self): + inidir = os.path.join(self.wd, 'files/default') + c = Config(inidir) + c.process() + with self.assertRaises(AttributeError): + c.add('xxx', 'FOO_BAR') + c.add('xxx', 'FOO_BAR', exists_ok=True) + r = c.get('FOO_BAR') + self.assertEqual(r, 'xxx') + + + 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) + + + def test_all(self): + inidir = os.path.join(self.wd, 'files') + c = Config(inidir) + a = c.all() + self.assertEqual(a, list(c.store.keys())) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_enc.py b/tests/test_enc.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import os +import unittest +import logging + +from confini import Config +from confini.error import DecryptError +from confini.crypt.pgp import PGPDecrypter + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +script_dir = os.path.dirname(os.path.realpath(__file__)) +gnupg_dir = os.path.join(script_dir, 'gnupg') + +class TestBasic(unittest.TestCase): + + wd = os.path.dirname(__file__) + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_enc(self): + inidir = os.path.join(self.wd, 'files/crypt') + c = Config(inidir) + decrypter = PGPDecrypter() + c.add_decrypt(decrypter) + c.process() + with self.assertRaises(DecryptError): + c.get('FOO_BAZ') + os.environ['GNUPGHOME'] = gnupg_dir + c.get('FOO_BAZ') + + + def test_decrypt_with_non_string(self): + inidir = os.path.join(self.wd, 'files/crypt') + c = Config(inidir) + decrypter = PGPDecrypter() + c.add_decrypt(decrypter) + c.process() + override = { + 'FOO_XYZZY': False, + } + c.dict_override(override, 'test') + c.get('FOO_XYZZY') + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_env.py b/tests/test_env.py @@ -0,0 +1,88 @@ +#!/usr/bin/python + +import os +import unittest +import logging + +from confini import Config + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +class TestEnv(unittest.TestCase): + + wd = os.path.dirname(__file__) + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_dict_override(self): + inidir = os.path.join(self.wd, 'files') + c = Config(inidir) + c.process() + + override_dict = { + 'FOO_BAR': '666', + 'XYZZY_BERT': 'oscar', + 'BAR_FOO': None, + } + c.dict_override(override_dict, 'arbitrary dict') + + expect = { + 'FOO_BAR': '666', + 'FOO_BAZ': '029a', + 'BAR_FOO': 'oof', + 'XYZZY_BERT': 'oscar', + } + self.assertDictEqual(expect, c.store) + + override_dict = { + 'BAR_FOO': 'barbarbar', + } + c.dict_override(override_dict, 'arbitrary dict') + + expect = { + 'FOO_BAR': '666', + 'FOO_BAZ': '029a', + 'BAR_FOO': 'barbarbar', + 'XYZZY_BERT': 'oscar', + } + self.assertDictEqual(expect, c.store) + + + + def test_env_a_override(self): + os.environ['FOO_BAR'] = '43' + inidir = os.path.join(self.wd, 'files') + c = Config(inidir) + c.process() + + os.environ['ZZZ_FOO_BAR'] = '44' + inidir = os.path.join(self.wd, 'files') + c = Config(inidir, env_prefix='ZZZ') + c.process() + expect = { + 'FOO_BAR': '44', + 'FOO_BAZ': '029a', + 'BAR_FOO': 'oof', + 'XYZZY_BERT': 'ernie', + } + self.assertDictEqual(expect, c.store) + + os.environ['ZZZ_FOO_BAR'] = '' + inidir = os.path.join(self.wd, 'files') + c = Config(inidir, env_prefix='ZZZ') + c.process() + expect = { + 'FOO_BAR': '42', + 'FOO_BAZ': '029a', + 'BAR_FOO': 'oof', + 'XYZZY_BERT': 'ernie', + } + self.assertDictEqual(expect, c.store) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_multi.py b/tests/test_multi.py @@ -0,0 +1,50 @@ +#!/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(self): + inidir_one = os.path.join(self.wd, 'files', 'multi', 'one') + inidir_two = os.path.join(self.wd, 'files', 'multi', 'two') + c = Config(inidir_one, override_dirs=[inidir_two]) + c.process() + r = c.get('FOO_BAR') + self.assertEqual(r, 'plugh') + r = c.get('FOO_BAZ') + self.assertEqual(r, '42') + r = c.get('FOO_BAH') + self.assertEqual(r, None) + r = c.get('BAR_ONE') + self.assertEqual(r, 'three') + + + def test_parse_two_schema_error(self): + inidir_one = os.path.join(self.wd, 'files', 'multi', 'one') + inidir_two = os.path.join(self.wd, 'files', 'multi', 'three') + c = Config(inidir_one, override_dirs=[inidir_two]) + with self.assertRaises(KeyError): + c.process() + + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_translate.py b/tests/test_translate.py @@ -0,0 +1,49 @@ +# standard imports +import os +import unittest +import logging + +# local imports +from confini import Config + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + + +class TestTranslate(unittest.TestCase): + + wd = os.path.dirname(__file__) + + def setUp(self): + pass + + + def tearDown(self): + pass + + + def test_parse_default(self): + inidir = os.path.join(self.wd, 'files/translate') + c = Config(inidir) + c.process() + + self.assertTrue(c.get('TRUE_A')) + self.assertTrue(c.get('TRUE_B')) + self.assertTrue(c.get('TRUE_C')) + + self.assertFalse(c.true('FALSE_A')) + self.assertFalse(c.true('FALSE_B')) + self.assertFalse(c.true('FALSE_C')) + self.assertIsNone(c.get('FALSE_D')) + + o = { + 'TRUE_A': True, + 'FALSE_A': False, + } + c.dict_override(o, 'test') + self.assertTrue(c.true('TRUE_A')) + self.assertFalse(c.true('FALSE_A')) + + +if __name__ == '__main__': + unittest.main()