FastAPI(64)- Settings and Environment Variables 配置项和环境变量
背景
- 在许多情况下,应用程序可能需要一些外部设置或配置,例如密钥、数据库凭据、电子邮件服务凭据等。
- 大多数这些设置都是可变的(可以更改),例如数据库 URL,很多可能是敏感数据,比如密码
- 出于这个原因,通常在应用程序读取的环境变量中提供它们
Pydantic Settings
- Pydantic 提供了一个很好的实用程序来处理环境变量的设置
- 从 Pydantic 导入 BaseSettings 并创建一个子类,非常类似于 Pydantic 的 BaseModel
- 与 Pydantic Model 一样,可以使用类型注释和默认值声明类属性
- 可以使用和 Pydantic Model 的所有相同验证功能和工具,例如不同的数据类型和使用 Field()
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog: https://www.cnblogs.com/poloyy/
# time: 2021/10/9 7:25 下午
# file: 52_settings_env.py
"""
import os import uvicorn
from fastapi import FastAPI
from pydantic import BaseSettings class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50 settings = Settings()
app = FastAPI() @app.get("/info")
async def info():
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}
- 然后,当创建 Settings 该类的实例时,Pydantic 将以不区分大小写的方式读取环境变量
- 因此,仍会为属性 app_name 读取为大写变量 APP_NAME
- 接下来它将转换和验证数据
- 因此,当使用该 settings 对象时,将拥有声明的类型的数据(例如 items_per_user 是 int)
运行 uvicorn 服务器
要为单个命令设置多个环境变量,只需用空格分隔它们,并将它们全部放在命令之前
ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app
访问 /info 接口
Settings 跨模块调用
config.py
from pydantic import BaseSettings class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50 settings = Settings()
main.py
from fastapi import FastAPI
from .config import settings app = FastAPI() @app.get("/info")
async def info():
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}
Settings 在依赖项中
前言
- 在某些情况下,提供依赖项的 Settings 会有用,而不是让全局对象拥有可随处使用的 Settings
- 在测试期间会有用,因为使用自定义 Settings 覆盖依赖项非常容易
config.py
from pydantic import BaseSettings class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50
这里不创建默认实例 settings = Settings()
main.py
from fastapi import FastAPI, Depends
from functools import lru_cache
from .config import Settings app = FastAPI() @lru_cache
def get_settings():
return Settings @app.get("/info")
async def info(settings: Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}
测试上述接口
from fastapi.testclient import TestClient
from .config import Settings
from .main import app, get_settings client = TestClient(app) # 依赖覆盖,为 Settings 对象设置一个新的 admin_email 值
def get_settings_override():
return Settings(admin_email="testing_admin@example.com") app.dependency_overrides[get_settings] = get_settings_override def test_app():
response = client.get("/info")
data = response.json()
assert data == {
"app_name": "Awesome API",
"admin_email": "testing_admin@example.com",
"items_per_user": 50,
}
命令行执行
> pytest 53_settings_test.py
============================================================================================================ test session starts ============================================================================================================
platform darwin -- Python 3.9.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/polo/Downloads/FastAPI_project
plugins: anyio-3.3.2
collected 1 item 53_settings_test.py . [100%] ============================================================================================================= 1 passed in 0.30s =============================================================================================================
使用 .env 文件
背景
如果有会经常变化的设置项,也许在不同的环境中,将它们放在一个文件中,然后从文件中读取它们,就好像它们是环境变量一样
这些环境变量通常放在一个文件 .env 中,该文件称为“dotenv”
tips
- 以点 (.) 开头的文件是类 Unix 系统(如 Linux 和 macOS)中的隐藏文件
- 但是 dotenv 文件实际上不必具有那个确切的文件名
- Pydantic 支持使用外部库读取这类型的文件
安装第三方库
pip install python-doten
.env 文件
ADMIN_EMAIL="xiaopolo@example.com"
APP_NAME="小菠萝"
config.py 文件
from pydantic import BaseSettings class Settings(BaseSettings):
app_name: str = "Awesome API"
admin_email: str
items_per_user: int = 50 class Config:
# 设置需要识别的 .env 文件
env_file = ".env"
lru_cache
背景
继上面的栗子,读取 .env 文件可能是一件代价高昂(缓慢)的操作
从性能角度出发,肯定希望只读取一次,后续每个请求可以重复使用同一个 Settings 对象,这样就只会读取一次 .env 文件
def get_settings():
return Settings()
上述代码,如果作为请求的依赖项,那么每次请求进来,都会创建一个 Settings 对象,然后读取一次 .env 文件,这不是我们希望的
@lru_cache
如果加上了 @lru_cache 那么 get_settings 只会在第一次调用的时候执行一次,然后 Settings 对象也只会创建一次,.env 文件也只会读取一次
from functools import lru_cache
from fastapi import Depends, FastAPI
from . import config app = FastAPI() @lru_cache()
def get_settings():
return config.Settings() @app.get("/info")
async def info(settings: config.Settings = Depends(get_settings)):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}
对于后续请求的依赖项中的 get_settings() 的任何后续调用,它不会执行 get_settings() 的内部代码并创建新的 Settings 对象,而是返回与第一次调用时返回的相同对象
lru_cache 技术细节
- @lru_cache() 修改它修饰的函数返回与第一次返回相同的值,而不是再次执行函数内部代码
- 因此,它下面的函数将针对每个参数组合执行一次
- 然后,每当使用完全相同的参数组合调用函数时,每个参数组合返回相同的值将一次又一次地使用
- 在请求依赖项 get_settings() 的情况下,该函数没有参数,所以它总是返回相同的值
- 这样,它的行为就好像它只是一个全局变量
- 但是因为它使用了一个依赖函数,所以可以很容易地覆盖它进行测试
- @lru_cache() 是 functools 的一部分,它是 Python 标准库的一部分
- 使用 @lru_cache() 可以避免为每个请求一次又一次地读取 .env 文件,同时可以在测试期间覆盖它的值
有参数的函数的栗子
@lru_cache()
def say_hi(name: str, salutation: str = "Ms."):
print(123)
return f"Hello {salutation} {name}" print(say_hi(name="Camila"))
print(say_hi(name="Camila")) print(say_hi(name="Rick", salutation="Mr."))
print(say_hi(name="Rick", salutation="Mr.")) print(say_hi(name="Camila"))
print(say_hi(name="Rick", salutation="Mr."))
运行结果
123
Hello Ms. Camila
Hello Ms. Camila 123
Hello Mr. Rick
Hello Mr. Rick Hello Ms. Camila
Hello Mr. Rick
使用完全相同的参数调用函数时,直接返回结果而不会执行厘米的代码
原理图
FastAPI(64)- Settings and Environment Variables 配置项和环境变量的更多相关文章
- CMake语法—环境变量(Environment Variable)
目录 CMake语法-环境变量(Environment Variable) 1 定义环境变量 2 应用环境变量 2.1 代码结构 2.2 示例代码 2.3 运行结果 3 小结 CMake语法-环境变量 ...
- Debian Environment Variables
原文:EnvironmentVariables General Environment variables are named strings available to all application ...
- Environment Variables
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682653(v=vs.85).aspx Every process has an ...
- Visual Studio Set Project Environment Variables
Visual Studio Set Project Environment Variables eryar@163.com In Visual Studio you can specify chang ...
- CVE: 2014-6271、CVE: 2014-7169 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis
目录 . 漏洞的起因 . 漏洞原理分析 . 漏洞的影响范围 . 漏洞的利用场景 . 漏洞的POC.测试方法 . 漏洞的修复Patch情况 . 如何避免此类漏洞继续出现 1. 漏洞的起因 为了理解这个漏 ...
- How to keep Environment Variables when Using SUDO
The trick is to add environment variables to sudoers file via sudo visudo command and add these line ...
- [Whole Web, Nods.js, PM2] Passing environment variables to node.js using pm2
learn how to pass environment variables to your node.js app using the pm2 config file. This is usefu ...
- List environment variables from Command Prompt
Request: List the environment variables from Command Promt To list one varibales , the syntax is lik ...
- [NPM] Execute npx commands with $npm_ Environment Variables
We will incorporate npm specific environment variables when executing various npx commands. In our e ...
随机推荐
- eclipse性能调优的一次记录
最近因为学习原因,eclipse中插件越来越多,造成eclipse一次次假死,着实很影响工作效率和心情,有时正是兴起,但是造成短片很令人生气,如果eclipse卡顿或者假死,在电脑配置较不错的情况下, ...
- C程序设计学习笔记(完结)
时间:2015-4-16 09:17 不求甚解,每有会意,欣然忘食.学习的过程是痛苦的 第1章 程序设计和C语言 第2章 算法--程序的灵魂 -算法的五个特点 ...
- ORB_SLAM2 Ubuntu16.04编译错误
Ubuntu14.04一切正常,迁移到Ubuntu16.04后编译报错,提示: /usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h:745:3: ...
- Docker | 入门 & 基础操作
Dcoker 入门 确保docker 已经安装好了,如没有装好的可以参考:Docker | 安装 运行第一个容器 docker run -it ubuntu /bin/bash docker run ...
- Python - //和/的区别
/ 表示浮点数除法,返回浮点结果; // 表示整数除法,返回不大于结果的一个最大的整数 print("6 // 4 = " + str(6 // 4)) print("6 ...
- k8s核心资源之Pod概念&入门使用讲解(三)
目录 1. k8s核心资源之Pod 1.1 什么是Pod? 1.2 Pod如何管理多个容器? 1.3 Pod网络 1.4 Pod存储 1.5 Pod工作方式 1.5.1 自主式Pod 1.5.2 控制 ...
- vue2.0 前端框架
在正式开始先复习一下js基础.因为vue最通终也要操作这些元素,vue和以前学的js并不挂勾,他和传统的jquert 设计理念相反 ## js 数据类型 1 基本类型 number string ...
- 洛谷P1056——排座椅(模拟,贪心,排序)
https://www.luogu.org/problem/show?pid=1056 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发 ...
- Python树莓派 爬虫心得
平台: 树莓派 linux 语言:python 搞一个爬虫都清楚是怎么回事,我这里玩过之后有下面的心得: 为什么要用树莓派呢,省电啊,没乱七八糟的桌面问题,可以一直开着. 1.树莓派上的磁盘写入对于不 ...
- 关于buildroot移植的思考
buildroot是一个成熟的SDK框架,基于它有了openwrt. 曾经有一个项目,需要将原有的OpenWrt SDK改造,并且将软件框架重新定义.尝试精简原来的OpenWrt,并且删除所有的软件包 ...