beetbox / confuse

painless YAML config files for Python
https://pypi.org/project/confuse/
MIT License
415 stars 51 forks source link

How to read local folder as source for default yaml file #124

Closed mvadu closed 3 years ago

mvadu commented 3 years ago

I am trying to create a docker image with a python module, and trying to use confuse to use for config management.

RUN pip install confuse
#confuse expects yaml extn
COPY config_default.yml config_default.yaml 
COPY iot.py iot.py

config_default.yml

ble:
  device_id: 0

iot.py

custom_config_file = 'custom.yml'
try:
    config = confuse.Configuration('iot')
    # Add config items from specific file
    if os.path.exists(custom_config_file):
        config.set_file(custom_config_file)
except:
    sys.stderr.write("Couldn't load config files")
    raise

Now inside the docker both main python file and the yaml file will be at the root level (/). Above code fails to read the config_default since it is assuming the default location to be in /root/.config/iot (similar to #75). How can I make confuse ignore the default folder guess work and ask it to load from current folder?

sampsyo commented 3 years ago

Hmm; when config_default.py is missing, it should just silently ignore that fact. (In other words, the default file is loaded only optionally.) Can you include the actual error you're seeing?

mvadu commented 3 years ago

Since posting this question I came across #63 and tried the approach suggested (to override config_dir).

iot.py

#!/usr/bin/env python3
import sys
import os
import confuse

class AppConfig(confuse.Configuration):
    def config_dir(self):
        return os.getcwd()

def load_config() -> AppConfig:
    try:
        config = AppConfig("iot")
        # config.set_file('config_default.yaml')
        # custom_config_file = 'custom.yml'
        # # Add config items from specific file
        # if os.path.exists(custom_config_file):
        #     config.set_file(custom_config_file)
    except:
        sys.stderr.write("Couldn't load config files")
        raise
    return config

config = load_config()
print(config)
print(config.config_dir())
dev_id = config['ble']['device_id'].get(int)
print(dev_id)

and inside docker

>ls -all
-rwxrw-r--   1 root root    20 Feb 24 18:00 config_default.yaml
drwxr-xr-x  13 root root  3720 Feb 24 18:02 dev
drwxr-xr-x   1 root root  4096 Feb 24 18:02 etc
drwxr-xr-x   2 root root  4096 Jan 30 17:37 home
-rwxrw-r--   1 root root   717 Feb 24 18:01 iot.py

>python iot.py
{}
/
Traceback (most recent call last):
  File "//iot.py", line 26, in <module>
    dev_id = config['ble']['device_id'].get(int)
  File "/usr/local/lib/python3.9/site-packages/confuse/core.py", line 351, in get
    return templates.as_template(template).value(self, template)
  File "/usr/local/lib/python3.9/site-packages/confuse/templates.py", line 70, in value
    return self.get_default_value(view.name)
  File "/usr/local/lib/python3.9/site-packages/confuse/templates.py", line 75, in get_default_value
    raise exceptions.NotFoundError(u"{} not found".format(key_name))
confuse.exceptions.NotFoundError: ble.device_id not found
sampsyo commented 3 years ago

It's really hard to say whether this is the correct behavior without knowing the contents of those files. Also, FWIW, I think Docker is a red herring here and the problem probably lies elsewhere.

mvadu commented 3 years ago

this is all in the default config

 cat config_default.yaml
ble:
  device_id: 0
mvadu commented 3 years ago

trying bare yaml load seems to be working fine..

 python
Python 3.9.2 (default, Feb 19 2021, 17:14:57)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import yaml
>>> default_config_file = 'config_default.yaml'
>>> with open(default_config_file, 'r') as yaml_stream:
...     config = yaml.load(yaml_stream, Loader=yaml.SafeLoader)
...
>>> print(config)
{'ble': {'device_id': 0}}
>>>
mvadu commented 3 years ago

@sampsyo I think I found my problem.. even after overriding the config_dir, default_filename is still appended with _package_path . So I manually added config.set_file('config_default.yaml') and it worked just fine..