All Projects → daviskirk → climatecontrol

daviskirk / climatecontrol

Licence: MIT license
Python library for loading settings and config data from files and environment variables

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to climatecontrol

Dynaconf
Configuration Management for Python ⚙
Stars: ✭ 2,082 (+10310%)
Mutual labels:  config, yaml, settings, configuration, environment-variables, configuration-management, app-config, environment-configuration, 12factorapp
parse it
A python library for parsing multiple types of config files, envvars & command line arguments that takes the headache out of setting app configurations.
Stars: ✭ 86 (+330%)
Mutual labels:  config, yaml, toml, configuration, environment-variables, configuration-management, configuration-files
Simple Settings
A simple way to manage your project settings.
Stars: ✭ 165 (+725%)
Mutual labels:  config, yaml, toml, settings, configuration, configuration-management
sitri
Sitri - powerful settings & configs for python
Stars: ✭ 20 (+0%)
Mutual labels:  config, configuration, environment-variables, configuration-management, app-config, pydantic
Fig
A minimalist Go configuration library
Stars: ✭ 142 (+610%)
Mutual labels:  yaml, toml, configuration, environment-variables, configuration-management
Koanf
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
Stars: ✭ 450 (+2150%)
Mutual labels:  config, yaml, toml, configuration, configuration-management
goodconf
Transparently load variables from environment or JSON/YAML file.
Stars: ✭ 80 (+300%)
Mutual labels:  config, yaml, configuration, environment-variables, pydantic
cfg-rs
A Configuration Library for Rust Applications
Stars: ✭ 18 (-10%)
Mutual labels:  config, yaml, toml, settings, configuration
Konf
A type-safe cascading configuration library for Kotlin/Java/Android, supporting most configuration formats
Stars: ✭ 225 (+1025%)
Mutual labels:  config, yaml, toml, configuration
Dasel
Query, update and convert data structures from the command line. Comparable to jq/yq but supports JSON, TOML, YAML, XML and CSV with zero runtime dependencies.
Stars: ✭ 759 (+3695%)
Mutual labels:  config, yaml, toml, configuration
Strictyaml
Type-safe YAML parser and validator.
Stars: ✭ 836 (+4080%)
Mutual labels:  config, yaml, configuration, configuration-management
rubric
Linter Config Initializer for Python
Stars: ✭ 21 (+5%)
Mutual labels:  config, toml, configuration-management, configuration-files
Mconfig
MCONFIG is a lightweight Golang library for integrating configs files like (json, yml, toml) and environment variables into one config struct.
Stars: ✭ 28 (+40%)
Mutual labels:  config, yaml, toml, environment-variables
Config Rs
⚙️ Layered configuration system for Rust applications (with strong support for 12-factor applications).
Stars: ✭ 915 (+4475%)
Mutual labels:  config, toml, configuration, configuration-management
Config Lite
A super simple & flexible & useful config module.
Stars: ✭ 78 (+290%)
Mutual labels:  config, yaml, toml, configuration
Node Convict
Featureful configuration management library for Node.js
Stars: ✭ 1,855 (+9175%)
Mutual labels:  config, configuration, environment-variables, configuration-management
config-cpp
C++ Configuration management library inspired by the Viper package for golang.
Stars: ✭ 21 (+5%)
Mutual labels:  yaml, toml, environment-variables, configuration-files
Night Config
Powerful java configuration library for toml, yaml, hocon, json and in-memory configurations
Stars: ✭ 93 (+365%)
Mutual labels:  yaml, toml, configuration, configuration-management
paerser
No description or website provided.
Stars: ✭ 38 (+90%)
Mutual labels:  yaml, toml, configuration, environment-variables
superconfig
Access environment variables. Also includes presence validation, type coercion and default values.
Stars: ✭ 33 (+65%)
Mutual labels:  config, configuration, environment-variables, configuration-management

Build Status Coverage Status PyPI version PyPI license PyPI pyversions Conda version Code Style Black

https://raw.githubusercontent.com/daviskirk/climatecontrol/logo/climatecontrol-text.svg?sanitize=true

CLIMATECONTROL controls your applications settings and configuration environment. It is a Python library for loading app configurations from files and/or namespaced environment variables.

Features

  • Separation of settings and code
  • Loading from files (.yaml, .json, .toml)
  • Loading multiple files using glob syntax
  • Loading from environment variables, including loading of nested values
  • Freely reference nested configurations via files or environment variables
  • CLI integration
  • Validation using the Validation library of your choice
  • Logging configuration integration
  • Testing integration

