跳转到主要内容

简化环境变量解析

项目描述

environs:简化环境变量解析

Latest version Build Status marshmallow 3 compatible

environs 是一个Python库,用于解析环境变量。它允许您将配置与代码分开存储,遵循 《十二要素应用》 方法。

内容

特性

  • 类型转换
  • .env 文件读入 os.environ(对本地开发很有用)
  • 验证
  • 定义自定义解析器行为
  • 框架无关,但与 FlaskDjango 集成良好

安装

pip install environs

基本用法

设置一些环境变量...

export GITHUB_USER=sloria
export MAX_CONNECTIONS=100
export SHIP_DATE='1984-06-25'
export TTL=42
export ENABLE_LOGIN=true
export GITHUB_REPOS=webargs,konch,ped
export GITHUB_REPO_PRIORITY="webargs=2,konch=3"
export COORDINATES=23.3,50.0
export LOG_LEVEL=DEBUG

使用environs解析它们...

from environs import Env

env = Env()
env.read_env()  # read .env file, if it exists
# required variables
gh_user = env("GITHUB_USER")  # => 'sloria'
secret = env("SECRET")  # => raises error if not set

# casting
max_connections = env.int("MAX_CONNECTIONS")  # => 100
ship_date = env.date("SHIP_DATE")  # => datetime.date(1984, 6, 25)
ttl = env.timedelta("TTL")  # => datetime.timedelta(0, 42)
log_level = env.log_level("LOG_LEVEL")  # => logging.DEBUG

# providing a default value
enable_login = env.bool("ENABLE_LOGIN", False)  # => True
enable_feature_x = env.bool("ENABLE_FEATURE_X", False)  # => False

# parsing lists
gh_repos = env.list("GITHUB_REPOS")  # => ['webargs', 'konch', 'ped']
coords = env.list("COORDINATES", subcast=float)  # => [23.3, 50.0]

# parsing dicts
gh_repos_priorities = env.dict(
    "GITHUB_REPO_PRIORITY", subcast_values=int
)  # => {'webargs': 2, 'konch': 3}

支持类型

