envcon


Nameenvcon JSON
Version 1.8.3 PyPI version JSON
download
home_pagehttps://github.com/neriat/envcon
Summaryenvcon: environment variables parsing using type-hints
upload_time2024-01-31 18:12:44
maintainerNeria
docs_urlNone
authorNeria
requires_python>=3.8.1,<4.0.0
licenseMIT
keywords environment variables configuration 12factor twelve-factor
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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"
}
        
Elapsed time: 0.18473s