Fix type hinting for load_env (#2107)

* Deprecate `load_env` in favor of `env_prefix`

`load_env` both enabled/disabled environment variable parsing, while
also letting the user modify the env prefix. Deprecate the ability to
disable environment parsing, and add a new config variable to track the
user's desired prefix for environment-based configuration.

Resolves: #2102

* Add a few common .gitignore patterns
This commit is contained in:
Johnathan Raymond 2021-04-12 11:31:35 -07:00 committed by GitHub
parent 30479765cb
commit e21521f45c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 11 deletions

3
.gitignore vendored
View File

@ -18,3 +18,6 @@ build/*
.DS_Store
dist/*
pip-wheel-metadata/
.pytest_cache/*
.venv/*
.vscode/*

View File

@ -43,7 +43,7 @@ from sanic.asgi import ASGIApp
from sanic.base import BaseSanic
from sanic.blueprint_group import BlueprintGroup
from sanic.blueprints import Blueprint
from sanic.config import BASE_LOGO, Config
from sanic.config import BASE_LOGO, SANIC_PREFIX, Config
from sanic.exceptions import (
InvalidUsage,
SanicException,
@ -125,7 +125,8 @@ class Sanic(BaseSanic):
router: Optional[Router] = None,
signal_router: Optional[SignalRouter] = None,
error_handler: Optional[ErrorHandler] = None,
load_env: bool = True,
load_env: Union[bool, str] = True,
env_prefix: Optional[str] = SANIC_PREFIX,
request_class: Optional[Type[Request]] = None,
strict_slashes: bool = False,
log_config: Optional[Dict[str, Any]] = None,
@ -150,7 +151,7 @@ class Sanic(BaseSanic):
self._test_manager = None
self.asgi = False
self.blueprints: Dict[str, Blueprint] = {}
self.config = Config(load_env=load_env)
self.config = Config(load_env=load_env, env_prefix=env_prefix)
self.configure_logging = configure_logging
self.ctx = SimpleNamespace()
self.debug = None

View File

@ -1,7 +1,8 @@
from inspect import isclass
from os import environ
from pathlib import Path
from typing import Any, Union
from typing import Any, Dict, Optional, Union
from warnings import warn
from .utils import load_module_from_file_location, str_to_bool
@ -41,7 +42,13 @@ DEFAULT_CONFIG = {
class Config(dict):
def __init__(self, defaults=None, load_env=True, keep_alive=None):
def __init__(
self,
defaults: Dict[str, Union[str, bool, int, float, None]] = None,
load_env: Optional[Union[bool, str]] = True,
env_prefix: Optional[str] = SANIC_PREFIX,
keep_alive: Optional[int] = None,
):
defaults = defaults or {}
super().__init__({**DEFAULT_CONFIG, **defaults})
@ -50,9 +57,20 @@ class Config(dict):
if keep_alive is not None:
self.KEEP_ALIVE = keep_alive
if load_env:
prefix = SANIC_PREFIX if load_env is True else load_env
self.load_environment_vars(prefix=prefix)
if env_prefix != SANIC_PREFIX:
if env_prefix:
self.load_environment_vars(env_prefix)
elif load_env is not True:
if load_env:
self.load_environment_vars(prefix=load_env)
warn(
"Use of load_env is deprecated and will be removed in "
"21.12. Modify the configuration prefix by passing "
"env_prefix instead.",
DeprecationWarning,
)
else:
self.load_environment_vars(SANIC_PREFIX)
def __getattr__(self, attr):
try:

View File

@ -59,14 +59,14 @@ def test_load_from_object_string_exception(app):
app.config.load("test_config.Config.test")
def test_auto_load_env():
def test_auto_env_prefix():
environ["SANIC_TEST_ANSWER"] = "42"
app = Sanic(name=__name__)
assert app.config.TEST_ANSWER == 42
del environ["SANIC_TEST_ANSWER"]
def test_auto_load_bool_env():
def test_auto_bool_env_prefix():
environ["SANIC_TEST_ANSWER"] = "True"
app = Sanic(name=__name__)
assert app.config.TEST_ANSWER is True
@ -80,6 +80,12 @@ def test_dont_load_env():
del environ["SANIC_TEST_ANSWER"]
@pytest.mark.parametrize('load_env', [None, False, "", "MYAPP_"])
def test_load_env_deprecation(load_env):
with pytest.warns(DeprecationWarning, match=r"21\.12"):
_ = Sanic(name=__name__, load_env=load_env)
def test_load_env_prefix():
environ["MYAPP_TEST_ANSWER"] = "42"
app = Sanic(name=__name__, load_env="MYAPP_")
@ -87,6 +93,14 @@ def test_load_env_prefix():
del environ["MYAPP_TEST_ANSWER"]
@pytest.mark.parametrize('env_prefix', [None, ""])
def test_empty_load_env_prefix(env_prefix):
environ["SANIC_TEST_ANSWER"] = "42"
app = Sanic(name=__name__, env_prefix=env_prefix)
assert getattr(app.config, "TEST_ANSWER", None) is None
del environ["SANIC_TEST_ANSWER"]
def test_load_env_prefix_float_values():
environ["MYAPP_TEST_ROI"] = "2.3"
app = Sanic(name=__name__, load_env="MYAPP_")
@ -101,6 +115,27 @@ def test_load_env_prefix_string_value():
del environ["MYAPP_TEST_TOKEN"]
def test_env_prefix():
environ["MYAPP_TEST_ANSWER"] = "42"
app = Sanic(name=__name__, env_prefix="MYAPP_")
assert app.config.TEST_ANSWER == 42
del environ["MYAPP_TEST_ANSWER"]
def test_env_prefix_float_values():
environ["MYAPP_TEST_ROI"] = "2.3"
app = Sanic(name=__name__, env_prefix="MYAPP_")
assert app.config.TEST_ROI == 2.3
del environ["MYAPP_TEST_ROI"]
def test_env_prefix_string_value():
environ["MYAPP_TEST_TOKEN"] = "somerandomtesttoken"
app = Sanic(name=__name__, env_prefix="MYAPP_")
assert app.config.TEST_TOKEN == "somerandomtesttoken"
del environ["MYAPP_TEST_TOKEN"]
def test_load_from_file(app):
config = dedent(
"""

View File

@ -1,4 +1,5 @@
import asyncio
import platform
from asyncio import sleep as aio_sleep
from json import JSONDecodeError
@ -6,7 +7,6 @@ from os import environ
import httpcore
import httpx
import platform
import pytest
from sanic_testing.testing import HOST, SanicTestClient