beetbox / beetbox/confuse

Loosen config path assumptions

Open
#75 6 comments 4 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
424
Forks
57
PR merge metrics
No merged PRs in 30d

Description

`confuse` tries to make some smart guesses about where config files are stored on the system, but it can be somewhat confusing and sometimes I would rather just hardcode specific locations that I can direct people to with certainty.

Basically, I'd like to be able to just do this:
```python
config = confuse.LazyConfig('mypkg', paths='~/.mypkg/config.yml')
```
--------

I apologize for just pasting a bunch of code, but I figured I'd illustrate the change. I was planning on submitting a pull request, but I figured I would open an issue first to discuss.

Basically, I decoupled the auto-config detection from the the class definition and now they live in 2 utility functions. Now you have the option to override the default config paths and the `Configuration` object is simpler and less dependent on the config location assumptions.

```python

class Configuration(RootView):
def __init__(self, appname, modname=None, paths=None, defaults=None, read=True):
super(Configuration, self).__init__([])
self.appname = appname
self.modname = modname
self._env_var = '{}DIR'.format(self.appname.upper())
self._package_path = _package_path(modname) if modname else None

# set/find config files - this preserves the original behavior by default
self.paths = _as_list(paths) or self.user_config_files()[:1]
self.defaults_paths = _as_list(defaults) or self.pkg_config_files()

if read:
self.read()

def user_config_files(self):
return find_user_config_files(self.appname, self._env_var)

def pkg_config_files(self):
return find_pkg_config_files(self._package_path)

def read(self, user=True, defaults=True):
if user:
for filename in self.paths:
self.set_file(filename)
if defaults:
for filename in self.defaults_paths:
self.set_file(filename, default=True)

def set_file(self, filename, default=False, ignore_missing=False):
filename = os.path.abspath(filename)
if os.path.isdir(filename): # provided directory, find file
fname = DEFAULT_FILENAME if default else CONFIG_FILENAME
filename = os.path.join(filename, fname)

if ignore_missing and not os.path.isfile(filename):
return
self.set(ConfigSource(load_yaml(filename), filename, default=default))

def dump(self):
...

def find_user_config_files(appname, env_var, config_fname=CONFIG_FILENAME):
# If environment variable is set, use it.
if env_var in os.environ:
appdir = os.path.abspath(os.path.expanduser(os.environ[env_var]))
if os.path.isfile(appdir): # allow user to set config explicitly
cfgfiles = [appdir]
else:
cfgfiles = [os.path.join(appdir, config_fname)]
else:
# Search platform-specific locations. If no config file is
# found, fall back to the first directory in the list.
cfgfiles = [os.path.join(d, appname, config_fname) for d in config_dirs()]
cfgfiles = [f for f in cfgfiles if os.path.isfile(f)] or cfgfiles[:1]

# Ensure that the directory exists.
for f in cfgfiles:
os.makedirs(os.path.dirname(f), exist_ok=True)
return cfgfiles

def find_pkg_config_files(package_path, config_fname=DEFAULT_FILENAME):
return [os.path.join(package_path, config_fname)] if package_path else []

def _as_list(x):
return (
x if isinstance(x, list) else
list(x) if isinstance(x, tuple) else
[x] if x else [])
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the Configuration.__init__, read, and set_file entry points and the proposed find_user_config_files, find_pkg_config_files, and _as_list helpers shown in the issue. Verify that explicit paths work while the default path discovery behavior remains unchanged, and run the existing test suite to confirm the configuration API still behaves correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
tooling
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.