Package: envcon
envcon: easy environment variables parsingEnvcon-  easy environment variables parsing.Envcon allows you to store configuration separated from your code, likeThe Twelve-Factor Appsuggests.Envcon heavily leaned on python type-hints and makes configuration simple and declerative.ContentsFeaturesInstallUsageBasic usagePrefixOptionalFreezing ClassAnother SourceSupported typesCastingReading .env filesWhy...?Why environment variables?Why not os.environ?LicenseFeaturesSimple usageType-castingParse.envfile as well as environment variables (os.environ)Default valuesPrefixhuman readable errorsfreezing classes after injectionInstallpip install envconUsageAssuming these environment variables are set (or written in .env file)exportMONGO_USER=myMongoUserexportMONGO_PASSWORD=shh_its_a_secretexportSECRET_NUMBER=0.42exportONE_TO_TEN=1,2,3,4,5,6,7,8,9,10exportIS_ENABLED=trueexportURL=http://www.google.comBasic usagefromenvconimportenvironment_configuration@environment_configurationclassConfigs:SECRET_NUMBER:floatIS_ENABLED:boolONE_TO_TEN:list[int]# on python 3.8 use List[int] (from typing import List)print(Configs.SECRET_NUMBER)# 0,42print(type(Configs.SECRET_NUMBER))# <class 'float'>print(Configs.IS_ENABLED)# Trueprint(type(Configs.IS_ENABLED))# <class 'bool'>print(type(Configs.ONE_TO_TEN[0]))# <class 'int'>Prefixfromenvconimportenvironment_configuration@environment_configuration(prefix="MONGO_")classMongoConfiguration:USER:strPASSWORD:strprint(MongoConfiguration.USER)# myMongoUserOptionalAll variables without default value are considered required.
Optional annotation suggests non-required variable and default set toNone.fromtypingimportOptionalfromenvconimportenvironment_configuration@environment_configurationclassConfiguration:NON_EXISTING_ENV_VER:Optional[int]print(type(Configuration.NON_EXISTING_ENV_VER))# <class 'NoneType'>Freezing ClassBy default, after injection, modifications of fields is prevented.
This feature is inspired by@dataclassfrozen flag.
This behaviour can be overridden, or explicitly described:fromenvconimportenvironment_configuration@environment_configuration(frozen=False)classMyConfiguration:SOME_CONFIGURATION:str@environment_configurationclassAnotherConfiguration:SOME_CONFIGURATION:strMyConfiguration.SOME_CONFIGURATION="yey"print(MyConfiguration.SOME_CONFIGURATION)# yeyAnotherConfiguration.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 allowedAnother SourceWhat if I want different source other than my.envfile /os.environ?fromenvconimportconfigurationmy_config_dict={"MONGO_USER":"myUser","MONGO_PASSWORD":"myPassword",}@configuration(prefix="MONGO_",source=my_config_dict)classMongoConfiguration:USER:strPASSWORD:strprint(MongoConfiguration.USER)# myUserExceptionsfromenvconimportenvironment_configuration@environment_configurationclassConfigurationA:NON_EXISTING_ENV_VER:int# LookupError: NON_EXISTING_ENV_VER is not an environment variable, nor has default valueSupported typesThe following types hints are supportedBuiltins and fromtyping:strboolintfloatlistlist[T] # >= python 3.9. T = str/bool/int/floatdictListList[T]DictOptional[T] # T = str/bool/int/float/dict/list/list[T]Castingint floatSimple casting.i,f="42","4.2"int(i)float(i)boolThe following case-insensitive strings are considered True and False.True:1yyestrueFalse"" (empty string)0nnofalseAnything but these values raises an exception.Its strongly suggested sticking with simple lowercase "false/true" and not something like fALsE.listList is parsed as comma separated values.If sub-type is provided (e.g.list[int]) each element will be converted as well.dictJSON string which loaded using json.loads()Reading.envfilesBy default, envcon will parse your.envfile.
This feature is useful for local development..env will not override your environment variables.You can turn this feature off:@environment_configuration(include_dot_env_file=False)classMyConfigClass:...Why...?Why environment variables?SeeThe 12-factor Appsection onconfiguration.Why notos.environ?Basically, because this:classConfig: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 valueOPTIONAL_URL=os.environ.get("OPTIONAL_URL",None)OPTIONAL_NUMBER=int(os.environ.get("OPTIONAL_NUMBER","0"))orNoneNUMS_LIST=[int(i)foriinos.environ["NUMS_LIST"].splite(",")]NUMS_LIST_WITH_DEFAULT=[int(i)foriinos.environ.get("NUMS_LIST","1,2,3").splite(",")]will simply turn into this:fromtypingimportOptional,List@environment_configurationclassConfig:MAX_CONNECTION:int=42TIMEOUT:float=4.2MY_PASSWORD:strOPTIONAL_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 youcast environment variables to the correct typespecify required environment variablesdefine default valuesparse list and dictLicenseMIT licensed.