# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['confgetti']

package_data = \
{'': ['*']}

install_requires = \
['python-consul>=1.1.0,<2.0.0', 'voluptuous>=0.11.7,<0.12.0']

setup_kwargs = {
    'name': 'confgetti',
    'version': '0.1.12',
    'description': 'Package for getting configuration variables from remote configuration server, json files and environment variables in a simple way',
    'long_description': '<img src="docs/images/confgetti_logo_small.png" width="200">\n\n*latest version 0.1.11*\n\n![](https://github.com/Styria-Digital/confgetti/workflows/Tests/badge.svg)\n\n#### Tool for configuration and variables management.\n\nFetch variables for your application easily from **Consul KV** ➡️ **config\\*.json** ➡️ **environment.** via simple python method/s!\n\n## Content\n\n1. [Installation and QuickStart](#installation-and-quickstart)\n    1. [Install with pip](#install-confgetti-with-pip)\n    2. [Get a single variable](#get-a-single-variable)\n    3. [Get multiple variables](#get-multiple-variables)\n    4. [Override module variables](#override-current-module-variables)\n2. [The Problem](#the-problem)\n    1. [King of n00bs way](#1-king-of-n00bs-way)\n    2. [Slightly less n00b way](#2-slightly-less-n00b-way)\n3. [The Solution](#the-solution)\n    1. [Logic flow](#logic-flow)\n4. [Consul settings](#consul-settings)\n    1. [Through environment variables](#through-environment-variables)\n    2. [Upon initialization](#upon-initialization)\n5. [API](#api)\n    1. [Shorthand methods](#shorthand-methods)\n        1. [get_variables](#confgettiget_variablespath-keys-use_envtrue-use_consultrue)\n        2. [load_and_validate_config](#confgettiload_and_validate_configconfig_module_name-env_var-schemanone-keysnone-uppercasefalse)\n    2. [Confgetti](#confgetticonfgetticonsul_confignone-prepare_consultrue)\n        1. [get_variable](#confgetticonfgettiget_variablekey-pathnone-fallbacknone-convert_tonone-use_envtrue-use_consultrue)\n        2. [get_variables](#confgetticonfgettiget_variablespathnone-keysnone-use_envtrue-use_consultrue)\n6. [Demos](#demos)\n7. [Developer Notes](#developer-notes)\n    1. [Releasing new version](#releasing-new-version)\n\n\n## Installation and QuickStart\n\n### Install **Confgetti** with `pip`:\n\n```\npip install confgetti\n```\n\n### Get a single variable:\n\n```python\n# my_app/config.py\nfrom Confgetti import get_variable\n\ncgtti = Confgetti({\'host\': \'consul_instance_host\'})\n\nmy_variable = cgtti.get_variable(\'MY_VARIABLE\')\n```\n\n### Get multiple variables:\n\n```python\n# my_app/config.py\nfrom Confgetti import get_variable\n\ncgtti = Confgetti({\'host\': \'consul_instance_host\'})\n\nmy_variables_dict = cgtti.get_variables(keys=[\n    \'MY_VARIABLE\',\n    \'YOUR_VARIABLE\',\n    \'OUR_VARIABLE\'\n])\n```\n\n### Override current module variables:\n\n\n1. `ENV CONSUL_HOST=consul_instance_host`\n2. variables under `MY_APP` namespace in consul\n\n```python\n# my_app/config.py\nfrom voluptuous import Schema, Coerce\nfrom confgetti import load_and_validate_config\n\n\nmy_variable = None\nyour_variable = None\n\n_schema = Schema({\n    "my_variable": str,\n    "your_variable": Coerce(int)\n})\n\n\nload_and_validate_config(__name__, \'MY_APP\', _schema)\n\n```\n```python\n# my_app/some_logic.py\nfrom .config import my_variable, your_variable\n\nprint(my_variable)  # should be a string and not None\nprint(your_variable  # should be an integer and not None\n\n```\n\n\n## The Problem\n\nModern web app development and deployment often consider isolated app environments that are easily manageble and quickly deployed with software as **VM**s or **Docker**.  \nAs your app gets bigger and needs more and more *settings* variables declared in your configuration modules or classes, management of those variables becomes frustrating, especially for those who manage the production state of the app or multiple apps and do not care about actual application code.\n\nImagine a simple web application that uses a database for data storage, cache mechanism, and AWS S3 Bucket static file storage. Oh yes, and our app is Dockerized.  \nTo run that app successfully usually you need to pass configuration variables to methods/drivers that are communicating with those services. So at least, you\'ll need:\n\n1. **Database**\n    1. Database name\n    2. Host\n    3. Username\n    4. Password\n    5. Port?\n2. **Cache**\n    1. Host\n    2. Index?\n    3. Username?\n    4. Password?\n3. **S3 Bucket**\n    1. AWS secret access key\n    2. AWS access key id\n    3. Bucket name\n\nSo for just **3** external services, we could end with up to **12** different settings variables that are crucial for the successful running of our simple web app.\n\nHow do you deal with a problem like an *n00b*?\n\n#### 1. "King of n00bs" way\n\nYou could always leave those variable hardcoded to your configuration module, but perhaps, what if suddenly you need to switch to different AWS user and use the different bucket? \n\nWe even do not touch application code or logic actually but we need to:\n1. push those changes to our repository (wait for a Merge request, eh?)\n2. build a new Docker image\n3. deploy a new image\n\nWhole deployment process just because  of those **3** simple variables. Not to mention that there are some sensitive data in those **12** variables, so storing them inside codebase is **NEVER** a good idea and **ALWAYS** security issue.\n\n#### 2. "Slightly less n00b" way\n\nThe most common way of variables management, especially in the Docker world, is to assign necessary variables into the container environment via Docker runner and then get them from application code by checking the value of some agreed and known environment key name.\n\nIf we put aside the security problem of such an approach (yes, environment variables could be readable by a malicious user), there is still one more common and frustrating problem: A bunch of sensitive variables that need to be correctly passed each time as our Docker container is restarted or redeployed.\n\nEach time you need to pass those **12** variables to `docker` command, and even with `docker-compose` you still need to declare those variables in the `docker-compose.yml` file which returns us to previous **"King of n00bs" way**.\n\nDo not forget, we are dealing with just one simple web app. Imagine the size of the problem on some cluster of web apps. Your DevOps(in most cases you) will hate you.\n\n\n## The Solution\n\nHere comes **Confgetti** to save a day! 🎉🎉🎉\n\n**Confgetti** uses [Consul](https://www.consul.io) key/value storage for setting and getting your variables.\nIf you have running consul instance and `MY_VARIABLE` exists in its KV, you can get it simple as that:\n\n```python\nfrom Confgetti import get_variable\n\ncgtti = Confgetti({\'host\': \'consul_instance_host\'})\n\nmy_variable = cgtti.get_variable(\'MY_VARIABLE\')\n```\n\nMaybe you still want to store some or all variables into environment?  \nNo problem!\n**Confgetti** can get a variable from your environment also.\n\nSo now we set environment variable `MY_VARIABLE` with some custom value.  \nHow to get a variable from the environment?  \nWith the same `get_variable` method used in the example above.  \nNo need for extra setup, custom code or monkey patching and it is because of **Confgetti** efficient logic flow.\n\n### Logic flow\n\n**Confgetti** tries to fetch a variable from two different sources in order, overriding the previous source result. \nWhen you ask for a variable with `get_variable`, the lookup is made in the following order:\n\n**Consul**  \n⬇️  \n**environment**  \n⬇️  \nApp  \n\nSo if you have `MY_VARIABLE` key stored in consul and in the environment, **Confgetti** will return the value\nstored in the environment (if you do not tell **Confgetti** otherwise.).  \n**Confgetti** does not punish you if you do not have the Consul server running, it will still return value from the environment variable!\n\nSlightly *high-level* function [load_and_validate_config](#confgettiload_and_validate_configconfig_module_name-env_var-schemanone-keysnone-uppercasefalse), that is used for fetching multiple variables at once and overriding declared module variables, will try to get variable from one extra\nsource, the local JSON configuration file in the following order:\n\n**Consul**  \n⬇️   \n**config.json**  \n⬇️  \n**environment**  \n⬇️  \nApp\n\nWith the same *override* logic.\n\n\n## Consul settings\n\n**Confgetti** uses a [python-consul](https://python-consul.readthedocs.io/en/latest/) package for communication with Consul\'s KV store.\n\nDefault connection settings are:\n\nhost: **consul**  \nport: **8500**  \nscheme: **http**  \n\nConnection settings can be configured in **2** ways:\n\n### Through environment variables\n\n#### Available environment variables:\n\n```\nCONSUL_HOST - default: \'consul\'\nCONSUL_PORT - default: 8500\nCONSUL_SCHEME - default: \'http\'\nCONSUL_TOKEN - default: None\nCONSUL_DC - default: None\n```\n\n#### Example\n\nYou have running consul instance on `my_host`, port `7500`, and on secured `https`,\nall you need to set the following environment variables:\n\n```\nCONSUL_HOST=my_host\nCONSUL_PORT=7500\nCONSUL_SCHEME=https\n``` \n\nAnd you do not have to pass any configuration dictionary when initializing Confgetti, because\nit will read settings from the environment.\n\n```python\n# my_app/config.py\nfrom Confgetti import get_variable\n\ncgtti = Confgetti()\n\nmy_variable = cgtti.get_variable(\'MY_VARIABLE\')\n```\n\n> **!!!ALERT:** This is only way of configuration for `load_and_validate_config` shorthand use.\n\n### Upon initialization\n\nWhen initializing **Confgetti** instance you can pass a dictionary with **Consnul** connection settings.\n\n#### Default configuration dictionary\n\n```python\nconsul_settings = {\n    \'host\': \'consul\',\n    \'port\': 8500,\n    \'scheme\': \'http\',\n    \'token\': None,\n    \'dc\': None\n}\n```\n\n#### Example\n\nYou have running consul instance on `my_host`, port `7500`, and on secured `https`:\n\n```python\n# my_app/config.py\nfrom Confgetti import get_variable\n\ncgtti = Confgetti({\n    \'host\': \'my_host\'\n    \'port\': 7500,\n    \'scheme\': \'https\'\n})\n\nmy_variable = cgtti.get_variable(\'MY_VARIABLE\')\n```\n\n## API\n\n### Shorthand methods\n\n> **!!!ALERT:** If you are using shorthand functions, make sure that you have provided **Consul** connection settings via environment variables!\n \n#### confgetti.get_variables(path, keys, use_env=True, use_consul=True))\n\nThis is shorthand function for `confgetti.Confgetti.get_variables`.\nUsed for fetching multiple variables at once from **Consul** or environment. Returns dictionary for fetched variables.\n\n**Arguments:**  \n- **path**(optional) - Namespace of variable location inside **Consul** KV storage. By default as `None`, it looks to root of KV for the variable.\n- **keys** - list of keys under which variables are defined. This can be a plain `list` of names, or `dict` where the key is the key name of variable and value type of value that should be returned. By default, variables are returned as a **string**. Available types: `str`, `int`, `bool`, `float`, `dict`. For example:\n\n    ```python\n    my_variables_dict = cgtti.get_variables(keys=[\n        \'MY_VARIABLE\',\n        \'YOUR_VARIABLE\',\n        \'OUR_VARIABLE\'\n    ])\n    ```\n\n    or\n\n    ```python\n    my_variables_dict = cgtti.get_variables(keys={\n        \'MY_VARIABLE\': str,\n        \'YOUR_VARIABLE\': bool,\n        \'OUR_VARIABLE\': int\n    })\n    ```\n\n- **use_env**(optional) - should **Confgetti** look to environment or no?  \n- **use_consul**(optional) - should **Confgetti** look to **Consul** or no?\n\n\n**Example:**  \n```python\nfrom confgetti import get_variables\n\nconvert_dict = {\n    "my_variable": str,\n    "your_variable": int,\n    "my_bool": bool,\n    "my_env_variable": str\n}\n\nvariables = get_variables(path=\'AWESOMEAPP\', keys=convert_dict)\n```\n\n#### confgetti.load_and_validate_config(config_module_name, env_var, schema=None, keys=None, uppercase=False)\n\nUsed for overriding current module variables. Usually it is used with [voluptuous.Schema](http://alecthomas.github.io/voluptuous/docs/_build/html/index.html) as `schema` argument for validation, but can be used without it, or with some custom method.\n\n**Arguments:**  \n- **config_module_name** - Usually `__name__` variable from current configuration file  \n- **env_var** - Prefix of variables in the environment, the namespace of variables location in **CONSUL** and key under which `JSON` configuration path is stored in the environment. See the example for better understanding.  \n- **schema**(optional) - Pass custom method here that should return `dict` of variables which will be glued to module later. Usually used with [voluptuous.Schema](http://alecthomas.github.io/voluptuous/docs/_build/html/index.html).  \n- **keys**(optional) - variable names list or dict with the desired type. If you do not pass this, and you pass `voluptuous.Schema` under `schema` argument, the method will return variables declared dict passed to `Schema` instance.  \n- **uppercase**(optional) - By default, variables are *glued* to the module in lowercase. If this is passed as `True`, variables will be *glued* in uppercase.  \n\n**Example:**  \n\n- *variables must be defined under `MY_APP` namespace in consul*\n- *if `configuration.json` is used, environment variable `MY_APP` must be set with a path to the file\n\n```python\n# my_app/config.py\nfrom voluptuous import Schema, Coerce\nfrom confgetti import load_and_validate_config\n\n\nmy_variable = None\nyour_variable = None\n\n_schema = Schema({\n    "my_variable": str,\n    "your_variable": Coerce(int)\n})\n\n\nload_and_validate_config(__name__, \'MY_APP\', _schema)\n\n```\n```python\n# my_app/some_logic.py\nfrom .config import my_variable, your_variable\n\nprint(my_variable)  # should be a string and not None\nprint(your_variable  # should be an integer and not None\n\n```\n\n### confgetti.Confgetti(consul_config=None, prepare_consul=True)\n\nConfgetti intialization accepts two optional arguments, both refering to communication\nwith Consul.\n\n**Arguments:** \n- **consul_config**(optional) - if dictionary with connection settings is passed client for communication with consul is initialized wit these settings.\n\n    **Example:**  \n\n    ```python\n    from confgetti import Confgetti\n\n    cgtti = Confgetti({\n        \'host\': \'localhost\'\n    })\n    ```\n\n- **prepare_consul**(optional) - if `False` is passed, connection to Consul instance is not prepared, and Confgetti will only seek for variables in environment.\n\n    **Example:**  \n\n    ```python\n    from confgetti import Confgetti\n\n    cgtti = Confgetti(prepare_consul=False)\n\n    cggti.get_variable(\'my_variable\') # only environment lookup\n    ```\n\n#### confgetti.Confgetti.get_variable(key, path=None, fallback=None, convert_to=None, use_env=True, use_consul=True)\n\nUsed for fetching single variable from **Consul** or environment. Returns single variable value\n\n**Arguments:**  \n- **key** - key under which variable is defined  \n- **path**(optional) - Namespace of variable location insike **Consul** KV storage. By default as `None` it looks to root of KV for variable.  \n- **fallback**(optional) - what is returned if variable is not found  \n- **convert_to**(optional) - should variable be converted to certain type? If type is passed, **Confgetti** tries to convert variable to passed type. By default, variable is returend as **string**. Available types: `str`, `int`, `bool`, `float`, `dict`\n- **use_env**(optional) - should **Confgetti** look to environment or no?  \n- **use_consul**(optional) - should **Confgetti** look to **Consul** or no?  \n\n**Example:**  \n\n```python\nfrom confgetti import Confgetti\n\ncgtti = Confgetti()\n\nmy_variable = cgtti.get_variable(\'my_variable\')\n```\n\n#### confgetti.Confgetti.get_variables(path=None, keys=None, use_env=True, use_consul=True)\n\nThis is internal method that is used for [get_variables](#confgettiget_variablespath-keys-use_envtrue-use_consultrue) shorthand. Arguments and logic is exactly the same.\n\n**Example:**  \n\n```python\nfrom confgetti import Confgetti\n\ncgtti = Confgetti()\n\nmy_variable = cgtti.get_variables([\'my_variable\', \'your_variable\'])\n```\n\n## Demos\n\nCheck [demos](https://gl.sds.rocks/GDNI/confgetti/tree/feature/documentation/demos) folder for example usages as simple python scripts.\n\n## Developer Notes\n\n### Releasing new version\n\nThis repository has automatic deployment configured via CI runner.\n\n**Steps for automatic deployment to `Styria`\'s PyPI server:**  \n1. Update `CHANGELOG.md` with future version release notes\n2. Commit and push changelog to `master` branch\n3. From the root of repository run `bumpversion patch`\n4. Push changes that command in the previous step has made to the repo\n5. Wait for `CI/CD` pipeline `deploy` step is finished, done!\n',
    'author': 'Styria Digital Development',
    'author_email': 'development@styria.dev',
    'maintainer': None,
    'maintainer_email': None,
    'url': None,
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
