Use Pydantic BaseSettings for config settings by StephenBrown2 · Pull Request #87 · fastapi/full-stack-fastapi-template
Enables the use of validation for config on load, and pulling from environment implicitly.
I believe I got all the types right, mostly strings. All of the values not critical for running (i.e. email settings) also have a default value, and so are optional. Others, those populated by cookiecutter, are required.
I also updated some deps to be consistent throughout and changed a single keyword arg to match Pydantic 1.0 usage, but I can back those out if needed.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love it 🥇
I didnot realize that pydantic provided the BaseSettings class. It's great 🎈
| ) -> ModelType: | ||
| obj_data = jsonable_encoder(db_obj) | ||
| update_data = obj_in.dict(skip_defaults=True) | ||
| update_data = obj_in.dict(exclude_unset=True) |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will conflict with PR #106
@StephenBrown2 just wondering if using Pydantic is superior to using Starlette config ? https://www.starlette.io/config/
Especially considering security usecases where we do not commit ".env" into the source code repo. Starlette config supports all those kind of cases. Pretty sure you can write them... so just curious
Pydantic by default reads form the environment, but can also read from a dotenv file, as long as the python-dotenv package is installed as well: https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support
Since Pydantic is already being used for validation/parsing, it seemed logical to use it for settings as well. One difference is that settings must be in a class, but that can come in useful for setting config in multiple ways, giving it one more option than Starlette's Config:
Setting value is determined as follows (in descending order of priority):
- Arguments passed to the
Settingsclass initialiser.- Environment variables, e.g.
my_prefix_special_functionas described above.- Variables loaded from a dotenv (
.env) file.- The default field values for the
Settingsmodel.
I see them as equivalent, and prefer Pydantic's method, but if one is not using Pydantic and instead using Starlette alone, it's perfectly fine to use that.
Thanks for your reply. The only reason I asked was that fastapi is built on Starlette and that uses this config system. So i was concerned that was the long term safer way
…On Tue, 25 Feb, 2020, 21:15 Stephen Brown II, ***@***.***> wrote: Pydantic by default reads form the environment, but can also read from a dotenv file, as long as the python-dotenv <https://pypi.org/project/python-dotenv/> package <https://pypi.org/project/python-dotenv/> is installed as well: https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support Since Pydantic is already being used for validation/parsing, it seemed logical to use it for settings as well. One difference is that settings must be in a class, but that can come in useful for setting config in multiple ways, giving it one more option than Starlette's Config: Setting value is determined as follows (in descending order of priority): 1. Arguments passed to the Settings class initialiser. 2. Environment variables, e.g. my_prefix_special_function as described above. 3. Variables loaded from a dotenv (.env) file. 4. The default field values for the Settings model. I see them as equivalent, and prefer Pydantic's method, but if one is not using Pydantic and instead using Starlette alone, it's perfectly fine to use that. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#87>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAASYU5QJ6YWC5SBMEFKGUTREU4JJANCNFSM4JXFGMDA> .
Personally I like Pydantic's BaseSettings more aswell.
You can also use sub models to structure settings somewhat. Prefixes can be set via the Config.
Example:
from pathlib import Path from typing import List from pydantic import ( AnyHttpUrl, BaseModel, BaseSettings, FilePath, PostgresDsn, SecretStr, ) class Paths(BaseModel): """File paths class. Build file paths using APP_DIR.""" APP_DIR: FilePath = Path(__file__).resolve().parent STATIC_DIR: FilePath = APP_DIR.joinpath("static") # Docker secrets directory SECRETS_DIR: FilePath = "/run/secrets" class PostgresSettings(BaseSettings): USER: str PASSWORD: SecretStr HOST: str PORT: int DB: str class Config: env_prefix = "POSTGRES_" class SMTPSettings(BaseSettings): USER: str PASSWORD: SecretStr TLS: bool SSL: bool HOST: str PORT: int class Config: env_prefix = "SMTP_" class JWTSettings(BaseSettings): EXPIRE_MINUTES: int = 60 * 24 * 8 # 60 minutes * 24 hours * 8 days = 8 days EMAIL_EXPIRE_MINUTES: int = 60 * 8 # 8 hours class Config: env_prefix = "JWT_" class Settings(BaseSettings): PATHS = Paths() POSTGRES = PostgresSettings() BASE_DB_URL: PostgresDsn = f"postgresql://{POSTGRES.USER}:{POSTGRES.PASSWORD.get_secret_value()}@{POSTGRES.HOST}:{POSTGRES.PORT}" DATABASE_URL: PostgresDsn = BASE_DB_URL + f"/{POSTGRES.DB}" TEST_DATABASE_URL: PostgresDsn = BASE_DB_URL + f"/{POSTGRES.DB}_test" SMTP: SMTPSettings = SMTPSettings() JWT: JWTSettings = JWTSettings() PROJECT_NAME: str SERVER_HOST: AnyHttpUrl = "http://0.0.0.0" CORS_WHITELIST: List[AnyHttpUrl] = [] FASTAPI_ENV: str TESTING: bool = False DEBUG: bool = False FIRST_SUPERUSER: str FIRST_SUPERUSER_PASSWORD: str USERS_OPEN_REGISTRATION: bool settings = Settings()
gusevyaroslove pushed a commit to gusevyaroslove/fastapi-template that referenced this pull request
Aug 4, 2024This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters