{"id":16728772,"url":"https://github.com/hukkin/typenv","last_synced_at":"2025-10-31T22:03:17.511Z","repository":{"id":39887285,"uuid":"227465311","full_name":"hukkin/typenv","owner":"hukkin","description":"Typed environment variable parsing for Python","archived":false,"fork":false,"pushed_at":"2025-10-06T17:45:32.000Z","size":147,"stargazers_count":17,"open_issues_count":2,"forks_count":6,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-08T00:38:05.328Z","etag":null,"topics":["configuration","dotenv","environment-variables","python","twelve-factor"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hukkin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-11T21:39:11.000Z","updated_at":"2025-06-17T05:28:56.000Z","dependencies_parsed_at":"2023-12-18T19:07:50.040Z","dependency_job_id":"0c6b1474-ac7e-4af3-9994-c37626846a98","html_url":"https://github.com/hukkin/typenv","commit_stats":null,"previous_names":["hukkinj1/typenv"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/hukkin/typenv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukkin%2Ftypenv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukkin%2Ftypenv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukkin%2Ftypenv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukkin%2Ftypenv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hukkin","download_url":"https://codeload.github.com/hukkin/typenv/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hukkin%2Ftypenv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006561,"owners_count":26084128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","dotenv","environment-variables","python","twelve-factor"],"created_at":"2024-10-12T23:11:39.442Z","updated_at":"2025-10-11T07:04:41.778Z","avatar_url":"https://github.com/hukkin.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://github.com/hukkin/typenv/actions/workflows/tests.yaml/badge.svg?branch=master)](https://github.com/hukkin/typenv/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)\n[![codecov.io](https://codecov.io/gh/hukkin/typenv/branch/master/graph/badge.svg)](https://codecov.io/gh/hukkin/typenv)\n[![PyPI version](https://img.shields.io/pypi/v/typenv)](https://pypi.org/project/typenv)\n\n# typenv\n\n\u003c!--- Don't edit the version line below manually. Let bump2version do it for you. --\u003e\n\n\u003e Version 0.2.0\n\n\u003e Typed environment variable parsing for Python\n\n**Table of Contents** *generated with [mdformat-toc](https://github.com/hukkin/mdformat-toc)*\n\n\u003c!-- mdformat-toc start --slug=github --maxlevel=6 --minlevel=2 --\u003e\n\n- [Background](#background)\n- [Installing](#installing)\n- [Usage](#usage)\n  - [Basics](#basics)\n  - [Supported types](#supported-types)\n  - [Default values](#default-values)\n  - [Name prefixes](#name-prefixes)\n  - [Name character set](#name-character-set)\n  - [Name uppercasing](#name-uppercasing)\n  - [Validation](#validation)\n  - [Reading from a `.env` file](#reading-from-a-env-file)\n  - [Dumping parsed values](#dumping-parsed-values)\n- [Acknowledgments](#acknowledgments)\n\n\u003c!-- mdformat-toc end --\u003e\n\n## Background\u003ca name=\"background\"\u003e\u003c/a\u003e\n\nTypenv does environment variable parsing with an API almost identical to the excellent [environs](https://github.com/sloria/environs).\nThere are a few reasons why typenv might be preferred:\n\n- Type annotated typecast functions: type checkers are able to understand types of parsed environment variables.\n- More flexible prefix manipulation of environment variable names.\n- Validation of environment variable names.\n- Optional automatic uppercasing of environment variable names.\n- Ability to generate a .env.example that shows expected types of environment variables.\n- Less dependencies. No [marshmallow](https://github.com/marshmallow-code/marshmallow) required.\n\n## Installing\u003ca name=\"installing\"\u003e\u003c/a\u003e\n\nInstalling from PyPI repository (https://pypi.org/project/typenv):\n\n```bash\npip install typenv\n```\n\n## Usage\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n### Basics\u003ca name=\"basics\"\u003e\u003c/a\u003e\n\nSet environment variables:\n\n```bash\nexport NAME='Harry Potter'\nexport AGE=14\nexport IS_WIZARD=true\nexport PATRONUM_SUCCESS_RATE=0.92\nexport BANK_BALANCE=134599.01\nexport LUCKY_NUMBERS=7,3,11\nexport EXTRA_DETAILS='{\"friends\": [\"Hermione\", \"Ron\"]}'\nexport FAVORITE_COLOR=0x7f0909\n```\n\nParse the values in Python:\n\n```python\nfrom typenv import Env\n\nenv = Env()\n\nNAME = env.str(\"NAME\")  # =\u003e \"Harry Potter\"\nAGE = env.int(\"AGE\")  # =\u003e 14\nIS_WIZARD = env.bool(\"IS_WIZARD\")  # =\u003e True\nPATRONUM_SUCCESS_RATE = env.float(\"PATRONUM_SUCCESS_RATE\")  # =\u003e 0.92\nBANK_BALANCE = env.decimal(\"BANK_BALANCE\")  # =\u003e decimal.Decimal(\"134599.01\")\nLUCKY_NUMBERS = env.list(\"LUCKY_NUMBERS\", subcast=int)  # =\u003e [7, 3, 11]\nEXTRA_DETAILS = env.json(\"EXTRA_DETAILS\")  # =\u003e {\"friends\": [\"Hermione\", \"Ron\"]}\nFAVORITE_COLOR = env.bytes(\"FAVORITE_COLOR\", encoding=\"hex\")  # =\u003e b\"\\x7f\\t\\t\"\n\n# Optional settings must have a default value\nIS_DEATH_EATER = env.bool(\"IS_DEATH_EATER\", default=False)  # =\u003e False\n```\n\n### Supported types\u003ca name=\"supported-types\"\u003e\u003c/a\u003e\n\nThe types supported by typenv are:\n\n- `env.str`\n- `env.int`\n- `env.bool`\n- `env.float`\n- `env.decimal`\n- `env.list`\n  - Takes a `subcast` keyword argument for casting list items to one of `str`, `int` , `bool`, `float` or `decimal.Decimal`\n- `env.json`\n- `env.bytes`\n  - Takes an `encoding` keyword argument for indicating how the bytes are encoded.\n    For now only `hex` is supported.\n\n### Default values\u003ca name=\"default-values\"\u003e\u003c/a\u003e\n\nNormally, if an environment variable is not found, typenv raises an exception.\nIf a default value is provided, however, that will be returned instead of raising.\n\n```python\nfrom typenv import Env\n\nenv = Env()\n\nBOOL = env.bool(\"NON_EXISTING_NAME\", default=False)  # =\u003e False\nLIST = env.list(\"NON_EXISTING_NAME\", default=[\"a\", \"b\"])  # =\u003e [\"a\", \"b\"]\nOPTIONAL_INT = env.int(\"NON_EXISTING_NAME\", default=None)  # =\u003e None\n```\n\n### Name prefixes\u003ca name=\"name-prefixes\"\u003e\u003c/a\u003e\n\n```bash\nexport FLASK_HOST=127.0.0.1\nexport FLASK_PORT=44144\n```\n\n```python\nfrom typenv import Env\n\nenv = Env()\n\n# Explicitly prefixing variable names works, but repeats itself\n# (especially given more environment variables and nested prefixes).\nHOST = env.str(\"FLASK_HOST\")  # =\u003e \"127.0.0.1\"\nPORT = env.int(\"FLASK_PORT\")  # =\u003e 44144\n\n# This reads the same variables as above, and can be a nice way of\n# reducing repetition and expressing structure. Note that it is possible\n# to have nested `with` statements.\nwith env.prefixed(\"FLASK_\"):\n    HOST = env.str(\"HOST\")  # =\u003e \"127.0.0.1\"\n    PORT = env.int(\"PORT\")  # =\u003e 44144\n\n# For more control, one can mutate `env.prefix` (of type list[str])\n# directly. Note that if an exception occurs reading the environment\n# variables, then `env.prefix` will not be reset to its initial value,\n# which is something that the `with` statement would take care of.\nenv.prefix.append(\"FLASK_\")\nHOST = env.str(\"HOST\")  # =\u003e \"127.0.0.1\"\nPORT = env.int(\"PORT\")  # =\u003e 44144\nenv.prefix.pop()\n```\n\n### Name character set\u003ca name=\"name-character-set\"\u003e\u003c/a\u003e\n\nTypenv validates environment variable names.\nBy default, the set of allowed characters includes upper case ASCII letters, digits and the underscore (`_`).\n\nThe set of allowed characters can be configured:\n\n```python\nfrom typenv import Env\n\nenv = Env(allowed_chars=\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n```\n\n### Name uppercasing\u003ca name=\"name-uppercasing\"\u003e\u003c/a\u003e\n\n```bash\nexport UPPER_CASE_NAME=true\n```\n\n```python\nfrom typenv import Env\n\n# Environment variable names in type cast methods will automatically be upper\n# cased when `upper=True` is set here.\nenv = Env(upper=True)\n\nNAME = env.bool(\"upper_casE_Name\")\n```\n\n### Validation\u003ca name=\"validation\"\u003e\u003c/a\u003e\n\n```bash\nexport NAME='Harry Potter'\nexport AGE=14\n```\n\n```python\nfrom typenv import Env\n\nenv = Env()\n\n# A single validator function\nNAME = env.str(\"NAME\", validate=lambda n: n.startswith(\"Harry\"))\n\n\n# A validator function can signal error by raising an exception\ndef is_positive(num):\n    if num \u003c= 0:\n        raise Exception(\"Number is not positive\")\n\n\n# A validator function can alternatively return `False` to signal an error\ndef is_less_than_thousand(num):\n    if num \u003e= 1000:\n        return False\n    return True\n\n\n# Multiple validator functions can be passed as an iterable of callables\nAGE = env.int(\"AGE\", validate=(is_positive, is_less_than_thousand))\n```\n\n### Reading from a `.env` file\u003ca name=\"reading-from-a-env-file\"\u003e\u003c/a\u003e\n\nWhile developing, it is often useful to read environment variables from a file.\nTypenv supports this via the `Env.read_end()` method.\nThe method will look for a file (by default) named `.env` in current working directory\nand import environment variables from it.\nIf a file is not found,\nthe method will walk up in the directory tree until a file is found or the root directory is reached.\nThe method returns a boolean that is `True` if a file is found.\n\nGiven a `.env` file in current working directory with the following content\n\n```sh\nSOME_VAR='some value'\n```\n\nThe following code will be able to read and parse the value\n\n```python\nfrom typenv import Env\n\nenv = Env()\nenv.read_env()\n\nSOME_VAR = env.str(\"SOME_VAR\")  # =\u003e \"some value\"\n```\n\n### Dumping parsed values\u003ca name=\"dumping-parsed-values\"\u003e\u003c/a\u003e\n\n```bash\nexport SOME_STR=blaablaa\nexport SOME_INT=99\n```\n\n```python\nfrom typenv import Env, ParsedValue\n\nenv = Env()\n\nSOME_STR = env.str(\"SOME_STR\")\nSOME_INT = env.int(\"SOME_INT\")\n\nassert env.dump() == {\n    \"SOME_INT\": ParsedValue(value=99, type=\"int\", optional=False),\n    \"SOME_STR\": ParsedValue(value=\"blaablaa\", type=\"str\", optional=False),\n}\n```\n\n## Acknowledgments\u003ca name=\"acknowledgments\"\u003e\u003c/a\u003e\n\nThe public API of this library is almost an exact copy of [environs](https://github.com/sloria/environs),\nwhich is based on [envparse](https://github.com/rconradharris/envparse) and [django-environ](https://github.com/joke2k/django-environ).\nCredit for the interface goes to the authors of those libraries.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhukkin%2Ftypenv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhukkin%2Ftypenv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhukkin%2Ftypenv/lists"}