Как передать переменные окружения в команду poetry run script?

У меня есть сервис на Poetry.

import uvicorn
import os
from fastapi import FastAPI


app = FastAPI(title=os.getenv("APP_NAME", "app"))


def main() -> None:
    uvicorn.run(app, host=os.getenv("APP_HOST", "localhost"), port=os.getenv("APP_PORT", 8000))


if __name__ == "__main__":
    main()

И я пытаюсь установить переменные окружения перед запуском, чтобы всё запустилось. Но не совсем понимаю как это правильно сделать.

Перед выполнением poetry run main пробовал установить переменные окружения с помощью set KEY=val, но это не сработало и их по прежнему не было видно в коде. То есть после set APP_PORT=9000, при запуске он по прежнему был 8000.

Попробовал устанавливать переменные так: $env:APP_PORT="9000". Это уже сработало и код начал запускаться. Но порт 9000 должен быть интом (так говорится в сообщении об ошибке) и $env:APP_PORT=9000 не помогает. А в коде на каждую переменную с интом кажется не очень удобным добавлять port = int(os.getenv("APP_PORT", 8000)).

Как можно правильно добавить переменные? Если я запускаю через PyCharm, то всё нормально работает. Как он устанавливает переменные окружения?


Ответы (1 шт):

Автор решения: insolor

Если $env:APP_PORT="9000" помогает передать переменную внутрь окружения poetry (насколько мне подсказывает гугл, это способ для powershell), то его и используете.

Также можно установить плагин poetry-dotenv-plugin для poetry:

poetry self add poetry-dotenv-plugin

тогда можно будет не устанавливать переменные окружения вручную, а прописать их в .env файле, что-то типа

APP_NAME=application
APP_HOST=0.0.0.0
APP_PORT=9000

Этот вариант удобен, если нужно указать несколько значений.


По второй части: переменные окружения всегда хранят строки. Если нужно получить число, вам конкретное значение нужно конвертировать в число, и способ через int(os.getenv("APP_PORT", 8000)), который вы упоминаете,- вполне рабочий вариант.

Если не нравится оборачивание в int(), например, можно использовать пакет pydantic-settings (документация), в модели описать поля, их типы, дефолтные значения. При наличии соответствующих значений в переменных окружения они заменят значения по умолчанию, при этом значения сконвертируются в соответствии с аннотациями типа в модели.

Пример:

from pydantic_settings import BaseSettings


class Settings(BaseSettings):
    app_name: str = "app"
    app_host: str = "localhost"
    app_port: int = 8000


settings = Settings()

print(settings)
print(type(settings.app_port))
# app = FastAPI(title=settings.app_name)


def main():
    ...
    # uvicorn.run(app, host=settings.app_host, port=settings.app_port)


if __name__ == "__main__":
    main()

Вывод при запуске без записи в переменные окружения:

> python test.py
app_name='app' app_host='localhost' app_port=8000
<class 'int'>

Вывод с передачей значения через переменную окружения (запускаю на linux):

> env APP_PORT=9876 python test.py
app_name='app' app_host='localhost' app_port=9876
<class 'int'>

Кроме переменных окружения поддерживаются .env файлы, см. там же: Dotenv (.env) support, это будет работать и без установки плагина poetry-dotenv-plugin.

→ Ссылка