warnings — 경고 제어
warnings — 경고 제어
경고 메시지는 일반적으로 프로그램의 어떤 조건에 대해 사용자를 경고하는 것이 유용한 상황에서 발행되는데, 그 조건이 (보통) 예외를 발생시키고 프로그램을 종료할 만큼 심각하지 않을 때예요. 예를 들어 프로그램이 더 이상 사용되지 않는(obsolete) 모듈을 사용할 때 경고를 발행하고 싶을 수 있어요.
Python 프로그래머는 이 모듈에 정의된 warn() 함수를 호출해 경고를 발행해요. 경고 메시지는 보통 sys.stderr에 기록되지만, 그 처리는 모든 경고를 무시하는 것부터 예외로 바꾸는 것까지 유연하게 변경할 수 있어요. 경고의 처리는 경고 범주, 경고 메시지의 텍스트, 발행된 소스 위치에 따라 달라질 수 있어요.
본문
경고 제어에는 두 단계가 있어요. 첫째, 경고가 발행될 때마다 메시지를 발행할지 여부를 결정하고, 둘째, 메시지를 발행한다면 사용자가 설정할 수 있는 훅을 사용해 형식화하고 인쇄해요.
경고 메시지를 발행할지 여부는 일치 규칙과 동작(action)의 시퀀스인 경고 필터(warning filter)로 제어돼요. filterwarnings()를 호출해 필터에 규칙을 추가하고, resetwarnings()를 호출해 기본 상태로 재설정할 수 있어요. 경고 메시지의 인쇄는 재정의할 수 있는 showwarning()을 호출해 이루어지며, 기본 구현은 formatwarning()으로 메시지를 형식화해요.
logging.captureWarnings()를 사용하면 모든 경고를 표준 logging 인프라로 처리할 수 있어요.
경고 범주 (Warning Categories)
경고 범주를 나타내는 여러 내장 예외가 있어요. 이 분류는 경고 그룹을 필터링하는 데 유용해요. 사용자 코드는 표준 경고 범주 중 하나를 하위 클래스화해 추가 경고 범주를 정의할 수 있어요. 경고 범주는 항상 Warning 클래스의 하위 클래스여야 해요.
현재 정의된 경고 범주 클래스:
| 클래스 | 설명 |
|---|---|
| Warning | 경고 범주의 기본 클래스. Exception의 하위 클래스 |
| UserWarning | 사용자 코드가 생성한 경고의 기본 클래스. warn()의 기본 범주 |
| DeprecationWarning | 다른 Python 개발자를 대상으로 하는 더 이상 사용되지 않는 기능 경고의 기본 클래스(기본적으로 무시됨) |
| PendingDeprecationWarning | 미래에 더 이상 사용되지 않을 기능에 대한 경고의 기본 클래스(기본적으로 무시됨) |
| SyntaxWarning | 의심스러운 구문에 대한 경고의 기본 클래스 |
| RuntimeWarning | 의심스러운 런타임 동작에 대한 경고의 기본 클래스 |
| FutureWarning | Python으로 작성된 애플리케이션의 최종 사용자를 대상으로 하는 더 이상 사용되지 않는 기능 경고의 기본 클래스 |
| ImportWarning | 모듈을 import하는 과정에서 트리거되는 경고의 기본 클래스(기본적으로 무시됨) |
| UnicodeWarning | Unicode 관련 경고의 기본 클래스 |
| EncodingWarning | 인코딩 관련 경고의 기본 클래스 |
| BytesWarning | bytes와 bytearray 관련 경고의 기본 클래스 |
| ResourceWarning | 자원 사용 관련 경고의 기본 클래스(기본적으로 무시됨) |
경고 필터 (The Warnings Filter)
경고 필터는 경고를 무시할지, 표시할지, 오류로 바꿀지(예외 발생) 제어해요. 개념적으로 경고 필터는 필터 사양의 정렬된 목록을 유지하며, 특정 경고는 일치가 발견될 때까지 목록의 각 필터 사양에 차례로 대조돼요. 각 항목은 (action, message, category, module, lineno) 형태의 튜플이에요.
action은 다음 문자열 중 하나예요:
"default"— 경고가 발행된 각 위치(모듈 + 줄 번호)에 대한 일치 경고의 첫 발생만 인쇄"error"— 일치 경고를 예외로 변환"ignore"— 일치 경고를 절대 인쇄하지 않음"always"— 일치 경고를 항상 인쇄"all"— "always"의 별칭"module"— 경고가 발행된 각 모듈(줄 번호 무시)에 대한 첫 발생만 인쇄"once"— 위치에 관계없이 일치 경고의 첫 발생만 인쇄
message는 경고 메시지의 시작이 일치해야 하는 정규 표현식을 포함하는 문자열이에요(대소문자 무시). category는 경고 범주가 일치하려면 그 하위 클래스여야 하는 클래스예요. module은 정규 표현식을 포함하는 문자열, lineno는 경고가 발생한 줄 번호 또는 모든 줄 번호와 일치할 0이에요.
경고가 보고되었고 등록된 필터와 일치하지 않으면 "default" 동작이 적용돼요. Warning 클래스는 내장 Exception 클래스에서 파생되므로, 경고를 오류로 바꾸려면 간단히 category(message)를 발생시키면 돼요.
경고 필터 설명 (Describing Warning Filters)
경고 필터는 Python 인터프리터 명령줄에 전달된 -W 옵션과 PYTHONWARNINGS 환경 변수로 초기화돼요. 개별 경고 필터는 콜론으로 구분된 필드 시퀀스로 지정돼요:
action:message:category:module:line
PYTHONWARNINGS의 경우 필터는 쉼표로 구분되며, 나중에 나열된 필터가 이전 필터보다 우선해요. 일반적으로 사용되는 경고 필터 예:
default # 모든 경고 표시 (기본적으로 무시되는 것 포함)
ignore # 모든 경고 무시
error # 모든 경고를 오류로 변환
error::ResourceWarning # ResourceWarning 메시지를 오류로 처리
default::DeprecationWarning # DeprecationWarning 메시지 표시
ignore,default:::mymodule # "mymodule"이 트리거한 경고만 보고
기본 경고 필터 (Default Warning Filter)
기본적으로 Python은 여러 경고 필터를 설치하며, -W 명령줄 옵션, PYTHONWARNINGS 환경 변수, filterwarnings() 호출로 재정의할 수 있어요. 일반 릴리스 빌드에서 기본 경고 필터는 (우선순위 순서로) default::DeprecationWarning:__main__, ignore::DeprecationWarning, ignore::PendingDeprecationWarning, ignore::ImportWarning, ignore::ResourceWarning 항목을 가져요. 디버그 빌드에서는 기본 경고 필터 목록이 비어 있어요.
일시적으로 경고 억제 (Temporarily Suppressing Warnings)
더 이상 사용되지 않는 함수처럼 경고를 발생시킬 것임을 아는 코드를 사용하면서 경고를 보고 싶지 않을 때는 catch_warnings 컨텍스트 매니저로 경고를 억제할 수 있어요:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
경고 테스트 (Testing Warnings)
catch_warnings 컨텍스트 매니저를 사용해 코드가 발생시키는 경고를 테스트할 수 있어요. record=True를 사용하면 경고 목록을 캡처해 검사할 수 있어요:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
fxn()
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
사용 가능한 함수 (Available Functions)
- *warnings.warn(message, category=None, stacklevel=1, source=None, , skip_file_prefixes=()) — 경고를 발행하거나, 무시하거나, 예외를 발생시켜요.
category인자가 주어지면 경고 범주 클래스여야 하고, 기본값은UserWarning이에요.stacklevel인자는 Python으로 작성된 래퍼 함수가 사용할 수 있어요. - warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None) —
warn()기능의 저수준 인터페이스로, 메시지, 범주, 파일 이름, 줄 번호를 명시적으로 전달해요. - warnings.showwarning(message, category, filename, lineno, file=None, line=None) — 경고를 파일에 기록해요.
- warnings.formatwarning(message, category, filename, lineno, line=None) — 경고를 표준 방식으로 형식화해요.
- warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False) — 경고 필터 사양 목록에 항목을 삽입해요.
- warnings.simplefilter(action, category=Warning, lineno=0, append=False) — 경고 필터 사양 목록에 간단한 항목을 삽입해요.
- warnings.resetwarnings() — 경고 필터를 재설정해요.
- *@warnings.deprecated(message, /, , category=DeprecationWarning, stacklevel=1) — 클래스, 함수, 오버로드가 더 이상 사용되지 않음을 나타내는 데코레이터예요. (버전 3.13에서 추가, PEP 702 참고)
사용 가능한 컨텍스트 매니저 (Available Context Managers)
classwarnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False) — 경고 필터와 showwarning() 함수를 복사하고, 종료 시 복원하는 컨텍스트 매니저예요. record가 True이면 사용자 정의 showwarning() 함수로 보이는 객체로 점차 채워지는 목록이 반환돼요. 목록의 각 객체는 message, category, filename, lineno, file, line, source 속성을 가져요.
컨텍스트 매니저의 동시성 안전 (Concurrent safety of Context Managers)
catch_warnings 컨텍스트 매니저의 동작은 sys.flags.context_aware_warnings 플래그에 따라 달라져요. 플래그가 true이면 컨텍스트 매니저는 동시성 안전 방식(스레드 안전하며 asyncio 코루틴과 태스크에서 안전)으로 동작하고, 그렇지 않으면 그렇지 않아요. 플래그 때문에 catch_warnings는 전역 속성을 수정하지 않고 ContextVar를 사용해 새로 설정된 경고 필터링 상태를 저장해요. 이 플래그는 -X context_aware_warnings 명령줄 옵션이나 PYTHON_CONTEXT_AWARE_WARNINGS 환경 변수로 설정할 수 있어요.