From ea1f49cf76aafd5fd7b5fb1ee0f1114057c01130 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 14:58:41 -0400 Subject: [PATCH 1/7] Add dependencies for docs https://github.com/squidfunk/mkdocs-material https://squidfunk.github.io/mkdocs-material/ --- poetry.lock | 296 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 296 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index f246ba1..c5bbd17 100644 --- a/poetry.lock +++ b/poetry.lock @@ -117,6 +117,20 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" +[[package]] +name = "ghp-import" +version = "2.0.1" +description = "Copy your docs directly to the gh-pages branch." +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["twine", "markdown", "flake8"] + [[package]] name = "identify" version = "2.2.10" @@ -128,6 +142,22 @@ python-versions = ">=3.6.1" [package.extras] license = ["editdistance-s"] +[[package]] +name = "importlib-metadata" +version = "4.6.1" +description = "Read metadata from Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] + [[package]] name = "iniconfig" version = "1.1.1" @@ -150,6 +180,39 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] plugins = ["setuptools"] +[[package]] +name = "jinja2" +version = "3.0.1" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markdown" +version = "3.3.4" +description = "Python implementation of Markdown." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.6" + [[package]] name = "mccabe" version = "0.6.1" @@ -158,6 +221,63 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for ๐Ÿ." +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "mkdocs" +version = "1.2.1" +description = "Project documentation with Markdown." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +click = ">=3.3" +ghp-import = ">=1.0" +importlib-metadata = ">=3.10" +Jinja2 = ">=2.10.1" +Markdown = ">=3.2.1" +mergedeep = ">=1.3.4" +packaging = ">=20.5" +PyYAML = ">=3.10" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] + +[[package]] +name = "mkdocs-material" +version = "7.1.9" +description = "A Material Design theme for MkDocs" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +markdown = ">=3.2" +mkdocs = ">=1.1" +mkdocs-material-extensions = ">=1.0" +Pygments = ">=2.4" +pymdown-extensions = ">=7.0" + +[[package]] +name = "mkdocs-material-extensions" +version = "1.0.1" +description = "Extension pack for Python Markdown." +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +mkdocs-material = ">=5.0.0" + [[package]] name = "mypy" version = "0.910" @@ -261,6 +381,25 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "pygments" +version = "2.9.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "pymdown-extensions" +version = "8.2" +description = "Extension pack for Python Markdown." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +Markdown = ">=3.2" + [[package]] name = "pyparsing" version = "2.4.7" @@ -320,6 +459,17 @@ pytest = ">=5.0" [package.extras] dev = ["pre-commit", "tox", "pytest-asyncio"] +[[package]] +name = "python-dateutil" +version = "2.8.1" +description = "Extensions to the standard Python datetime module" +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + [[package]] name = "pyyaml" version = "5.4.1" @@ -328,6 +478,17 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyyaml = "*" + [[package]] name = "regex" version = "2021.7.6" @@ -378,10 +539,33 @@ six = ">=1.9.0,<2" docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"] testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)", "xonsh (>=0.9.16)"] +[[package]] +name = "watchdog" +version = "2.1.3" +description = "Filesystem events monitoring" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +watchmedo = ["PyYAML (>=3.10)", "argh (>=0.24.1)"] + +[[package]] +name = "zipp" +version = "3.5.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] + [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "30811414ae694bb3c0eb4f06c51342f20f7028b0b90cd4195bbae8dd9bed7d6b" +content-hash = "44f4d164ca3965eeee63a893d2a9a15424c5098cb1bb5b77c6881983c5147181" [metadata.files] appdirs = [ @@ -478,10 +662,17 @@ flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] +ghp-import = [ + {file = "ghp-import-2.0.1.tar.gz", hash = "sha256:753de2eace6e0f7d4edfb3cce5e3c3b98cd52aadb80163303d1d036bda7b4483"}, +] identify = [ {file = "identify-2.2.10-py2.py3-none-any.whl", hash = "sha256:18d0c531ee3dbc112fa6181f34faa179de3f57ea57ae2899754f16a7e0ff6421"}, {file = "identify-2.2.10.tar.gz", hash = "sha256:5b41f71471bc738e7b586308c3fca172f78940195cb3bf6734c1e66fdac49306"}, ] +importlib-metadata = [ + {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"}, + {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"}, +] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, @@ -490,10 +681,70 @@ isort = [ {file = "isort-5.9.1-py3-none-any.whl", hash = "sha256:8e2c107091cfec7286bc0f68a547d0ba4c094d460b732075b6fba674f1035c0c"}, {file = "isort-5.9.1.tar.gz", hash = "sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56"}, ] +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, +] +markdown = [ + {file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c"}, + {file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49"}, +] +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] +mergedeep = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] +mkdocs = [ + {file = "mkdocs-1.2.1-py3-none-any.whl", hash = "sha256:11141126e5896dd9d279b3e4814eb488e409a0990fb638856255020406a8e2e7"}, + {file = "mkdocs-1.2.1.tar.gz", hash = "sha256:6e0ea175366e3a50d334597b0bc042b8cebd512398cdd3f6f34842d0ef524905"}, +] +mkdocs-material = [ + {file = "mkdocs-material-7.1.9.tar.gz", hash = "sha256:5a2fd487f769f382a7c979e869e4eab1372af58d7dec44c4365dd97ef5268cb5"}, + {file = "mkdocs_material-7.1.9-py2.py3-none-any.whl", hash = "sha256:92c8a2bd3bd44d5948eefc46ba138e2d3285cac658900112b6bf5722c7d067a5"}, +] +mkdocs-material-extensions = [ + {file = "mkdocs-material-extensions-1.0.1.tar.gz", hash = "sha256:6947fb7f5e4291e3c61405bad3539d81e0b3cd62ae0d66ced018128af509c68f"}, + {file = "mkdocs_material_extensions-1.0.1-py3-none-any.whl", hash = "sha256:d90c807a88348aa6d1805657ec5c0b2d8d609c110e62b9dce4daf7fa981fa338"}, +] mypy = [ {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, @@ -555,6 +806,14 @@ pyflakes = [ {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] +pygments = [ + {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, + {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, +] +pymdown-extensions = [ + {file = "pymdown-extensions-8.2.tar.gz", hash = "sha256:b6daa94aad9e1310f9c64c8b1f01e4ce82937ab7eb53bfc92876a97aca02a6f4"}, + {file = "pymdown_extensions-8.2-py3-none-any.whl", hash = "sha256:141452d8ed61165518f2c923454bf054866b85cf466feedb0eb68f04acdc2560"}, +] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, @@ -571,6 +830,10 @@ pytest-mock = [ {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, ] +python-dateutil = [ + {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, + {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, +] pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, @@ -594,6 +857,10 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] +pyyaml-env-tag = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] regex = [ {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, @@ -654,3 +921,30 @@ virtualenv = [ {file = "virtualenv-20.4.7-py2.py3-none-any.whl", hash = "sha256:2b0126166ea7c9c3661f5b8e06773d28f83322de7a3ff7d06f0aed18c9de6a76"}, {file = "virtualenv-20.4.7.tar.gz", hash = "sha256:14fdf849f80dbb29a4eb6caa9875d476ee2a5cf76a5f5415fa2f1606010ab467"}, ] +watchdog = [ + {file = "watchdog-2.1.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9628f3f85375a17614a2ab5eac7665f7f7be8b6b0a2a228e6f6a2e91dd4bfe26"}, + {file = "watchdog-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:acc4e2d5be6f140f02ee8590e51c002829e2c33ee199036fcd61311d558d89f4"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85b851237cf3533fabbc034ffcd84d0fa52014b3121454e5f8b86974b531560c"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a12539ecf2478a94e4ba4d13476bb2c7a2e0a2080af2bb37df84d88b1b01358a"}, + {file = "watchdog-2.1.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6fe9c8533e955c6589cfea6f3f0a1a95fb16867a211125236c82e1815932b5d7"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d9456f0433845e7153b102fffeb767bde2406b76042f2216838af3b21707894e"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fd8c595d5a93abd441ee7c5bb3ff0d7170e79031520d113d6f401d0cf49d7c8f"}, + {file = "watchdog-2.1.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0bcfe904c7d404eb6905f7106c54873503b442e8e918cc226e1828f498bdc0ca"}, + {file = "watchdog-2.1.3-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bf84bd94cbaad8f6b9cbaeef43080920f4cb0e61ad90af7106b3de402f5fe127"}, + {file = "watchdog-2.1.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b8ddb2c9f92e0c686ea77341dcb58216fa5ff7d5f992c7278ee8a392a06e86bb"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8805a5f468862daf1e4f4447b0ccf3acaff626eaa57fbb46d7960d1cf09f2e6d"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:3e305ea2757f81d8ebd8559d1a944ed83e3ab1bdf68bcf16ec851b97c08dc035"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_i686.whl", hash = "sha256:431a3ea70b20962e6dee65f0eeecd768cd3085ea613ccb9b53c8969de9f6ebd2"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:e4929ac2aaa2e4f1a30a36751160be391911da463a8799460340901517298b13"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:201cadf0b8c11922f54ec97482f95b2aafca429c4c3a4bb869a14f3c20c32686"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:3a7d242a7963174684206093846537220ee37ba9986b824a326a8bb4ef329a33"}, + {file = "watchdog-2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:54e057727dd18bd01a3060dbf5104eb5a495ca26316487e0f32a394fd5fe725a"}, + {file = "watchdog-2.1.3-py3-none-win32.whl", hash = "sha256:b5fc5c127bad6983eecf1ad117ab3418949f18af9c8758bd10158be3647298a9"}, + {file = "watchdog-2.1.3-py3-none-win_amd64.whl", hash = "sha256:44acad6f642996a2b50bb9ce4fb3730dde08f23e79e20cd3d8e2a2076b730381"}, + {file = "watchdog-2.1.3-py3-none-win_ia64.whl", hash = "sha256:0bcdf7b99b56a3ae069866c33d247c9994ffde91b620eaf0306b27e099bd1ae0"}, + {file = "watchdog-2.1.3.tar.gz", hash = "sha256:e5236a8e8602ab6db4b873664c2d356c365ab3cac96fbdec4970ad616415dd45"}, +] +zipp = [ + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, +] diff --git a/pyproject.toml b/pyproject.toml index 13ba5f5..bac7d26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ python = "^3.8" black = {version = "21.6b0", allow-prereleases = true} flake8 = "^3.8" isort = "^5.8" +mkdocs-material = "^7" mypy = ">=0.900" pre-commit = "^2.11" pytest = "^6.2" From 69d2bd5d60e7715705bed7d1bfd885fe32868c3b Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:00:19 -0400 Subject: [PATCH 2/7] Create MkDocs site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://squidfunk.github.io/mkdocs-material/creating-your-site/ ```text โฏ mkdocs new . INFO - Writing config file: ./mkdocs.yml INFO - Writing initial docs: ./docs/index.md ``` --- docs/index.md | 17 +++++++++++++++++ mkdocs.yml | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..327a4ed --- /dev/null +++ b/docs/index.md @@ -0,0 +1,17 @@ +# Welcome to MkDocs + +For full documentation visit [mkdocs.org](https://www.mkdocs.org). + +## Commands + +- `mkdocs new [dir-name]` - Create a new project. +- `mkdocs serve` - Start the live-reloading docs server. +- `mkdocs build` - Build the documentation site. +- `mkdocs -h` - Print help message and exit. + +## Project layout + + mkdocs.yml # The configuration file. + docs/ + index.md # The documentation homepage. + ... # Other markdown pages, images and other files. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..d2ba56c --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,2 @@ +site_name: My Docs +site_url: https://example.com/ From 02fb162ce7f4aeef4a6d34884a18db5e6703f509 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:01:56 -0400 Subject: [PATCH 3/7] Configure MkDocs site https://squidfunk.github.io/mkdocs-material/creating-your-site/#configuration `edit_uri` - `edit_uri: ""` disables the "Edit on GitHub" button https://squidfunk.github.io/mkdocs-material/setup/adding-a-git-repository/ `markdown_extensions` - `pymdownx.inlinehilite`: code block highlighting https://squidfunk.github.io/mkdocs-material/reference/code-blocks/ `theme` - colors: `primary` is header bar, `accent` is within page text, media queries allow for light/dark theme based on browser preference https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/ - `font: false`: don't load Google fonts https://squidfunk.github.io/mkdocs-material/setup/changing-the-fonts/ - `icon`: refers to icons bundled with mkdocs-material https://squidfunk.github.io/mkdocs-material/setup/changing-the-logo-and-icons/ Add Vercel config: https://vercel.com/docs/configuration Add Prettier config: It appears that MkDocs requires four-space tabs in order to properly render Markdown lists. An additional Prettier config will be added to specify the `tabWidth`. --- docs/.prettierrc | 3 +++ mkdocs.yml | 42 ++++++++++++++++++++++++++++++++++++++++-- vercel.json | 4 ++++ 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 docs/.prettierrc create mode 100644 vercel.json diff --git a/docs/.prettierrc b/docs/.prettierrc new file mode 100644 index 0000000..0a02bce --- /dev/null +++ b/docs/.prettierrc @@ -0,0 +1,3 @@ +{ + "tabWidth": 4 +} diff --git a/mkdocs.yml b/mkdocs.yml index d2ba56c..a776628 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,2 +1,40 @@ -site_name: My Docs -site_url: https://example.com/ +edit_uri: "" +markdown_extensions: + - admonition + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - toc: + permalink: true + toc_depth: 3 +nav: + - "index.md" +repo_name: br3ndonland/fastenv +repo_url: https://github.com/br3ndonland/fastenv +site_name: fastenv docs +site_url: https://fastenv.bws.bio +theme: + features: + - header.autohide + - navigation.instant + - navigation.top + font: false + icon: + logo: octicons/gear-24 + repo: octicons/mark-github-16 + name: material + palette: + - media: "(prefers-color-scheme: dark)" + accent: deep orange + primary: deep orange + scheme: slate + toggle: + icon: material/weather-night + name: Switch to light mode + - media: "(prefers-color-scheme: light)" + accent: deep orange + primary: deep orange + scheme: default + toggle: + icon: material/weather-sunny + name: Switch to dark mode diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..20041ca --- /dev/null +++ b/vercel.json @@ -0,0 +1,4 @@ +{ + "cleanUrls": true, + "trailingSlash": false +} From e669e13666207387ce1db479874f087a46f820fb Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:05:40 -0400 Subject: [PATCH 4/7] Update docs homepage with info from README - Align info in README and docs/index.md - Use gear instead of wrench for settings icon --- README.md | 24 ++++++++++++++++-------- docs/index.md | 31 +++++++++++++++++++------------ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 3e08942..4929108 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# fastenv +# โš™๏ธ fastenv ๐Ÿš€ -๐Ÿ”ง _Unified settings management for FastAPI and beyond_ ๐Ÿš€ +_Unified settings management for FastAPI and beyond_ [![PyPI](https://img.shields.io/pypi/v/fastenv?color=success)](https://pypi.org/project/fastenv/) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) @@ -13,17 +13,25 @@ ## Description -[Environment variables](https://en.wikipedia.org/wiki/Environment_variable) are key-value pairs provided to the operating system with syntax like `VARIABLE_NAME=value`. Collections of environment variables are stored in files commonly named _.env_ and called "dotenv" files. The Python standard library provides tools for reading environment variables, such as `os.getenv("VARIABLE_NAME")`, but these tools only read environment variables that have already been loaded. Additional logic is therefore needed to load environment variables before they can be read by Python. +[Environment variables](https://en.wikipedia.org/wiki/Environment_variable) are key-value pairs provided to the operating system with syntax like `VARIABLE_NAME=value`. Collections of environment variables are stored in files commonly named _.env_ and called "dotenv" files. The Python standard library `os` module provides tools for reading environment variables, such as `os.getenv("VARIABLE_NAME")`, but only handles strings, and doesn't include tools for file I/O. Additional logic is therefore needed to load environment variables from files before they can be read by Python, and to convert variables from strings to other Python types. This project aims to: -- **Unify settings management for FastAPI**. [Uvicorn](https://www.uvicorn.org/), [Starlette](https://www.starlette.io/config/), and _[pydantic](https://pydantic-docs.helpmanual.io/usage/settings/)_ each have their own ways of loading environment variables and configuring application settings. This means that, when [configuring a FastAPI application](https://fastapi.tiangolo.com/advanced/settings/), there are at least three different settings management tools available, each with their own pros and cons. It would be helpful to address the limitations of each of these options, potentially providing a similar, improved API for each one. - **Replace the aging [python-dotenv](https://github.com/theskumar/python-dotenv) project** with a similar, but more intuitive API, and modern syntax and tooling. -- **Read settings from TOML**. [It's all about _pyproject.toml_ now](https://snarky.ca/what-the-heck-is-pyproject-toml/). [Poetry](https://python-poetry.org/) has pushed [PEP 517](https://www.python.org/dev/peps/pep-0517/) build tooling and [PEP 518](https://www.python.org/dev/peps/pep-0518/) build requirements forward, and even `setuptools` has [come around](https://setuptools.readthedocs.io/en/latest/build_meta.html). Why donโ€™t we use the metadata from our _pyproject.toml_ files in our Python APIs? - **Integrate with object storage**. Dotenv files are commonly kept in object storage like AWS S3, but none of the tools mentioned above integrate with object storage clients. +- **Implement asynchronous file I/O**. Downloading, reading, and writing files can be done asynchronously with the help of packages like [AnyIO](https://github.com/agronholm/anyio) and [aioaws](https://github.com/samuelcolvin/aioaws). +- **Read settings from TOML**. [It's all about _pyproject.toml_ now](https://snarky.ca/what-the-heck-is-pyproject-toml/). [Poetry](https://python-poetry.org/) has pushed [PEP 517](https://www.python.org/dev/peps/pep-0517/) build tooling and [PEP 518](https://www.python.org/dev/peps/pep-0518/) build requirements forward, and [even `setuptools` has come around](https://setuptools.readthedocs.io/en/latest/build_meta.html). Why donโ€™t we use the metadata from our _pyproject.toml_ files in our Python APIs? +- **Unify settings management for FastAPI**. [Uvicorn](https://www.uvicorn.org/), [Starlette](https://www.starlette.io/config/), and _[pydantic](https://pydantic-docs.helpmanual.io/usage/settings/)_ each have their own ways of loading environment variables and configuring application settings. This means that, when [configuring a FastAPI application](https://fastapi.tiangolo.com/advanced/settings/), there are at least three different settings management tools available, each with their own pros and cons. It would be helpful to address the limitations of each of these options, potentially providing a similar, improved API for each one. + +The source code is 100% type-annotated and unit-tested. + +## Documentation + +Documentation is built with [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/), deployed on [Vercel](https://vercel.com/), and available at [fastenv.bws.bio](https://fastenv.bws.bio) and [fastenv.vercel.app](https://fastenv.vercel.app). -Let's see how this goes! +[Vercel build configuration](https://vercel.com/docs/build-step): -## Further information +- Build command: `python3 -m pip install 'mkdocs-material>=7.0.0,<=8.0.0' && mkdocs build --site-dir public` +- Output directory: `public` (default) -See [CONTRIBUTING.md](.github/CONTRIBUTING.md). +[Vercel site configuration](https://vercel.com/docs/configuration) is specified in _vercel.json_. diff --git a/docs/index.md b/docs/index.md index 327a4ed..e0bfb89 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,24 @@ -# Welcome to MkDocs +# โš™๏ธ fastenv ๐Ÿš€ -For full documentation visit [mkdocs.org](https://www.mkdocs.org). +_Unified settings management for FastAPI and beyond_ -## Commands +[![PyPI](https://img.shields.io/pypi/v/fastenv?color=success)](https://pypi.org/project/fastenv/) +[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://black.readthedocs.io/en/stable/) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![ci](https://github.com/br3ndonland/fastenv/workflows/ci/badge.svg)](https://github.com/br3ndonland/fastenv/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/br3ndonland/fastenv/branch/main/graph/badge.svg?token=WDNHES5OYR)](https://codecov.io/gh/br3ndonland/fastenv) -- `mkdocs new [dir-name]` - Create a new project. -- `mkdocs serve` - Start the live-reloading docs server. -- `mkdocs build` - Build the documentation site. -- `mkdocs -h` - Print help message and exit. +## Description -## Project layout +[Environment variables](https://en.wikipedia.org/wiki/Environment_variable) are key-value pairs provided to the operating system with syntax like `VARIABLE_NAME=value`. Collections of environment variables are stored in files commonly named _.env_ and called "dotenv" files. The Python standard library `os` module provides tools for reading environment variables, such as `os.getenv("VARIABLE_NAME")`, but only handles strings, and doesn't include tools for file I/O. Additional logic is therefore needed to load environment variables from files before they can be read by Python, and to convert variables from strings to other Python types. - mkdocs.yml # The configuration file. - docs/ - index.md # The documentation homepage. - ... # Other markdown pages, images and other files. +This project aims to: + +- **Replace the aging [python-dotenv](https://github.com/theskumar/python-dotenv) project** with a similar, but more intuitive API, and modern syntax and tooling. +- **Integrate with object storage**. Dotenv files are commonly kept in object storage like AWS S3, but none of the tools mentioned above integrate with object storage clients. +- **Implement asynchronous file I/O**. Downloading, reading, and writing files can be done asynchronously with the help of packages like [AnyIO](https://github.com/agronholm/anyio) and [aioaws](https://github.com/samuelcolvin/aioaws). +- **Read settings from TOML**. [It's all about _pyproject.toml_ now](https://snarky.ca/what-the-heck-is-pyproject-toml/). [Poetry](https://python-poetry.org/) has pushed [PEP 517](https://www.python.org/dev/peps/pep-0517/) build tooling and [PEP 518](https://www.python.org/dev/peps/pep-0518/) build requirements forward, and [even `setuptools` has come around](https://setuptools.readthedocs.io/en/latest/build_meta.html). Why donโ€™t we use the metadata from our _pyproject.toml_ files in our Python APIs? +- **Unify settings management for FastAPI**. [Uvicorn](https://www.uvicorn.org/), [Starlette](https://www.starlette.io/config/), and _[pydantic](https://pydantic-docs.helpmanual.io/usage/settings/)_ each have their own ways of loading environment variables and configuring application settings. This means that, when [configuring a FastAPI application](https://fastapi.tiangolo.com/advanced/settings/), there are at least three different settings management tools available, each with their own pros and cons. It would be helpful to address the limitations of each of these options, potentially providing a similar, improved API for each one. + +The source code is 100% type-annotated and unit-tested. From f6346ac1e5d9a81351d05663c33331076021e488 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:06:33 -0400 Subject: [PATCH 5/7] Add favicon from Material for MkDocs https://squidfunk.github.io/mkdocs-material/setup/changing-the-logo-and-icons/ https://github.com/squidfunk/mkdocs-material/blob/HEAD/docs/assets/favicon.png --- docs/assets/images/favicon.png | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/assets/images/favicon.png diff --git a/docs/assets/images/favicon.png b/docs/assets/images/favicon.png new file mode 100644 index 0000000..21f252e --- /dev/null +++ b/docs/assets/images/favicon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:58f13cf9b640a1e7d128722b964bdd884079b6e4e90897219abaef1faf0fb16f +size 1995 From 940dcb5e3a32513ae42bee7202236ece66b88472 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:08:32 -0400 Subject: [PATCH 6/7] Add placeholder for environment variable docs --- docs/environment.md | 1 + mkdocs.yml | 1 + 2 files changed, 2 insertions(+) create mode 100644 docs/environment.md diff --git a/docs/environment.md b/docs/environment.md new file mode 100644 index 0000000..1ed0fb1 --- /dev/null +++ b/docs/environment.md @@ -0,0 +1 @@ +# Environment variables diff --git a/mkdocs.yml b/mkdocs.yml index a776628..592b3e6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ markdown_extensions: toc_depth: 3 nav: - "index.md" + - "environment.md" repo_name: br3ndonland/fastenv repo_url: https://github.com/br3ndonland/fastenv site_name: fastenv docs From 05836f1155e934ad61e60d49fa22fc5e2fb88138 Mon Sep 17 00:00:00 2001 From: Brendon Smith Date: Tue, 6 Jul 2021 15:09:45 -0400 Subject: [PATCH 7/7] Add docs comparing fastenv with other projects --- docs/comparisons.md | 173 ++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 174 insertions(+) create mode 100644 docs/comparisons.md diff --git a/docs/comparisons.md b/docs/comparisons.md new file mode 100644 index 0000000..07cbb4e --- /dev/null +++ b/docs/comparisons.md @@ -0,0 +1,173 @@ +# Comparisons + +## environ + +The [Python standard library `os` module](https://docs.python.org/3/library/os.html) offers operating system utilities, including `os.environ` for working with environment variables. `os.environ` is instantiated from `os._Environ`, which is an implementation of `collections.abc.MutableMapping`. The source code for `collections.abc.MutableMapping` can be found in _[python/cpython/Lib/\_collections_abc.py](https://github.com/python/cpython/blob/0a7dcbdb13f1f2ab6e76e1cff47e80fb263f5da0/Lib/_collections_abc.py#L875-L959)_. As explained in the docstring for `MutableMapping`: + +> A MutableMapping is a generic container for associating key/value pairs. +> +> This class provides concrete generic implementations of all methods except for `__getitem__`, `__setitem__`, `__delitem__`, `__iter__`, and `__len__`. + +Subclasses of `collections.abc.MutableMapping`, such as `os._Environ`, need to provide implementations of each of those methods. + +Type stubs for `collections.abc.MutableMapping` are located in [python/typeshed/stdlib/typing.pyi](https://github.com/python/typeshed/blob/14add7520bb2f6dd468338c50fe94a5ac9a6ae0c/stdlib/typing.pyi#L453-L480). These are the type stubs for the standard library `typing` module, which [aliases `collections.abc.MutableMapping`](https://github.com/python/cpython/blob/0a7dcbdb13f1f2ab6e76e1cff47e80fb263f5da0/Lib/typing.py#L1670). + +See the [`os` module docs](https://docs.python.org/3/library/os.html) and the [docs on mapping types](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict) for more information. + +## environs + +- [environs](https://github.com/sloria/environs) is a project with useful features for managing _.env_ files and application settings. Its API was inspired by [django-environ](https://github.com/joke2k/django-environ) and [envparse](https://github.com/rconradharris/envparse). The maintainers [considered](https://github.com/rconradharris/envparse/issues/12) merging environs and envparse into one project. +- The _[README](https://github.com/sloria/environs#why)_ compares environs to `os.environ`, and offers a concise justification of the additional features that environs provides. +- While it separates config from code, as suggested by the [twelve-factor app](https://12factor.net/config) methodology, it also combines environment variables and settings. Environment variables and their type-casted setting counterparts are combined into the same model. +- Initially, the source code wasn't consistently type-annotated ([sloria/environs#186](https://github.com/sloria/environs/issues/186)), but based on its [PEP 561](https://www.python.org/dev/peps/pep-0561/) marker file, it appears to be type-annotated now. +- Depends on marshmallow and python-dotenv ([sloria/environs#196](https://github.com/sloria/environs/issues/196)), so it inherits the limitations described in the [python-dotenv section](#python-dotenv). + +## _pydantic_ + +### Settings configuration + +_pydantic_ offers a [`BaseSettings` model](https://pydantic-docs.helpmanual.io/usage/settings/). Settings class attributes are automatically read from environment variables, and the full power of _pydantic_ data parsing/validation can be applied. + + +!!!example "Simple _pydantic_ settings model" + + ```py + import os + + from pydantic import BaseSettings + + os.environ["BOOLEAN_SETTING"] = "false" + os.environ["INTEGER_SETTING"] = "123" + os.environ["STRING_SETTING"] = "example_value" + + + class SimpleSettings(BaseSettings): + boolean_setting: bool = True + integer_setting: int = 000 + string_setting: str = "default_value" + + + print(SimpleSettings().dict()) + # {"boolean_setting": False, "integer_setting": 123, "string_setting": "example_value"} + ``` + +### File I/O + +- In addition to reading environment variables that have already been set, _pydantic_ can load environment variables from _.env_ files. However, it depends on python-dotenv to load _.env_ files, so it inherits the limitations described in the [python-dotenv section](#python-dotenv). +- If no _.env_ file is found at the path provided, _pydantic_ will fail silently, rather than raising a `FileNotFoundError`. This can lead to issues if applications depend on environment variables that _pydantic_ fails to load. + +## python-decouple + +- [python-decouple](https://github.com/henriquebastos/python-decouple) loads settings from _.env_ and _.ini_ files. Its supported configuration file format appears to be inspired by [Foreman](https://github.com/ddollar/foreman), a Ruby configuration management tool. +- Variables are set with calls to instances of its `AutoConfig` class, which offers type-casting to convert strings to other Python types: `config("DEBUG", cast=bool)`. +- Source code is not type-annotated. +- Classes inherit from `object`, and therefore require their own implementations of methods already present in other data structures. This could be easily eliminated by inheriting from a mapping data structure such as `collections.abc.MutableMapping`. +- Continues supporting Python 2 after its [end-of-life](https://www.python.org/doc/sunset-python-2/), and has not been tested on the latest versions of Python 3. + +## python-dotenv + +- [python-dotenv](https://github.com/theskumar/python-dotenv) is a package for loading _.env_ files and setting environment variables. It was [started](https://github.com/theskumar/python-dotenv/commit/5fc02b7303e8854243970e12564f2433da7a1f7f) by Django co-creator Jacob Kaplan-Moss in 2013, and was originally called django-dotenv. It is used by [Uvicorn](https://www.uvicorn.org/) and _[pydantic](https://pydantic-docs.helpmanual.io/usage/settings/)_, and suggested in the [FastAPI docs](https://fastapi.tiangolo.com/advanced/settings/). +- Its primary data structure, `dotenv.main.DotEnv`, inherits from `object`. As a result, it requires its own mapping mathods (`dict`, `get_key`, `set_key`, `unset_key`) that could be easily eliminated by inheriting from a mapping data structure such as `collections.abc.MutableMapping`. +- Other methods have confusing, counter-intuitive APIs. For example, the `load_dotenv()` function is supposed to "Parse a _.env_ file and then load all the variables found as environment variables," according to its docstring. However, the function always returns `True`, even if no _.env_ file is found or no environment variables are set, because of `DotEnv.set_as_environment_variables()`. Furthermore, this confusing behavior is not documented, because, as the maintainer [commented](https://github.com/theskumar/python-dotenv/issues/164#issuecomment-494750043), "The return value of `load_dotenv` is undocumented as I was planning to do something useful with it, but could not settle down to one." +- Maintainers have not been receptive to improvements. See [theskumar/python-dotenv#263](https://github.com/theskumar/python-dotenv/pull/263) for context. +- Continues supporting Python 2 after its [end-of-life](https://www.python.org/doc/sunset-python-2/), so it has to use [Python 2 type comments](https://mypy.readthedocs.io/en/stable/python2.html) and other legacy cruft. + +## Starlette + +### Settings configuration + +Starlette offers a [config module](https://www.starlette.io/config/) for working with environment variables and settings, which takes inspiration from [python-decouple](https://github.com/henriquebastos/python-decouple). Settings are created by calling a Starlette `Config` instance. Constant notation is suggested for settings (`UPPERCASE_WITH_UNDERSCORES`). + + +!!!example + + ```py + import starlette.config + + config = starlette.config.Config() + FOO_CONSTANT = config("FOO_VARIABLE", cast=str, default="baz") + ``` + +Starlette will look for an environment variable `FOO_VARIABLE`. For example, setting `FOO_VARIABLE=bar` in the environment will result in `FOO_CONSTANT = "bar"`. If the environment variable is unset, the result will be `FOO_CONSTANT = "baz"`. The `cast` keyword argument allows use of Starlette type-casting. + +### Type-casting + +Type-casting provides improvements over some aspects of the standard library. For example, Starlette intuitively casts Boolean values, unlike the Python built-in `bool` type: + + +!!!example "Type-casting with `starlette.config`" + + ```py + โฏ python3 + + >>> bool("false") + True + >>> import starlette.config + >>> config = starlette.config.Config() + >>> config("BOOLEAN_SETTING", cast=bool, default="false") + False + ``` + +### One-way configuration preference + +Starlette has an opinionated one-way configuration preference (environment variables -> Starlette `Config` instance). To avoid modifying environment variables after they have been loaded into a Starlette `Config` instance, [Starlette provides its own mapping onto `os.environ`](https://www.starlette.io/config/#reading-or-modifying-the-environment) (`starlette.config.environ`), which will raise an exception on attempts to change an environment variable that has already been loaded into a corresponding setting on a `Config` instance. + +While it is useful to have `starlette.config.environ` synchronized with `os.environ`, the downside is that `starlette.config.environ` contains local environment variables loaded from `os.environ`, and therefore wouldn't typically be dumped to a file. + +It is also important to note that the one-way preference will only be enforced when using `starlette.environ`. If a variable is changed using `os.environ`, it will be updated correspondingly in `starlette.environ`, but no exception will be raised, and the `config` value will not be updated. + + +!!!example "Environment variables with `starlette.config`" + + ```py + โฏ python3 + + >>> import os + >>> import starlette.config + >>> os.environ.get("FOO_VARIABLE") + >>> starlette.config.environ["FOO_VARIABLE"] = "bar" + >>> os.environ.get("FOO_VARIABLE") + 'bar' + >>> config = starlette.config.Config() + >>> FOO_CONSTANT = config("FOO_VARIABLE", cast=str, default="baz") + >>> FOO_CONSTANT + 'bar' + >>> starlette.config.environ["FOO_VARIABLE"] = "foo" + Traceback (most recent call last): + File ".venv/lib/python3.9/site-packages/starlette/config.py", line 26, in __setitem__ + raise EnvironError( + starlette.config.EnvironError: Attempting to set environ['FOO_VARIABLE'], + but the value has already been read. + >>> os.environ["FOO_VARIABLE"] = "foo" + >>> os.environ["FOO_VARIABLE"] + 'foo' + >>> starlette.config.environ["FOO_VARIABLE"] + 'foo' + >>> FOO_CONSTANT + 'bar' + ``` + +### File I/O + +- Starlette `Config` accepts an `env_file` keyword argument, which should point to a _.env_ file on disk. It loads the file with the synchronous `open()` built-in function. +- If no _.env_ file is found at the path provided by `Config(env_file)`, Starlette will fail silently, rather than raising a `FileNotFoundError`. This can lead to issues if applications depend on environment variables that Starlette fails to load. +- Starlette `Config` does not support multiple _.env_ files ([encode/starlette#432](https://github.com/encode/starlette/issues/432)). + +### The future of `starlette.config` + +From [encode/starlette#432](https://github.com/encode/starlette/issues/432#issuecomment-471617467): + +> I guess we may actually end up pulling the configuration stuff out into a strictly seperate package (or indeed even just pointing at python-decouple - since it's the same style). +> +> With 12-factor config you really should have a fairly small set of environment. (Eg. the database configuration should just be a single URL.) +> +> What we _will_ want to do though is provide really good examples of how to arrange things sensibly, so that eg. you have a project that has a `settings.py` that includes a whole bunch of project configuration, and which you can arrange into seperate bits, and demonstrate clearly how the _environment_ should be a small set of variables, but the project _settings_ may be more comprehensive. +> +> We could perfectly well also point to other configuration-manangement packages that're out there as alternatives. + +## Other + +- [dotenvy](https://github.com/chickenzord/dotenvy) can load _.env_ files and apply a type schema to the variables. It does not appear to be actively maintained. +- [env](https://github.com/MasterOdin/env) does not add much beyond `os.environ` (does not even load files), has not been released since 2012, and does not appear to be actively maintained. +- [envparse](https://github.com/rconradharris/envparse) offers features for parsing and type-casting environment variables, but does not appear to be actively maintained. +- [python-configurator](https://github.com/guitarpoet/python-configurator) depends on python-dotenv and appears to emphasize TOML settings files. diff --git a/mkdocs.yml b/mkdocs.yml index 592b3e6..39d81d7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,6 +10,7 @@ markdown_extensions: nav: - "index.md" - "environment.md" + - "comparisons.md" repo_name: br3ndonland/fastenv repo_url: https://github.com/br3ndonland/fastenv site_name: fastenv docs