# envcon: easy environment variables parsing
[![Downloads](https://static.pepy.tech/personalized-badge/envcon?period=total&units=none&left_color=grey&right_color=yellow&left_text=Downloads)](https://pepy.tech/project/envcon)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9-blue)](https://www.python.org)
[![Pypi](https://img.shields.io/pypi/v/envcon)](https://pypi.org)
[![MIT license](https://img.shields.io/github/license/neriat/envcon)](https://lbesson.mit-license.org/)
**Envcon** - easy environment variables parsing.
Envcon allows you to store configuration separated from your code, like
[The Twelve-Factor App](https://12factor.net/config) suggests.
Envcon heavily leaned on python type-hints and makes configuration simple and declerative.
## Contents
- [Features](#features)
- [Install](#install)
- [Usage](#usage)
- [Basic usage](#basic-usage)
- [Prefix](#prefix)
- [Optional](#optional)
- [Freezing Class](#freezing-class)
- [Another Source](#another-source)
- [Supported types](#supported-types)
- [Casting](#casting)
- [Reading .env files](#reading-env-files)
- [Why...?](#why)
- [Why environment variables?](#why-environment-variables)
- [Why not os.environ?](#why-not-osenviron)
- [License](#license)
## Features
- Simple usage
- Type-casting
- Parse `.env` file as well as environment variables (`os.environ`)
- Default values
- Prefix
- human readable errors
- freezing classes after injection
## Install
pip install envcon
## Usage
Assuming these environment variables are set (or written in .env file)
```bash
export MONGO_USER=myMongoUser
export MONGO_PASSWORD=shh_its_a_secret
export SECRET_NUMBER=0.42
export ONE_TO_TEN=1,2,3,4,5,6,7,8,9,10
export IS_ENABLED=true
export URL=http://www.google.com
```
### Basic usage
```python3
from envcon import environment_configuration
@environment_configuration
class Configs:
SECRET_NUMBER: float
IS_ENABLED: bool
ONE_TO_TEN: list[int] # on python 3.8 use List[int] (from typing import List)
print(Configs.SECRET_NUMBER) # 0,42
print(type(Configs.SECRET_NUMBER)) # <class 'float'>
print(Configs.IS_ENABLED) # True
print(type(Configs.IS_ENABLED)) # <class 'bool'>
print(type(Configs.ONE_TO_TEN[0])) # <class 'int'>
```
### Prefix
```python3
from envcon import environment_configuration
@environment_configuration(prefix="MONGO_")
class MongoConfiguration:
USER: str
PASSWORD: str
print(MongoConfiguration.USER) # myMongoUser
```
### Optional
All variables without default value are considered required.
Optional annotation suggests non-required variable and default set to `None`.
```python3
from typing import Optional
from envcon import environment_configuration
@environment_configuration
class Configuration:
NON_EXISTING_ENV_VER: Optional[int]
print(type(Configuration.NON_EXISTING_ENV_VER)) # <class 'NoneType'>
```
### Freezing Class
By default, after injection, modifications of fields is prevented.
This feature is inspired by `@dataclass` frozen flag.
This behaviour can be overridden, or explicitly described:
```python3
from envcon import environment_configuration
@environment_configuration(frozen=False)
class MyConfiguration:
SOME_CONFIGURATION: str
@environment_configuration
class AnotherConfiguration:
SOME_CONFIGURATION: str
MyConfiguration.SOME_CONFIGURATION = "yey"
print(MyConfiguration.SOME_CONFIGURATION) # yey
AnotherConfiguration.SOME_CONFIGURATION = "oh"
# Traceback (most recent call last):
# File "<input>", line 1, in <module>
# File "example.py", line 10, in __setattr__
# raise FrozenClassAttributesError()
# envcon.metaclasses.FrozenClassAttributesError: Class is frozen. modifying attributes is not allowed
```
### Another Source
What if I want different source other than my `.env` file / `os.environ`?
```python3
from envcon import configuration
my_config_dict = {
"MONGO_USER": "myUser",
"MONGO_PASSWORD": "myPassword",
}
@configuration(prefix="MONGO_", source=my_config_dict)
class MongoConfiguration:
USER: str
PASSWORD: str
print(MongoConfiguration.USER) # myUser
```
### Exceptions
```python3
from envcon import environment_configuration
@environment_configuration
class ConfigurationA:
NON_EXISTING_ENV_VER: int
# LookupError: NON_EXISTING_ENV_VER is not an environment variable, nor has default value
```
## Supported types
The following types hints are supported
Builtins and from `typing`:
- `str`
- `bool`
- `int`
- `float`
- `list`
- `list[T] # >= python 3.9. T = str/bool/int/float`
- `dict`
- `List`
- `List[T]`
- `Dict`
- `Optional[T] # T = str/bool/int/float/dict/list/list[T]`
### Casting
#### int float
Simple casting.
```python3
i, f = "42", "4.2"
int(i)
float(i)
```
#### bool
The following case-insensitive strings are considered True and False.
- True:
- 1
- y
- yes
- true
- False
- "" (empty string)
- 0
- n
- no
- false
Anything but these values raises an exception.
Its strongly suggested sticking with simple lowercase "false/true" and not something like fALsE.
#### list
List is parsed as comma separated values.
If sub-type is provided (e.g. `list[int]`) each element will be converted as well.
#### dict
JSON string which loaded using json.loads()
## Reading `.env` files
By default, envcon will parse your `.env` file.
This feature is useful for local development.
.env will not override your environment variables.
You can turn this feature off:
```python3
@environment_configuration(include_dot_env_file=False)
class MyConfigClass:
...
```
## Why...?
### Why environment variables?
See [The 12-factor App](http://12factor.net/config) section on
[configuration](http://12factor.net/config).
### Why not `os.environ`?
Basically, because this:
```python3
class Config:
MAX_CONNECTION = int(os.environ.get("MAX_CONNECTION", "42"))
TIMEOUT = float(os.environ.get("TIMEOUT", "4.2"))
MY_PASSWORD = os.environ["MY_PASSWORD"] #required w/o default value
OPTIONAL_URL = os.environ.get("OPTIONAL_URL", None)
OPTIONAL_NUMBER = int(os.environ.get("OPTIONAL_NUMBER", "0")) or None
NUMS_LIST = [int(i) for i in os.environ["NUMS_LIST"].splite(",")]
NUMS_LIST_WITH_DEFAULT = [int(i) for i in os.environ.get("NUMS_LIST", "1,2,3").splite(",")]
```
will simply turn into this:
```python3
from typing import Optional, List
@environment_configuration
class Config:
MAX_CONNECTION: int = 42
TIMEOUT: float = 4.2
MY_PASSWORD: str
OPTIONAL_URL: Optional[str]
OPTIONAL_NUMBER: Optional[int]
NUMS_LIST: list[int] # in python 3.8 use List[int]
NUMS_LIST_WITH_DEFAULT: list[int] = [1, 2, 3]
```
envcon will help you
- cast environment variables to the correct type
- specify required environment variables
- define default values
- parse list and dict
## License
MIT licensed.
Raw data
{
"_id": null,
"home_page": "https://github.com/neriat/envcon",
"name": "envcon",
"maintainer": "Neria",
"docs_url": null,
"requires_python": ">=3.8.1,<4.0.0",
"maintainer_email": "me@neria.dev",
"keywords": "environment,variables,configuration,12factor,twelve-factor",
"author": "Neria",
"author_email": "me@neria.dev",
"download_url": "https://files.pythonhosted.org/packages/41/d1/63003f4bba7c872918a5534a2948944fa654f425b942f1fcba5daed397d8/envcon-1.8.3.tar.gz",
"platform": null,
"description": "# envcon: easy environment variables parsing\n\n[![Downloads](https://static.pepy.tech/personalized-badge/envcon?period=total&units=none&left_color=grey&right_color=yellow&left_text=Downloads)](https://pepy.tech/project/envcon)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Python](https://img.shields.io/badge/python-3.8%20%7C%203.9-blue)](https://www.python.org)\n[![Pypi](https://img.shields.io/pypi/v/envcon)](https://pypi.org)\n[![MIT license](https://img.shields.io/github/license/neriat/envcon)](https://lbesson.mit-license.org/)\n\n**Envcon** - easy environment variables parsing. \nEnvcon allows you to store configuration separated from your code, like \n[The Twelve-Factor App](https://12factor.net/config) suggests. \nEnvcon heavily leaned on python type-hints and makes configuration simple and declerative. \n\n## Contents\n\n- [Features](#features)\n- [Install](#install)\n- [Usage](#usage)\n - [Basic usage](#basic-usage)\n - [Prefix](#prefix)\n - [Optional](#optional)\n - [Freezing Class](#freezing-class)\n - [Another Source](#another-source)\n- [Supported types](#supported-types)\n - [Casting](#casting)\n- [Reading .env files](#reading-env-files)\n- [Why...?](#why)\n - [Why environment variables?](#why-environment-variables)\n - [Why not os.environ?](#why-not-osenviron)\n- [License](#license)\n\n## Features\n\n- Simple usage\n- Type-casting\n- Parse `.env` file as well as environment variables (`os.environ`)\n- Default values\n- Prefix\n- human readable errors\n- freezing classes after injection\n\n## Install\n\n pip install envcon\n\n## Usage\n\nAssuming these environment variables are set (or written in .env file)\n\n```bash\nexport MONGO_USER=myMongoUser\nexport MONGO_PASSWORD=shh_its_a_secret\nexport SECRET_NUMBER=0.42\nexport ONE_TO_TEN=1,2,3,4,5,6,7,8,9,10\nexport IS_ENABLED=true\nexport URL=http://www.google.com\n```\n\n### Basic usage\n\n```python3\nfrom envcon import environment_configuration\n\n@environment_configuration\nclass Configs:\n SECRET_NUMBER: float\n IS_ENABLED: bool\n ONE_TO_TEN: list[int] # on python 3.8 use List[int] (from typing import List) \n\nprint(Configs.SECRET_NUMBER) # 0,42\nprint(type(Configs.SECRET_NUMBER)) # <class 'float'>\nprint(Configs.IS_ENABLED) # True\nprint(type(Configs.IS_ENABLED)) # <class 'bool'>\nprint(type(Configs.ONE_TO_TEN[0])) # <class 'int'> \n```\n\n### Prefix\n\n```python3\nfrom envcon import environment_configuration\n\n@environment_configuration(prefix=\"MONGO_\")\nclass MongoConfiguration:\n USER: str\n PASSWORD: str\n\nprint(MongoConfiguration.USER) # myMongoUser\n \n```\n\n### Optional\nAll variables without default value are considered required.\nOptional annotation suggests non-required variable and default set to `None`.\n\n```python3\nfrom typing import Optional\nfrom envcon import environment_configuration\n\n@environment_configuration\nclass Configuration:\n NON_EXISTING_ENV_VER: Optional[int]\n\nprint(type(Configuration.NON_EXISTING_ENV_VER)) # <class 'NoneType'>\n \n```\n\n\n### Freezing Class\nBy default, after injection, modifications of fields is prevented.\nThis feature is inspired by `@dataclass` frozen flag.\nThis behaviour can be overridden, or explicitly described: \n\n```python3\nfrom envcon import environment_configuration\n\n@environment_configuration(frozen=False)\nclass MyConfiguration:\n SOME_CONFIGURATION: str\n\n\n@environment_configuration\nclass AnotherConfiguration:\n SOME_CONFIGURATION: str\n\n\nMyConfiguration.SOME_CONFIGURATION = \"yey\"\nprint(MyConfiguration.SOME_CONFIGURATION) # yey\nAnotherConfiguration.SOME_CONFIGURATION = \"oh\"\n# Traceback (most recent call last):\n# File \"<input>\", line 1, in <module>\n# File \"example.py\", line 10, in __setattr__\n# raise FrozenClassAttributesError()\n# envcon.metaclasses.FrozenClassAttributesError: Class is frozen. modifying attributes is not allowed\n```\n\n\n### Another Source\nWhat if I want different source other than my `.env` file / `os.environ`? \n```python3\nfrom envcon import configuration\n\nmy_config_dict = {\n \"MONGO_USER\": \"myUser\",\n \"MONGO_PASSWORD\": \"myPassword\",\n}\n\n@configuration(prefix=\"MONGO_\", source=my_config_dict)\nclass MongoConfiguration:\n USER: str\n PASSWORD: str\n\nprint(MongoConfiguration.USER) # myUser\n \n```\n\n### Exceptions\n\n```python3\nfrom envcon import environment_configuration\n\n@environment_configuration\nclass ConfigurationA:\n NON_EXISTING_ENV_VER: int\n\n# LookupError: NON_EXISTING_ENV_VER is not an environment variable, nor has default value\n \n```\n\n## Supported types\n\nThe following types hints are supported\n\nBuiltins and from `typing`:\n- `str`\n- `bool`\n- `int`\n- `float`\n- `list`\n- `list[T] # >= python 3.9. T = str/bool/int/float`\n- `dict` \n- `List`\n- `List[T]`\n- `Dict`\n- `Optional[T] # T = str/bool/int/float/dict/list/list[T]`\n\n### Casting\n\n#### int float\nSimple casting. \n```python3\ni, f = \"42\", \"4.2\"\nint(i)\nfloat(i)\n```\n\n#### bool\nThe following case-insensitive strings are considered True and False. \n- True:\n - 1\n - y\n - yes\n - true\n- False\n - \"\" (empty string)\n - 0\n - n\n - no\n - false\n\nAnything but these values raises an exception. \nIts strongly suggested sticking with simple lowercase \"false/true\" and not something like fALsE.\n\n#### list\nList is parsed as comma separated values. \nIf sub-type is provided (e.g. `list[int]`) each element will be converted as well.\n\n#### dict\nJSON string which loaded using json.loads()\n\n\n## Reading `.env` files\nBy default, envcon will parse your `.env` file.\nThis feature is useful for local development. \n.env will not override your environment variables. \n\nYou can turn this feature off: \n```python3\n@environment_configuration(include_dot_env_file=False)\nclass MyConfigClass:\n ...\n```\n\n\n## Why...?\n\n### Why environment variables?\n\nSee [The 12-factor App](http://12factor.net/config) section on\n[configuration](http://12factor.net/config).\n\n### Why not `os.environ`?\nBasically, because this:\n```python3\nclass Config:\n MAX_CONNECTION = int(os.environ.get(\"MAX_CONNECTION\", \"42\"))\n TIMEOUT = float(os.environ.get(\"TIMEOUT\", \"4.2\"))\n MY_PASSWORD = os.environ[\"MY_PASSWORD\"] #required w/o default value\n OPTIONAL_URL = os.environ.get(\"OPTIONAL_URL\", None)\n OPTIONAL_NUMBER = int(os.environ.get(\"OPTIONAL_NUMBER\", \"0\")) or None\n NUMS_LIST = [int(i) for i in os.environ[\"NUMS_LIST\"].splite(\",\")]\n NUMS_LIST_WITH_DEFAULT = [int(i) for i in os.environ.get(\"NUMS_LIST\", \"1,2,3\").splite(\",\")]\n```\n\nwill simply turn into this:\n```python3\nfrom typing import Optional, List\n\n@environment_configuration\nclass Config:\n MAX_CONNECTION: int = 42\n TIMEOUT: float = 4.2\n MY_PASSWORD: str\n OPTIONAL_URL: Optional[str]\n OPTIONAL_NUMBER: Optional[int]\n NUMS_LIST: list[int] # in python 3.8 use List[int]\n NUMS_LIST_WITH_DEFAULT: list[int] = [1, 2, 3]\n```\n\nenvcon will help you\n\n- cast environment variables to the correct type\n- specify required environment variables\n- define default values\n- parse list and dict\n\n## License\n\nMIT licensed. ",
"bugtrack_url": null,
"license": "MIT",
"summary": "envcon: environment variables parsing using type-hints",
"version": "1.8.3",
"project_urls": {
"Homepage": "https://github.com/neriat/envcon",
"Repository": "https://github.com/neriat/envcon"
},
"split_keywords": [
"environment",
"variables",
"configuration",
"12factor",
"twelve-factor"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "61cc47337f8d2df16142b6c69bfd3e26d3775e1b69b52beeedb237432b48e2c5",
"md5": "0f02f5e175354509ca034f366a962ccc",
"sha256": "eaf1edc528633709c4c5bec465d3052ef53bc33e5dcd0312c8af802275e63bb1"
},
"downloads": -1,
"filename": "envcon-1.8.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0f02f5e175354509ca034f366a962ccc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8.1,<4.0.0",
"size": 10264,
"upload_time": "2024-01-31T18:12:43",
"upload_time_iso_8601": "2024-01-31T18:12:43.476741Z",
"url": "https://files.pythonhosted.org/packages/61/cc/47337f8d2df16142b6c69bfd3e26d3775e1b69b52beeedb237432b48e2c5/envcon-1.8.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "41d163003f4bba7c872918a5534a2948944fa654f425b942f1fcba5daed397d8",
"md5": "5e3812e9f47fe56dbf5440ab378284ff",
"sha256": "47da0658579d899d5a951fdde6d8de58fc41010d2f1ee7fe00894d75a0f5784b"
},
"downloads": -1,
"filename": "envcon-1.8.3.tar.gz",
"has_sig": false,
"md5_digest": "5e3812e9f47fe56dbf5440ab378284ff",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8.1,<4.0.0",
"size": 8185,
"upload_time": "2024-01-31T18:12:44",
"upload_time_iso_8601": "2024-01-31T18:12:44.864463Z",
"url": "https://files.pythonhosted.org/packages/41/d1/63003f4bba7c872918a5534a2948944fa654f425b942f1fcba5daed397d8/envcon-1.8.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-01-31 18:12:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "neriat",
"github_project": "envcon",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "envcon"
}