app-settings 1.4.4
YAML for application configuration, lite version (inspired by Ruby gem "config")
License: MIT
Requires Python: >=3.6

app\_settings module
====================

Simplify usage of YAML files for application configuration.

Inspired by Ruby Gem "config" https://github.com/railsconfig/config But
not all features implemented yet.

Usage example
-------------

Installation: ``pip install app_settings``

Create sample app with following structure:

.. code:: bash

    /my_app
      my_app.py
      /config
        settings.yml  # at least one *.yml file required
        additional_settings.yml
        /settings  # use this only in case if you need different settings for your environments
          production.yml
          production.db.yml
          development.yml
          development.db.yml   

``AppSettings`` -- singleton, so it is not possible to create more than
one instance of config object.

By default, script will try to load all ``./config/*.yml`` and, if exist
``./config/settings/${APP_ENV}*.yml`` configuration files.

Take note, that all variables defined in ``./config/*.yml`` files will
be overridden by variables from ``./config/settings/${APP_ENV}.yml``.

Also, ``./config/*.yml`` loaded in alphabetical order, so if you will
define variable VAR in ``additional_settings.yml`` it will be redefined
by VAR from ``settings.yml``.

If you have settings, which not depends on the environment, simply use
``./config/{file name}.yml``; In case, when you need settings, which
depends on the environment, use ``./config/settings/{ENV}.yml``.

Environment (development/stage/production etc)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If your application use more than one environment, for example
``development`` and ``production``, you can specify what config file to
load by setting env variable

.. code:: python

    # before your application starts
    # export APP_ENV='production' or APP_ENV='production' python my_app.py 

    from app_settings import AppSettings

    cfg = AppSettings()

By default, if no ``APP_ENV`` is given, file
``./config/settings/development.yml`` will be loaded, that's why this
file is required.

Also it is possible to redefine name of variable.

.. code:: python

    # export TEST_ENV='production'

    from app_settings import AppSettings

    cfg = AppSettings(env_name='TEST_ENV')

Working with environment variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is possible to redefine or set settings from environment variables.
AppSettings will read all env variables with ``SETTINGS`` prefix (by
default).

.. code:: yaml

    # settings.yml
    level1:
      redefined: 'redefined'
      not_redefined: 'not redefined'

.. code:: python

    # export SETTINGS__MY_VAR='test'
    # export SETTINGS__LEVEL1__REDEFINED='val'

    from app_settings import AppSettings

    cfg = AppSettings()
    print(cfg.my_var)  # 'test'
    print(cfg.level1.redefined)  # 'val'
    print(cfg.level1.not_redefined)  # 'not redefined'

You can setup your own prefix:

.. code:: python

    # export MYPREFIX__MY_VAR='test'
    # export MYPREFIX__LEVEL1__REDEFINED='val'

    from app_settings import AppSettings

    cfg = AppSettings(prefix='myprefix')
    print(cfg.my_var)  # 'test'
    print(cfg.level1.redefined)  # 'val'

Also it is possible to setup environment variable splitter (default:
``__``).

.. code:: python

    # export SETTINGS.MY_VAR='test'
    # export SETTINGS.LEVEL1.REDEFINED='val'

    from app_settings import AppSettings

    cfg = AppSettings(splitter='.')
    print(cfg.my_var)  # 'test'
    print(cfg.level1.redefined)  # 'val'

If you don't need to set/redefine settings from environment variables,
use ``use_env`` flag.

.. code:: python

    from app_settings import AppSettings
    cfg = AppSettings(use_env=False)

Suppress KeyError exception
~~~~~~~~~~~~~~~~~~~~~~~~~~~

In case, if you don't want to receive KeyError exception if key not
defined in file, you can use ``raise_error`` flag. By default: True

.. code:: python

    from app_settings import AppSettings
    cfg = AppSettings(raise_error=False)

    key = cfg.this_value_not_exist  # key == None

Config path
~~~~~~~~~~~

You can redefine default config path

.. code:: python

    from app_settings import AppSettings

    cfg = AppSettings(configs_path='my_config_path')

Run tests
---------

.. code:: bash

    cd app_settings
    python -m pytest -v --alluredir=./tests/results -n `nproc` --cov=app_settings --cov-config .coveragerc ./tests

Sample usage for tests
~~~~~~~~~~~~~~~~~~~~~~

Run these commands to create sample files structure

.. code:: bash

    $ cd <your project dir> 
    $ mkdir -p config/settings && \ 
        touch config/settings.yml && \
        touch config/settings/{production.yml,testing.yml} && \
        echo "implicity_wait: 5" > config/settings.yml && \
        echo 'search_text: "production environment"' > config/settings/production.yml && \
        echo 'search_text: "testing environment"' > config/settings/testing.yml
    $ touch test_with_app_settings.py

Install all python requirements:

.. code:: bash

    pip install selenium pytest app_settings

Copy code to ``test_with_app_settings.py``

.. code:: python

    ### Example, don't use it in your code
    import os
    os.environ['TEST_ENV'] = 'production'
    ### example

    import pytest
    from app_settings import AppSettings
    from selenium import webdriver


    @pytest.fixture(scope='session')
    def settings():
        cfg = AppSettings(env_name='TEST_ENV')
        return cfg


    @pytest.fixture
    def browser(settings):
        driver = webdriver.Chrome()
        driver.implicitly_wait(settings.implicity_wait)
        yield driver
        driver.close()


    def test_example(browser, settings):
        browser.get("https://ya.ru")
        search_field = browser.find_element_by_id('text')
        search_field.send_keys(settings.search_text)  # depending on env
        search_button = browser.find_element_by_tag_name('button')
        search_button.click()
        browser.find_elements_by_css_selector("div ul li")

TODO
----

1. Add reload feature