3
0
Fork 0

fix: force interpolation of %(here)s, %(__file__)s in config files

we were previously doing this only for the `wutta.config.include` and
`wutta.config.require` settings, and pyramid (or paste?) has been
handling certain other ones, e.g. for beaker session cache paths.

but we really need to be able to rely on this being available
"everywhere" or else it's just confusing.
This commit is contained in:
Lance Edgar 2024-12-18 13:43:19 -06:00
parent 659d7e551e
commit fa76eb6aa9
2 changed files with 35 additions and 14 deletions

View file

@ -252,34 +252,44 @@ class WuttaConfig:
if path in self.files_read:
return
# try to load config from the given path
try:
config = configuration.config_from_ini(path, read_from_file=True)
except FileNotFoundError:
if not require:
log.warning("INI config file not found: %s", path)
return
raise
# try to load config with standard parser, and default vars
here = os.path.dirname(path)
config = configparser.ConfigParser(defaults={'here': here, '__file__': path})
if not config.read(path):
if require:
raise FileNotFoundError(f"could not read required config file: {path}")
return
# ok add that one to the mix
# load all values into (yet another) temp config
temp_config = configparser.RawConfigParser()
for section in config.sections():
temp_config.add_section(section)
# nb. must interpolate most values but *not* for logging formatters
raw = section.startswith('formatter_')
for option in config.options(section):
temp_config.set(section, option, config.get(section, option, raw=raw))
# re-write as temp file with "final" values
fd, temp_path = tempfile.mkstemp(suffix='.ini')
os.close(fd)
with open(temp_path, 'wt') as f:
temp_config.write(f)
# and finally, load that into our main config
config = configuration.config_from_ini(temp_path, read_from_file=True)
configs.append(config)
self.files_read.append(path)
# need parent folder of that path, for %(here)s interpolation
here = os.path.dirname(path)
# bring in any "required" files
requires = config.get(f'{self.appname}.config.require')
if requires:
for path in self.parse_list(requires):
path = path % {'here': here}
self._load_ini_configs(path, configs, require=True)
# bring in any "included" files
includes = config.get(f'{self.appname}.config.include')
if includes:
for path in self.parse_list(includes):
path = path % {'here': here}
self._load_ini_configs(path, configs, require=False)
def get_prioritized_files(self):

View file

@ -159,6 +159,17 @@ require = %(here)s/first.conf
self.assertEqual(files[0], second)
self.assertEqual(files[1], first)
def test_default_vars_interpolated(self):
myconf = self.write_file('my.conf', """
[foo]
bar = %(here)s/bar.txt
baz = %(__file__)s
""")
config = conf.WuttaConfig(files=[myconf])
self.assertEqual(config.get('foo.bar'), f'{self.tempdir}/bar.txt')
self.assertEqual(config.get('foo.baz'), myconf)
def test_constructor_defaults(self):
config = conf.WuttaConfig()
self.assertEqual(config.defaults, {})