Я пытаюсь реализовать правильное управление переменными среды в средах разработки, производства и промежуточной среды. Использование Pydantic имеет решающее значение, поскольку Pydantic присутствует повсюду в приложении.
Тестирование этого приложения становится сложной задачей из-за настройки переменных среды на основе операционной системы в производственной среде и среде разработки.
У меня есть следующее:
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from devtools import debug
class Config(BaseSettings):
# Environment
STAGE: str = Field('prod', validation_alias='STAGE')
OTHER: str
model_config = SettingsConfigDict(env_file='.test.env', env_file_encoding='utf-8', env_prefix='DEV_')
settings = Config()
debug(settings)
с файлом .test.env
, который выглядит так:
STAGE=test
DEV_OTHER = "other"
и я установил переменную среды ОС следующим образом:
export STAGE=dev
давая следующий ответ с printenv
:
...
STAGE=dev
...
и затем получите следующий вывод:
test.py:18 <module>
settings: Config(
STAGE='test',
OTHER='other',
)
В Pydantic переменная среды ОС будет иметь приоритет, но здесь этого не происходит, поскольку установка переменных среды в среде разработки связана с процессом.
Это приводит к неожиданному поведению с настройками Pydantic. Есть ли обходной путь? Я не хочу устанавливать STAGE
в файле bash и перезапускать среду (что обычно означает перезагрузку компьютера) всякий раз, когда я хочу проверить поведение в разных средах.
Хорошо, не уверен, что я следую. Файл .test.env
загружается, поскольку я могу получить доступ ко всем его значениям через объект Config()
. У меня также есть переменная STAGE
, объявленная как переменная env ОС, которая также присутствует в .test.env
. Согласно документации Pydantic я ожидаю, что первое будет иметь приоритет, но это не так. >> «Даже при использовании файла dotenv pydantic по-прежнему будет читать переменные среды, а также файл dotenv, переменные среды всегда будут иметь приоритет над значениями, загруженными из файла dotenv».
Извините моя ошибка. Вы правы, pydantic загружает и расставляет приоритеты значений из среды. Но я на самом деле не могу воспроизвести вашу проблему. На моей машине приоритет имеет переменная env. Вы на 100% уверены, что переменная среды присутствует во время выполнения? Не могли бы вы проверить, например? print(os.getenv("STAGE"))
?
Как вы используете Python? Вы уверены, что процесс Python наследует переменные среды? Что, если поставить import os; print(os.environ)
вверху файла?
Да, это странно. os.environ.get('STAGE')
возвращает None
, однако printenv
возвращает STAGE=prod
даже с export STAGE=prod
, что должно сделать переменную доступной для всех подпроцессов. Даже если я закрою все процессы, связанные с Python, export
переменную и перезапущу процесс Python, все равно ничего.
Проблема связана не с Pytdantic, а с видимостью переменных среды и соответствующих процессов, в которых они создаются, как упоминается в juanpa.arrivillaga и lord_haffi. Переменная, созданная с помощью export
в оболочке, доступна только этой оболочке и любому подпроцессу этой оболочки. Его необходимо сохранить, добавив в ~/.zshrc
или что-то подобное, прежде чем он станет доступен другим процессам.
Традиционно .zshrc
и подобные — это подходящее место для вещей, которые не передаются через среду (например, PS1
и другие неэкспортируемые конфигурации оболочки). Традиционный способ UNIX гласит, что переменные среды входят в .profile
/.zprofile
/и т. д., поэтому они устанавливаются только один раз при создании оболочки входа и не запускаются повторно для каждой интерактивной оболочки, созданной как подпроцесс этой оболочки входа.
Если вы не загружаете файл
.test.env
в реальные переменные среды, они там не будут присутствовать. Класс pydanticBaseSettings
только загружает файл и анализирует содержимое в объект pydantic. Он не изменяет переменные среды. От них тоже не загружается.