config-library
utility library to find and load configuration files
see the documentation for more information
Installation
pip install config-library
pip install config-library[all]
pip install config-library[validation]
pip install config-library[dotenv]
pip install config-library[json5]
pip install config-library[toml]
pip install config-library[yaml]
Install Variations
variation | information |
---|
config-library[all] | adds all dependencies from the variations below |
config-library[validation] | adds support to validate the loaded configuration against a pydantic model |
config-library[dotenv] | adds support to load .env files |
config-library[json5] | adds support to load .json5 files |
config-library[toml] | adds support to load .toml files |
config-library[yaml] | adds support to load .yaml files |
Supported Config-Types
Usage Example
Basic usage
from configlib import find_and_load
config = find_and_load("app.conf")
address = config.get('database', 'address')
port = config.getint('database', 'port', fallback=5000)
Validation
from configlib import find_and_load, validation
class ConfigModel(validation.BaseModel):
database: 'DatabaseModel'
class DatabaseModel(validation.BaseModel):
address: validation.IPvAnyAddress
port: validation.PositiveInt
config = find_and_load("config.ext")
config.validate(ConfigModel)
Config distribution
configlib offers a global configuration instance.
This can help you avoid the hassle of passing the configuration instance to different functions.
main.py
from configlib import config, find_and_load
from sub import function
config.update(find_and_load("config.ext"))
function()
sub.py
import logging
from configlib import config
def function():
if config.getbool("debug"):
logging.debug("Some information")
...
Loading specific file
import configlib
config = configlib.load("./app.conf")
Loading from environment variables
import configlib
config = configlib.load_environ("APP")
Specify/Customise search locations
from configlib.finder import find, places
config_file = find(
"project-name.conf",
"project-name/settings.conf",
"{project-name,variant-name}/settings.conf",
places=[places.local, places.user_conf],
)
Accessing configuration
In the end you get an instance of the ConfigInterface
with useful get-methods
from configlib import ConfigInterface
config: ConfigInterface
config.get("database", "address", fallback="localhost")
config.getstr("database", "address", fallback="localhost")
config.getint("database", "port", fallback=5432)
config.getfloat("database", "timeout", fallback=10.0)
config.getbool("database", "delayed-connect", fallback=False)
config.getlist("database", "tables", fallback=[], cast=str)
config.gettuple("database", "tables", fallback=[], cast=str)
config.getsplit("database", "tables")
config.getpath("database", "client-paths", fallback="./")
config.getpaths("database", "client-paths", fallback=[], as_path=True)
config.getshlex("database", "additional-params", fallback=[])
config.getinterface("database")
config.gettype("database", "timeout")
More in detail
For the more detailed description we will use this code example.
import configlib
config = configlib.find_and_load('project.conf', 'project/app.conf')
Searching
The configlib.finder
subpackage has a few predefined paths it attempts to search in.
In each of these places it attempts to find one of the passed variants (project.conf
, project/app.conf
).
If it can't find one it goes to the next place and repeats this process.
system file-structure
/
├─ etc/
├─ home/user/
│ ├─ path/to/repo/
│ │ ├─ src/code/
│ │ │ ├─ main.py
│ ├─ .config/
places where config-library
searches for the config-file
/home/user/path/to/repo/src/code/project.conf
(next to the started script)/home/user/path/to/repo/src/code/project/app.conf
/home/user/path/to/repo/project.conf
(next to .git/)/home/user/path/to/repo/project/app.conf
/home/user/.config/project.conf
(~/.config/)/home/user/.config/project/app.conf
/home/user/project.conf
(~/)/home/user/project/app.conf
/etc/project.conf
(/etc/)/etc/project/app.conf
Loading
After the search returns a filepath it is passed to the load()
function.
This function analyzes the file-extension and loads it with the correct loader.
The loader can be extended via the configlib.loader.register_loader
decorator.
Important is that it should return native types to be compatible with the ConfigInterface
from configlib.loader import register_loader
@register_loader("env", "environ")
def custom_loader(fp) -> dict:
...