pydantic: BaseSettings can't read from .env file

Bug

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.3
            pydantic compiled: True
                 install path: /home/xxx/playground/fastapi/.venv/lib/python3.6/site-packages/pydantic
               python version: 3.6.9 (default, Nov  7 2019, 10:44:02)  [GCC 8.3.0]
                     platform: Linux-5.3.0-7642-generic-x86_64-with-Ubuntu-18.04-bionic
     optional deps. installed: ['email-validator']

The example is from here https://github.com/samuelcolvin/pydantic/pull/1011 and still don’t work. Documentation don’t help also.

Note that I removed default value for Settings.foo

.env

foo=baz

settings.py

from pydantic import BaseSettings


class Settings(BaseSettings):
    foo: str = 'bar'

    class Config:
        env_file = ".env"


settings = Settings()

Exception

In [1]: from settings import settings
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
<ipython-input-1-89c4f5117928> in <module>
----> 1 from settings import settings

~/playground/fastapi/settings.py in <module>
      9 
     10 
---> 11 settings = Settings()

~/playground/fastapi/.venv/lib/python3.6/site-packages/pydantic/env_settings.cpython-36m-x86_64-linux-gnu.so in pydantic.env_settings.BaseSettings.__init__()

~/playground/fastapi/.venv/lib/python3.6/site-packages/pydantic/main.cpython-36m-x86_64-linux-gnu.so in pydantic.main.BaseModel.__init__()

ValidationError: 1 validation error for Settings
foo
  field required (type=value_error.missing)

In [2]: 

If I load_dotenv() manually - it works:

In [2]: from dotenv import load_dotenv

In [3]: load_dotenv()
Out[3]: True

In [4]: from settings import settings

In [5]: settings
Out[5]: Settings(foo='baz')

In [6]: 

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (5 by maintainers)

Most upvoted comments

This is very likely because your .env is not in the current working directory.

From the docs:

either absolute or relative to the current working directory.

E.g. .env being in the same directory as config.py doesn’t matter.

We should make this notice more obvious in the docs to stop all these questions.

That said, it is already in the docs, please try to read them before posting questions on closed issues.

Hi!

Either I do not understand the concept of current directory or something completely unexpected keeps happening.

To better understand the cause of exceptions, I’ve created the minimal working example with the following project structure:

myapp/
    settings.py
.env
app.py

where in the settings.py I have the following code:

from pydantic import BaseSettings
from pathlib import Path
import os
env_location = Path("./.env").resolve()
print(env_location)
print(Path(os.curdir).resolve())
print("File exists", env_location.exists())

class Settings(BaseSettings):
    VAR1: str
    VAR2: str
    
    class Config:
        case_sensitive = True
        _env_file=env_location,
        _env_file_encoding="utf-8"

settings = Settings()

which is then imported in app.py , which I run with python app.py.

The output is:

/research_pydantic_settings/.env
/research_pydantic_settings
File exists True
Traceback (most recent call last):
pydantic.error_wrappers.ValidationError: 2 validation errors for Settings
VAR1
  field required (type=value_error.missing)
VAR2
  field required (type=value_error.missing)

The docs says “In either case, the value … can be any valid path or filename, either absolute or relative to the current working directory.” I tried both. No effect. If I do print the contents of .env file in settings.py script, everything works fine.

Getting the same issue with v1.6. Shouldn’t this be able to work without needing to call load_dotenv()?

It worked for me only with load_dotenv(), so can confirm this is not working nor with relative nor with absolute paths or I’m doing something wrong

If you are using py-dotenv, you can use find_dotenv to locate your file:

from dotenv import find_dotenv
from pydantic import BaseSettings

class Settings(BaseSettings):
    ...

    class Config:
        env_file = find_dotenv(".env")
        env_file_encoding = "utf-8"

on pydantic 2.4.2

this works for me:

config.py

from pydantic_settings import BaseSettings, SettingsConfigDict
from dotenv import find_dotenv, load_dotenv

load_dotenv(find_dotenv(".env"))

class Config(BaseSettings):
    ...
    
    model_config = SettingsConfigDict(case_sensitive=True)

I had to combine python-dotenv’s load_env and find_dotenv.

The .env file was in the parent directory of the config.py.

IT works only if i add .env in the same directory as config.py :

from dotenv import load_dotenv
load_dotenv()

class Settings(BaseSettings):
    API_V1_STR: str
    class Config:
        env_file = ".env"

@HenryDashwood The issue here is that you use ~/.env, which is not directly resolved by pathlib.Path. You could change it to

   class Config:
        env_file = os.path.expanduser('~/.env')

Maybe we could add expanduser directly in the code when env_path is created

Yep, I had the same issue, where the config.py is at a different, deeper folder than .env file (project root folder). I move config.py to the root folder, it works. Would be nice to be able to have config.py in any folder, with future pydantic release.

IT works only if i add .env in the same directory as config.py :

from dotenv import load_dotenv
load_dotenv()

class Settings(BaseSettings):
    API_V1_STR: str
    class Config:
        env_file = ".env"

Hi! In my case I used clear config.py with “.env”

from pydantic import BaseSettings

class Settings(BaseSettings):
    
    class Config:
        env_file = ".env"
        env_file_encoding = 'utf-8'

installing pydantic with dotenv pip install pydantic[dotenv]

@orihomie I had the same issue because I had nested settings classes. To address the issue, I had to add .env file configuration explicitly in each class.