본문 바로가기

Python

Python: python-dotenv - .env 파일 관련 library # load_dotenv # override

728x90
반응형

환경변수로 사용할 부분을 .env 파일로 따로 빼서 관리하는 경우에,

파이썬에서 해당 파일에서 변수를 불러오는 방법중의 하나로 python-dotenv 라이브러리가 있다.

 

설치: 

pip install python-dotenv

 

from dotenv import load_dotenv
import os

load_dotenv()	# .env에 있는 변수를 환경변수로 불러오기

os.getenv("DEBUG", False) # 환경변수에서 "DEBUG"로 이름이 되어있는 변수의 값 가져오기, 없을경우 False를 default 값으로 사용

 

위와 같이 하면 일반적으로  된다.

 

그런데, 잘 작업을 하던 중에 이상한 에러가 발생...

# .env

DEBUG = "False"  # True or False

 

.env 파일에 위와 같이 설정한 DEBUG 값을 가져오기 위해

load_dotenv()후에 os.getenv("DEBUG") 이용하는데 오류가 발생

os.getenv("DEBUG")를 print로 찍어보니 다음과 같이 찍힌다.

'"False"  # True or False'

 

....

DEBUG = 하고 찍은 부분이 주석까지 하나의 string으로 잡혀서 출력

갑자기 문제가 발생해서 어떻게 된것인지는 더 디버깅을 해봐야겠지만, 나와 비슷한 문제가 생겨서

이슈를 제기한 사람이 있는듯 했다.

그런데 이 분은 _(언더스코어)를 2개 쓰면 출력이 안된다고 생각하고 이슈를 올렸다.

https://github.com/theskumar/python-dotenv/issues/485

 

Two underscores w/ load_dotenv() == None · Issue #485 · theskumar/python-dotenv

Using two underscores seems to cause load_dotenv() to fail. Works .env NEW_FEATUREENABLED=no app.py import os from dotenv import load_dotenv load_dotenv() new_feature = os.getenv("NEW_FEATUREENABLE...

github.com

 

아마 나와 비슷한 이유로 문제가 생긴것 같은데,

 

사실은, load_dotenv()로 뒤의 주석까지 변수의 값으로 불려온게 아니다.

내가 무엇을 어떻게 잘못 만졌는지 모르겠지만 '"False"  # True or False'이 DEBUG의 값으로 환경변수에 들어가 있는 상태이다.

load_dotenv()로 .env 파일의 DEBUG 값을 가져온게 아니라 이미 등록이 되어있다는 말이다..

이는 load_dotenv() 함수를 뜯어보면 알 수 있다.

 

# venv에 설치한 경로 확인
# venv>lib>python3.11>site-packages>dotenv>main.py

...

def load_dotenv(
    dotenv_path: Optional[StrPath] = None,
    stream: Optional[IO[str]] = None,
    verbose: bool = False,
    override: bool = False,
    interpolate: bool = True,
    encoding: Optional[str] = "utf-8",
) -> bool:
    if dotenv_path is None and stream is None:
        dotenv_path = find_dotenv()

    dotenv = DotEnv(
        dotenv_path=dotenv_path,
        stream=stream,
        verbose=verbose,
        interpolate=interpolate,
        override=override,
        encoding=encoding,
    )
    return dotenv.set_as_environment_variables()
    
 # Dotenv
 class DotEnv:
    def __init__(
        self,
        dotenv_path: Optional[StrPath],
        stream: Optional[IO[str]] = None,
        verbose: bool = False,
        encoding: Optional[str] = None,
        interpolate: bool = True,
        override: bool = True,
    ) -> None:
        self.dotenv_path: Optional[StrPath] = dotenv_path
        self.stream: Optional[IO[str]] = stream
        self._dict: Optional[Dict[str, Optional[str]]] = None
        self.verbose: bool = verbose
        self.encoding: Optional[str] = encoding
        self.interpolate: bool = interpolate
        self.override: bool = override

    ...

    def set_as_environment_variables(self) -> bool:
        """
        Load the current dotenv as system environment variable.
        """
        if not self.dict():
            return False

        for k, v in self.dict().items():
            if k in os.environ and not self.override:
                continue
            if v is not None:
                os.environ[k] = v

        return True

 

 

load_dotenv 함수는 Dotenv 클래스로부터 인스턴스를 만들어서,

해당 인스턴스의 set_as_environment_variables 메소드를 실행한다.

위 메소드를 살펴보면,

if v is not None:의 경우에 환경변수에 값을 등록한다. 즉, 환경변수에 이미 값이 없을때만 등록하는 로직이다.

 

위의 이슈에서 제기되었던 load_dotenv()가 언더스코어가 2개가 있는 경우에 안되었던 것은,

저 이슈제기자가 사용한 변수가 이미 환경변수에 들어가 있어서 안되어 있었을 것이다.

 

그렇다면, 이미 잘못된 값이 들어가 있거나, 그런 경우를 대비해서 항상 .env 파일의 변수를 환경변수에 등록하는

방법은 없을까?

load_dotenv에 override=True 옵션을 사용하면 된다. (default는 False로 되어있다.)

load_dotenv(override=True)

 

위와 같이 하면

set_as_environment_variables 메소드의 if 조건 중에서 not self.override 부분이 False가 돼서 continue가 아닌 다음 if문으로 들어가서 환경변수 값이 기존에 있더라도 load_dotenv 메소드로 찾은 변수 값으로 덮어씌울 수 있다.

 

(나는 무엇을 건드렸길래 원치 않는 환경변수 값이 들어가있었을까... shell을 껐다키고, 컴퓨터를 껐다켜도 계속 유지되었다... 이 글을 보신 분들 중에 이유를 아시는 분 있으면 꼭 알려주시면 감사하겠습니다 ㅠ)

728x90
반응형