환경변수로 사용할 부분을 .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
아마 나와 비슷한 이유로 문제가 생긴것 같은데,
사실은, 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을 껐다키고, 컴퓨터를 껐다켜도 계속 유지되었다... 이 글을 보신 분들 중에 이유를 아시는 분 있으면 꼭 알려주시면 감사하겠습니다 ㅠ)
'Python' 카테고리의 다른 글
Python: 서버 부하테스트 - locust (0) | 2024.01.22 |
---|---|
Python: datetime strftime strptime 의미 구분, # 어떤 의미? (0) | 2023.12.09 |
Python: class inheritance MRO, super # method resolution order # super # 상속 순서 # 부모 클래스 # 초기화 (0) | 2023.12.06 |
Python: [False] and [True] # falsy values in python # [False] or [True] # bool (1) | 2023.12.02 |
멀티프로세싱, 멀티스레딩 이해하기 with Python (0) | 2023.12.02 |