Install

pip install climatecontrol

Usage

Set some environment variables in your shell

export CLIMATECONTROL_VALUE1=test1
export CLIMATECONTROL_VALUE2=test2

Then use them in your python modules:

from climatecontrol import climate
print(climate.settings)

{
    'value1': 'test1',
    'value2': 'test2'
}

In case you want to update your settings or your environment variables have changed and you want to reload them, the update method will reload your settings:

import os
os.environ['CLIMATECONTROL_VALUE3'] = 'new_env_data'
climate.reload()
print(climate.settings)

{
    'value1': 'test1',
    'value2': 'test2',
    'value3': 'new_env_data'
}

Now you've noticed that you want more complex configurations and need nested settings. For this situation we can delimit sections using a double underscore:

export CLIMATECONTROL_SECTION1__VALUE1=test1
export CLIMATECONTROL_SECTION2__VALUE2=test2
export CLIMATECONTROL_SECTION2__VALUE3=test3
export CLIMATECONTROL_SECTION2__SUB_SECTION__VALUE4=test4
from climatecontrol import climate
print(climate.settings)

{
    'section1': {
        'value1': 'test1'
    },
    'section2': {
        'value2': 'test2',
        'value3': 'test3',
        'sub_section': {
            'value4': 'test4'
        }
    }
}

Settings file support

If you don't want to use an environment variable for every single setting and want to put your settings in a single file instead you can to this as well. Settings files can be yaml files (.yml/ .yaml), json files (.json) or toml files (.toml).

export CLIMATECONTROL_SETTINGS_FILE=./my_settings_file.yml

The file could look like this:

# ./climatecontrol_settings.yaml
section1:
  subsection1 = test1

section2:
  subsection2: test2
  subsection3: test3

or in toml form:

# ./climatecontrol_settings.toml
[section1]
subsection1 = "test1"

[section2]
subsection2 = "test2"
subsection3 = "test3"

In the following documentation examples, yaml files will be used, but any examples will work using the other file syntaxes as well.

See the climatecontrol.core.Climate.inferred_settings_files docstring for further examples of how settings files are loaded and how they can be named. Also note that you can set your own settings files explicitely either by settings an environment variable:

export CLIMATECONTROL_SETTINGS_FILE="mysettings.yaml, mysettings.toml, override.yml"

or by adding them in code:

