pythonfastapipydanticalembic

Pydantic BaseSettings cant find .env when running commands from different places


So, Im trying to setup Alembic with FastAPI and Im having a problem with Pydantic's BaseSettings, I get a validation error (variables not found) because it doesnt find the .env file (?)

It can be solved by changing env_file = ".env" to env_file = "../.env" in the BaseSettings class Config but that makes the error happen when running main.py, I tried setting it as an absolute path with env_file = os.path.abspath("../../.env") but that didnt work.

What should I do?

config.py:

import os
from functools import lru_cache

from pydantic_settings import BaseSettings

abs_path_env = os.path.abspath("../../.env")


class Settings(BaseSettings):
    APP_NAME: str = "AppName"
    SQLALCHEMY_URL: str
    ENVIRONMENT: str

    class Config:
        env_file = ".env"  # Works with uvicorn run command from my-app/project/
        # env_file = "../.env"  Works with alembic command from my-app/alembic
        # env_file = abs_path_env

@lru_cache()
def get_settings():
    return Settings()

Project folders:

my-app
├── alembic
│   ├── versions
│   ├── alembic.ini
│   ├── env.py
│   ├── README
│   └── script.py.mako
├── project
│   ├── core
│   │   ├── __init__.py
│   │   └── config.py
│   └── __init__.py
├── __init__.py
├── .env
└── main.py

Solution

  • For me it was the fact that .env was not in the same directory as the running script.

    I had to manually anchor the .env file to an absolute path.

    Here is my settings.py file with .env residing alongside in the same directory:

    import os
    
    from pydantic_settings import BaseSettings, SettingsConfigDict
    
    
    DOTENV = os.path.join(os.path.dirname(__file__), ".env")
    
    
    class Settings(BaseSettings):
        pg_dsn: str
        pg_pool_min_size: int
        pg_pool_max_size: int
        pg_pool_max_queries: int
        pg_pool_max_intactive_conn_lifetime: int
    
        model_config = SettingsConfigDict(env_file=DOTENV)
    

    So with the os.path.join(os.path.dirname(__file__), ".env") line I basically instruct to search for .env file inside the same directory as the settings.py file.

    This way you can run any of your scripts, and the Settings object will always point to your .dotenv file.