Configuration manager for Python applications.
Project description
Magic-settings
Installation
pip install magic-settings
Using settings from yaml
file
pip install magic-settings[yaml]
Initialization
Project settings class declaration
from magic_settings import BaseSettings, Property
from functools import partial
class MySettings(BaseSettings):
VERSION = Property(types=str)
PROJECT_DIR = Property(types=str)
LOGGING_LEVEL = Property(default='INFO', choices=['NOTSET', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])
RETRIES_NUMBER = Property(types=int, converts=[int])
COEFFICIENT = Property(types=float, converts=[float])
DEBUG = Property(types=bool, converts=[int, bool], default=False)
DISTRIBUTED_SERVICE_HOST_NAMES = Property(types=list, converts=[partial(str.split, sep=',')])
Class Property
is a descriptor with following parameters:
- types - Type of
value
or a tuple of possibletypes
. It is aValueError
ifvalue
is not one of thetypes
. - validators - List of
callable
objects each of which is successively applied tovalue
. RaisesValueError
ifvalue
does not pass at least one of the validations (if any validation function returnsFalse
). - choices - List of any objects. If
value
is not inchoices
- raisesValueError
. When using this parameter, parameterstypes
andvalidators
are ignored. - default - Sets the default value of
Property
. - converts - List of
callable
objects. It is a chain of transformations that are successively applied to thevalue
and overwrite it each time. It applies tovalue
only ifvalue
is a string. RaisesValueError
ifvalue
at least one of the transformations failed to apply.
Property classes
Besides Property
following classes may be used for standard types:
BoolProperty
: accepts boolean values, converts case-insensitivetrue
orfalse
to appropriate python boolean value. Also this property accepts numbers (0
is False,1
is True).FloatProperty
: accepts float number values.IntProperty
: accepts integer number values.StringProperty
: accepts string values.StringListProperty
: accepts list of strings. You can specify delimiter in constructor of this class (,
is default value).HostListProperty
: accepts list of hosts. Each host is a tuple containing astring
hostname and anint
port. Pairs should be divided by comma, hostname and port should be divided by colon. For example,192.168.20.1:80,www.yandex.ru:1234,localhost:8888
will be converted into[('192.168.20.1', 80), ('www.yandex.ru', 1234), ('localhost', 8888)]
.
Above example may be simplified using these properties:
from magic_settings import (BaseSettings, Property,
BoolProperty, FloatProperty, IntProperty, StringListProperty, StringProperty)
class MySettings(BaseSettings):
VERSION = StringProperty()
PROJECT_DIR = StringProperty()
LOGGING_LEVEL = Property(default='INFO', choices=['NOTSET', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])
RETRIES_NUMBER = IntProperty()
COEFFICIENT = FloatProperty()
DEBUG = BoolProperty(default=False)
DISTRIBUTED_SERVICE_HOST_NAMES = StringListProperty()
Settings configuration
Settings configuration occurs at the stage of creating a Settings object.
from my_project import my_module, my_awesome_module
from my_config import MySettings
settings = MySettings(
modules=[my_module, my_awesome_module],
prefix='MY_PROJECT_ENV_SETTINGS',
dotenv_path='/path/to/my/env',
override_env=True,
yaml_settings_path='/path/to/my/yaml/settings.yaml',
use_env=True
)
Parameters
-
modules: List of Python modules with variables to import. Default
None
. -
prefix: The prefix with which the environment variables are taken. Default -
None
.settings.py
class MySettings(BaseSettings): PSYDUCK = Property(types=str)
.env
MYPROJECT_PSYDUCK=Owowowow
some_other_place.py
settings = MySettings(prefix='MYPROJECT')
or
settings = MySettings(prefix='MYPROJECT_')
-
dotenv_path: Path to env-file. Default -
None
. Using for exporting variables from env-file to environment. Ifdotenv_path
isNone
- walking up the directory tree looking for the specified file - called.env
by default. -
override_env:
True
- override existing system environment variables with variables from.env
- file,False
- do not override. Default -False
. -
yaml_settings_path: Path to yaml config file. Default -
None
. -
use_env:
True
- use environment variables. Default -True
.
Exceptions
ValueError: If modules type is not list
or NoneType
and if type of element in modules is not ModuleType
.
Settings loading
Loading settings can be initiated anywhere in the project.
from where_your_settings import settings
settings.init()
If called again, it goes through the configuration files and update properties.
Settings priority
In case of intersection of settings the following priority will be applied: my_module -> my_awesome_module -> .env -> settings.yaml
class MySettings(BaseSettings):
PSYDUCK = Property(types=str)
my_module.py
PSYDUCK = 'one'
my_awesome_module.py
PSYDUCK = 'two'
.env
MYPROJECTPREFIX_PSYDUCK=env
setting.yaml
PSYDUCK: yaml
Examples
>>> settings = MySettings(modules=[my_module])
>>> settings.PSYDUCK
'one'
>>> settings = MySettings(modules=[my_module, my_awesome_module])
>>> settings.PSYDUCK
'two'
>>> settings = MySettings(modules=[my_awesome_module, my_module])
>>> settings.PSYDUCK
'one'
>>> settings = MySettings(modules=[my_module, my_awesome_module], dotenv_path='/path/to/dotenv')
>>> settings.PSYDUCK
'env'
>>> settings = MySettings(modules=[my_module, my_awesome_module], dotenv_path='/path/to/dotenv', use_env=False)
>>> settings.PSYDUCK
'two'
>>> settings = MySettings(modules=[my_module, my_awesome_module], dotenv_path='/path/to/dotenv', yaml_settings_path='/path/to/yaml/settings.yaml')
>>> settings.PSYDUCK
'yaml'
Temporary Property override
my_module.py
PIKACHU = 'Psyduck_is_not_fine'
PSYDUCK = 'Owowowow'
from my_project import my_module
from my_config import MySettings
class MySettings(BaseSettings):
PSYDUCK = Property(types=str)
PIKACHU = Property(types=str)
settings = MySettings(modules=[my_module])
settings.init()
with settings.temp_set_attributes(PSYDUCK='I_am_ok', PIKACHU='Psyduck_is_ok'):
print(settings.PSYDUCK) # 'I_am_ok'
print(settings.PIKACHU) # 'Psyduck_is_ok'
print(settings.PSYDUCK) # 'Owowowow'
print(settings.PIKACHU) # 'Psyduck_is_not_fine'
Method temp_set_attributes
is not thread-safe.
Settings list
You can use methods to_dict()
, to_json()
to get current settings:
from magic_settings import BaseSettings, Property
class MySettings(BaseSettings):
PSYDUCK = Property(types=str)
PIKACHU = Property(types=str)
settings = MySettings(dotenv_path='12345.env')
settings.PIKACHU = '3'
settings.PSYDUCK = '12345'
pprint(settings.to_dict())
{
'properties': {
'PIKACHU': '3',
'PSYDUCK': '12345'
},
'sources': [{
'source_type': 'dotenv',
'address': {
'dotenv_path': '12345.env',
'override': False
}
}]
}
Validation
It is recommended to use following BaseSettings
class methods during redefinition update_settings_from_source
method:
pre_validate
- check that types are configured correctly; check that the values fromchoices
and the default pass the type check.post_validate
- check if eachProperty
is assigned a value.
Dynamic settings
Implementing a custom dynamic settings source
Example with storing settings in dict source
:
from magic_settings import BaseDynamicSettings, Property
source = {
'JIGGLYPUFF': 'pink'
}
class BaseDynamicSettingsDict(BaseDynamicSettings):
async def update_settings_from_source(self):
super().update_config(**source)
async def update_config(self, **kwargs):
source.update(kwargs)
return super().update_config(**kwargs)
Definition of project`s dynamic settings class
class MyDynamicSettings(BaseDynamicSettingsDict):
JIGGLYPUFF = Property(types=str)
Dynamic Settings Initialization
loop = asyncio.get_event_loop()
dynamic_settings = MyDynamicSettings(loop=loop, update_period=5, task_retries_number=5)
- update_period: time between updating settings from source, in seconds.
- task_retries_number: the number of attempts to update the settings when an exception occurred before stopping the task.
Dynamic settings update
Updating settings only once
await dynamic_settings.update_settings_from_source()
Starting the update loop
await dynamic_settings.start_update()
Stopping the update loop
await dynamic_settings.stop_update()
Writing settings into the source
await dynamic_settings.update_config(JIGGLYPUFF='magenta')
Exceptions
- magic_settings.DynamicSettingsSourceError - this exception should be selected if the settings source in the class inherited from
BaseDynamicSettings
is unavailable.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file magic-settings-1.2.0.tar.gz
.
File metadata
- Download URL: magic-settings-1.2.0.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | be24793617d9faef25a8b540c3bf1920e2a2587327d1ae84c42ca368405a9363 |
|
MD5 | 5172e046ad5192060de4b80608e5e653 |
|
BLAKE2b-256 | 51b95f570c03cee61c12ae097c1df2a7e3de22070af24674f633a88008c79d2a |
File details
Details for the file magic_settings-1.2.0-py3-none-any.whl
.
File metadata
- Download URL: magic_settings-1.2.0-py3-none-any.whl
- Upload date:
- Size: 11.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1c5928b6a51f41b62d8287898b271904ac15115314a0afbdd6a16ca6b7b5e3b7 |
|
MD5 | a8f3c6a85759ad1dc3dc4a45a72d1293 |
|
BLAKE2b-256 | 44d01c2364baf665a737f5d68ae9e7e05df6021caaed4337d0c9ece6b7e5f2b6 |