climate.settings_files.extend(["mysettings.yaml", "mysettings.toml", "override.yml"]

Advanced Features

Setting variables from values saved in files

Sometimes we don't want to save values in plain text in environment files or in the settings file itself. Instead we have a file that contains the value of the setting we want. A good example for this behaviour are docker secrets that store secrets in temporary files.

To read a variable from a file, simply add a "_from_file" to the variable name and give it the path to the file that contains the variable as a value.

Using a settings file with the contents (in this case yaml):

section1:
  subsection1_from_file: /home/myuser/supersecret.txt

or using an environment variable:

export CLIMATECONTROL_SECTION1_SUBSECTION1_FROM_FILE="/home/myuser/supersecret.txt"

will both write the content of the file at "/home/myuser/supersecret.txt" into the variable section1 -> subsection1.

Setting variables from values saved in specific environment variables

Similarly, to read a value from an environment variable, add a "_from_env" to the variable name. For example if we wanted to obtain a value from the variable SPECIFIC_ENV_VAR:

export SPECIFIC_ENV_VAR="some value"

Using a settings file with the contents (in this case yaml):

section1:
  subsection1_from_env: SPECIFIC_ENV_VAR

or using an environment variable:

export CLIMATECONTROL_SECTION1_SUBSECTION1_FROM_FILE="/home/myuser/supersecret.txt"

will both write "some value" into the variable section1 -> subsection1.

Settings variables from serialized content

section1_from_json_content: '{"subsection1": "test", "subsection2": 2}'
section2_from_toml_content: 'subsection1 = "test"\nsubsection2 = 2\n'
section3_from_yaml_content: 'subsection1: test\nsubsection2: 2\n'

The equivilant environment variables are also handled correctly:

CLIMATECONTROL_SECTION1_FROM_JSON_CONTENT='{"subsection1": "test", "subsection2": 2}'
CLIMATECONTROL_SECTION2_FROM_TOML_CONTENT='subsection1 = "test"\nsubsection2 = 2\n'
CLIMATECONTROL_SECTION3_FROM_YAML_CONTENT='subsection1: test\nsubsection2: 2\n'

Nested settings files

In addition, file variables can also target other settings files directly. To do this, just make sure the target file is has an extension supported by climate control. A simple example is illustrated here. Given a settings file:

value1: "spam"
section1_from_file: /home/myuser/nestedfile.yaml

where the content of /home/myuser/nestedfile.yaml is:

value2: "cheese"
subsection:
  value3: "parrot"

which would result in a settings structure:

{
    "value1": "spam",
    "section1": {
        "value2": "cheese",
        "subsection": {
            "value3": "parrot"
        }
    }
}

You can also expand the settings at the root of the document by using only "_from_file" as the key:

value1: "spam"
_from_file: /home/myuser/nestedfile.yaml
{
    "value1": "spam",
    "value2": "cheese",
    "subsection": {
        "value3": "parrot"
    }
}

Extensions

While the default climate object is great for most uses, perhaps you already have a settings object style that you like or use a specific library for validation. In these cases, CLIMATECONTROL can be extended to use these libraries.

Dataclasses

>>> from climatecontrol.ext.dataclasses import Climate
>>> from dataclasses import dataclass, field
>>>
>>> @dataclass
... class SettingsSubSchema:
...     d: int = 4
...
>>> @dataclass
... class SettingsSchema:
...     a: str = 'test'
...     b: bool = False
...     c: SettingsSubSchema = field(default_factory=SettingsSubSchema)
...
>>> climate = Climate(dataclass_cls=SettingsSchema)
>>> # defaults are initialized automatically:
>>> climate.settings.a
'test'
>>> climate.settings.c.d
4
>>> # Types are checked if given
>>> climate.update({'c': {'d': 'boom!'}})
Traceback (most recent call last):
    ...
dacite.exceptions.WrongTypeError: wrong type for field "c.d" - should be "int" instead of "str"

Pydantic

Pydantic is a great data validation library: https://github.com/samuelcolvin/pydantic and climatecontrol also provides a simple extension to use pydantic models directly (typing functionality mentioned above works here as well).

>>> from climatecontrol.ext.pydantic import Climate
>>>
>>> class SettingsSubSchema(BaseModel):
...     d: int = 4
...
>>> class SettingsSchema(BaseModel):
...     a: str = 'test'
...     b: bool = False
...     c: SettingsSubSchema = SettingsSubSchema()
...
>>> climate = Climate(model=SettingsSchema)
>>> # defaults are initialized automatically:
>>> climate.settings.a
'test'
>>> climate.settings.c.d
4
>>> # Types are checked if given
>>> climate.update({'c': {'d': 'boom!'}})
Traceback (most recent call last):
    ...
pydantic.error_wrappers.ValidationError: 1 validation error for SettingsSchema
c -> d
    value is not a valid integer (type=type_error.integer)

Integrations

Command line support using click

The click library is a great tool for creating command line applications. If you don't want to have to use an environment to set your configuration file. Write your command line application like this:

import click

@click.command()
@climate.click_settings_file_option()
def cli():
   print(climate.settings)

save it to a file like "cli.py" and then call it after installing click:

pip install click
python cli.py --settings ./my_settings_file.toml

whithout needing to set any env vars.

Multiple files are supported. They will be automatically recursively merged with the last file overriting any overlapping keys of the first file.

pip install click
python cli.py --settings ./my_settings_file.toml  --settings ./my_settings_file.yaml

Logging

If you have a "logging" section in your settings files, you can configure python standard library logging using that section directly:

logging:
  formatters:
    default:
      format': "%(levelname)s > %(message)s"
  root:
    level: DEBUG
import logging
from climatecontrol import climate

climate.setup_logging()
logging.debug('test')
# outputs: DEBUG > test

Testing

When testing your application, different behaviours often depend on settings taking on different values. Assuming that you are using a single Settings object accross multiple functions or modules, handling these settings changes in tests can be tricky.

The settings object provides a simple method for modifying your settings object temporarily:

climate.update({'a': 1})
# Enter a temporary changes context block:
with climate.temporary_changes():
    climate.update({'a': 1})
    # Inside the context, the settings can be modified and used as you choose
    print(climate['a'])  # outputs: 2
# After the context exits the settings map
print(climate['a'])  # outputs: 1

Contributing

See: CONTRIBUTING.md

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].