以下都是 Env 的类型转换方法:

  • env.str
  • env.bool
  • env.int
  • env.float
  • env.decimal
  • env.list(接受可选的 subcastdelimiter 关键字参数)
  • env.dict(接受可选的 subcast_keyssubcast_valuesdelimiter 关键字参数)
  • env.json
  • env.datetime
  • env.date
  • env.time
  • env.timedelta(假设值是秒的整数)
  • env.url
  • env.uuid
  • env.log_level
  • env.path(转换为pathlib.Path
  • env.enum(转换为在type关键字参数中指定的任何枚举类型,接受可选的ignore_case关键字参数)

读取 .env 文件

# .env
DEBUG=true
PORT=4567

在解析变量之前调用Env.read_env

from environs import Env

env = Env()
# Read .env into os.environ
env.read_env()

env.bool("DEBUG")  # => True
env.int("PORT")  # => 4567

读取特定文件

默认情况下,Env.read_env将在当前目录中查找.env文件,并在找不到.env文件时向上递归,直到找到.env文件。

您也可以读取特定文件

from environs import Env

with open(".env.test", "w") as fobj:
    fobj.write("A=foo\n")
    fobj.write("B=123\n")

env = Env()
env.read_env(".env.test", recurse=False)

assert env("A") == "foo"
assert env.int("B") == 123

处理前缀

# export MYAPP_HOST=lolcathost
# export MYAPP_PORT=3000

with env.prefixed("MYAPP_"):
    host = env("HOST", "localhost")  # => 'lolcathost'
    port = env.int("PORT", 5000)  # => 3000

# nested prefixes are also supported:

# export MYAPP_DB_HOST=lolcathost
# export MYAPP_DB_PORT=10101

with env.prefixed("MYAPP_"):
    with env.prefixed("DB_"):
        db_host = env("HOST", "lolcathost")
        db_port = env.int("PORT", 10101)

变量扩展

# export CONNECTION_URL=https://${USER:-sloria}:${PASSWORD}@${HOST:-localhost}/
# export PASSWORD=secret
# export YEAR=${CURRENT_YEAR:-2020}

from environs import Env

env = Env(expand_vars=True)

connection_url = env("CONNECTION_URL")  # =>'https://sloria:secret@localhost'
year = env.int("YEAR")  # =>2020

验证

# export TTL=-2
# export NODE_ENV='invalid'
# export EMAIL='^_^'

from environs import Env
from marshmallow.validate import OneOf, Length, Email

env = Env()

# simple validator
env.int("TTL", validate=lambda n: n > 0)
# => Environment variable "TTL" invalid: ['Invalid value.']


# using marshmallow validators
env.str(
    "NODE_ENV",
    validate=OneOf(
        ["production", "development"], error="NODE_ENV must be one of: {choices}"
    ),
)
# => Environment variable "NODE_ENV" invalid: ['NODE_ENV must be one of: production, development']

# multiple validators
env.str("EMAIL", validate=[Length(min=4), Email()])
# => Environment variable "EMAIL" invalid: ['Shorter than minimum length 4.', 'Not a valid email address.']

延迟验证

默认情况下,在调用解析器方法对无效环境变量进行解析时将立即引发验证错误。为了延迟验证并引发包含所有无效变量组合错误消息的异常,请将eager=False传递给Env。在解析所有变量之后调用env.seal()

# export TTL=-2
# export NODE_ENV='invalid'
# export EMAIL='^_^'

from environs import Env
from marshmallow.validate import OneOf, Email, Length, Range

env = Env(eager=False)

TTL = env.int("TTL", validate=Range(min=0, max=100))
NODE_ENV = env.str(
    "NODE_ENV",
    validate=OneOf(
        ["production", "development"], error="NODE_ENV must be one of: {choices}"
    ),
)
EMAIL = env.str("EMAIL", validate=[Length(min=4), Email()])

env.seal()
# environs.EnvValidationError: Environment variables invalid: {'TTL': ['Must be greater than or equal to 0 and less than or equal to 100.'], 'NODE_ENV': ['NODE_ENV must be one of: production, development'], 'EMAIL': ['Shorter than minimum length 4.', 'Not a valid email address.']}

env.seal()验证所有已解析变量,并阻止进一步解析(调用解析器方法将引发错误)。

URL方案

env.url()通过schemes参数支持非标准URL方案。

REDIS_URL = env.url(
    "REDIS_URL", "redis://redis:6379", schemes=["redis"], require_tld=False
)

序列化

# serialize to a dictionary of simple types (numbers and strings)
env.dump()
# {'COORDINATES': [23.3, 50.0],
# 'ENABLE_FEATURE_X': False,
# 'ENABLE_LOGIN': True,
# 'GITHUB_REPOS': ['webargs', 'konch', 'ped'],
# 'GITHUB_USER': 'sloria',
# 'MAX_CONNECTIONS': 100,
# 'MYAPP_HOST': 'lolcathost',
# 'MYAPP_PORT': 3000,
# 'SHIP_DATE': '1984-06-25',
# 'TTL': 42}

定义自定义解析器行为

# export DOMAIN='http://myapp.com'
# export COLOR=invalid

from furl import furl


# Register a new parser method for paths
@env.parser_for("furl")
def furl_parser(value):
    return furl(value)


domain = env.furl("DOMAIN")  # => furl('https://myapp.com')


# Custom parsers can take extra keyword arguments
@env.parser_for("choice")
def choice_parser(value, choices):
    if value not in choices:
        raise environs.EnvError("Invalid!")
    return value


color = env.choice("COLOR", choices=["black"])  # => raises EnvError

与Flask一起使用

# myapp/settings.py

from environs import Env

env = Env()
env.read_env()

# Override in .env for local development
DEBUG = env.bool("FLASK_DEBUG", default=False)
# SECRET_KEY is required
SECRET_KEY = env.str("SECRET_KEY")

在初始化您的应用程序之后加载配置。

# myapp/app.py

from flask import Flask

app = Flask(__name__)
app.config.from_object("myapp.settings")

对于本地开发,使用.env文件来覆盖默认配置。

# .env
DEBUG=true
SECRET_KEY="not so secret"

注意:由于environs依赖于python-dotenv,因此flask CLI将自动读取.env和.flaskenv文件。

与Django一起使用

environs包含许多解析连接URL的辅助工具。要安装带有django支持的environs

pip install environs[django]

使用env.dj_db_urlenv.dj_cache_urlenv.dj_email_url分别解析DATABASE_URLCACHE_URLEMAIL_URL环境变量。

有关URL模式的更多详细信息,请参阅environs使用的以下项目。

基本示例

# myproject/settings.py
from environs import Env

env = Env()
env.read_env()

# Override in .env for local development
DEBUG = env.bool("DEBUG", default=False)
# SECRET_KEY is required
SECRET_KEY = env.str("SECRET_KEY")

# Parse database URLs, e.g.  "postgres://localhost:5432/mydb"
DATABASES = {"default": env.dj_db_url("DATABASE_URL")}

# Parse email URLs, e.g. "smtp://"
email = env.dj_email_url("EMAIL_URL", default="smtp://")
EMAIL_HOST = email["EMAIL_HOST"]
EMAIL_PORT = email["EMAIL_PORT"]
EMAIL_HOST_PASSWORD = email["EMAIL_HOST_PASSWORD"]
EMAIL_HOST_USER = email["EMAIL_HOST_USER"]
EMAIL_USE_TLS = email["EMAIL_USE_TLS"]

# Parse cache URLS, e.g "redis://localhost:6379/0"
CACHES = {"default": env.dj_cache_url("CACHE_URL")}

对于本地开发,使用.env文件来覆盖默认配置。

# .env
DEBUG=true
SECRET_KEY="not so secret"

有关更完整的示例,请参阅examples/目录中的django_example.py

为什么...?

为什么是环境变量?

请参阅12因子应用部分中的配置

为什么不是 os.environ

虽然os.environ对于简单用例足够使用,但典型应用程序将需要一种操作和验证原始环境变量的方法。environs抽象了处理环境变量的常见任务。

environs将帮助您

  • 将envvars转换为正确的类型
  • 指定必需的envvars
  • 定义默认值
  • 验证envvars
  • 解析列表和字典值
  • 解析日期、日期时间和时间差
  • 解析扩展变量
  • 将配置序列化为JSON、YAML等。

为什么还要另一个库?

有许多优秀的Python库用于解析环境变量。实际上,environs公共API的大部分功劳归功于envparsedjango-environ的作者。

environs旨在实现三个额外的目标

  1. 使扩展解析行为和开发插件变得容易。
  2. 利用由单独的库(marshmallow)提供的反序列化和验证功能。
  3. 清理冗余API。

请参阅此GitHub问题,其中详细说明了与envparse的具体差异。

许可证

MIT许可。有关更多详细信息,请参阅LICENSE文件。

项目详细信息


下载文件

下载适合您平台文件的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

environs-11.0.0.tar.gz (25.8 kB 查看哈希值)

上传时间

构建分布

environs-11.0.0-py3-none-any.whl (12.2 kB 查看哈希值)

上传时间 Python 3

由支持