我想在本地环境中运行一个Python脚本,通常在Docker容器中运行。docker-compose。Yml指定了一个env_file,看起来(部分)像下面这样:

DB_ADDR=rethinkdb
DB_PORT=28015
DB_NAME=ipercron

为了在本地运行,我希望将这些行转换为

os.environ['DB_ADDR'] = 'rethinkdb'
os.environ['DB_PORT'] = '28015'
os.environ['DB_NAME'] = 'ipercron'

我可以编写我的解析器,但我想知道是否有任何现有的模块/工具可以从配置文件中读取环境变量?


当前回答

如果你的系统/环境/工作流支持使用shell脚本,你可以创建一个脚本来包装这两个操作:

获取.env文件并将其导出为环境变量 使用set -a选项,其中“每个创建或修改的变量或函数都被赋予export属性,并标记为导出到后续命令的环境”。 调用具有简单os. environment .get代码的Python脚本/应用程序

示例.env文件(config.env):

TYPE=prod
PORT=5000

示例Python代码(test.py):

import os

print(os.environ.get('TYPE'))
print(os.environ.get('PORT'))

示例bash脚本(run.sh):

#!/usr/bin/env bash

set -a
source config.env
set +a

python3 test.py

示例运行:

$ tree
.
├── config.env
├── run.sh
└── test.py

$ echo $TYPE

$ echo $PORT

$ python3 test.py
None
None

$ ./run.sh 
prod
5000

当您直接运行Python脚本(python3 test.py)而不获取.env文件时,所有的environ。get calls返回None。

但是,当您将它包装在一个shell脚本中,该脚本首先将.env文件加载到环境变量中,然后再运行Python脚本时,Python脚本现在应该能够正确地读取环境变量。它还确保导出的env变量仅作为Python应用程序/脚本执行的一部分存在。

与其他流行的答案相比,这不需要任何外部Python库。

其他回答

只使用python std

import re

envre = re.compile(r'''^([^=]+)\s+?=\s+?(?:[\s"']*)(.+?)(?:[\s"']*)$''')
result = {}
with open('/etc/os-release') as ins:
    for line in ins:
        match = envre.match(line)
        if match is not None:
            result[match.group(1)] = match.group(2)

我不建议直接从程序中读取.env文件。12因素应用程序中的配置部分的思想是,你从环境变量中读取配置——即不是从文件中。

.env文件只是将这些变量放入环境的一种方便方法(见下文)。如果您开始在代码中直接读取文件,那么这一步就跳过了环境变量和所有后果,基本上又回到了起点,从文件中读取配置。

所以你应该做的是,使用一个工具,如dotenv-cli,读取。env文件,将变量导出到环境中,并在临时修改的环境中运行你的应用程序,如下所示:

$ dotenv yourapp

您可以使用ConfigParser。示例可以在这里找到。

但是这个库希望你的key=value数据出现在某些[标题]下。例如:

[mysqld]
user = mysql  # Key with values
pid-file = /var/run/mysqld/mysqld.pid
skip-external-locking
old_passwords = 1
skip-bdb      # Key without value
skip-innodb

如果你的系统/环境/工作流支持使用shell脚本,你可以创建一个脚本来包装这两个操作:

获取.env文件并将其导出为环境变量 使用set -a选项,其中“每个创建或修改的变量或函数都被赋予export属性,并标记为导出到后续命令的环境”。 调用具有简单os. environment .get代码的Python脚本/应用程序

示例.env文件(config.env):

TYPE=prod
PORT=5000

示例Python代码(test.py):

import os

print(os.environ.get('TYPE'))
print(os.environ.get('PORT'))

示例bash脚本(run.sh):

#!/usr/bin/env bash

set -a
source config.env
set +a

python3 test.py

示例运行:

$ tree
.
├── config.env
├── run.sh
└── test.py

$ echo $TYPE

$ echo $PORT

$ python3 test.py
None
None

$ ./run.sh 
prod
5000

当您直接运行Python脚本(python3 test.py)而不获取.env文件时,所有的environ。get calls返回None。

但是,当您将它包装在一个shell脚本中,该脚本首先将.env文件加载到环境变量中,然后再运行Python脚本时,Python脚本现在应该能够正确地读取环境变量。它还确保导出的env变量仅作为Python应用程序/脚本执行的一部分存在。

与其他流行的答案相比,这不需要任何外部Python库。

在无法使用python-dotenv的情况下,我使用了如下代码:

import os

def load_env_file(dotenv_path, override=False):
    with open(dotenv_path) as file_obj:
        lines = file_obj.read().splitlines()  # Removes \n from lines

    dotenv_vars = {}
    for line in lines:
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue

        key, value = line.split("=", maxsplit=1)
        dotenv_vars.setdefault(key, value)

    if override:
        os.environ.update(dotenv_vars)
    else:
        for key, value in dotenv_vars.items():
            os.environ.setdefault(key, value)

它读取给定的文件并解析包含“=”符号的行。 符号前的值是键,符号后的值是值。

具有与env文件中相同键的当前环境变量既可以保持不变,也可以使用override参数覆盖。