Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 565 – __main__에서 DeprecationWarning 표시

Author:
Alyssa Coghlan <ncoghlan at gmail.com>
Status:
Final
Type:
Standards Track
Created:
12-Nov-2017
Python-Version:
3.7
Post-History:
12-Nov-2017, 25-Nov-2017
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

Python 2.7 및 Python 3.2에서는 기본 경고 필터가 기본적으로 DeprecationWarning을 숨기도록 업데이트되었습니다. 이에 따라 Python으로 작성된 개발 도구(예: 린터, 정적 분석기, 테스트 실행기, 코드 생성기)의 사용 중단 경고와, 단지 Python으로 작성되었다는 이유만으로 해당되는 다른 애플리케이션의 사용 중단 경고는 사용자가 이를 보도록 명시적으로 선택하지 않는 한 사용자에게 표시되지 않았습니다.

그러나 이러한 변경은 API의 변경으로 인한 호환성 중단(CPython, 표준 라이브러리 또는 서드파티 라이브러리 중 어느 쪽이든)에 대해 해당 API 사용자에게 사전 통지를 제공한다는 본래의 주요 목적에서 DeprecationWarning의 효과를 현저히 떨어뜨리는 안타까운 부작용을 초래했습니다.

이러한 상황을 개선하기 위해 이 PEP에서는 기본 경고 필터를 한 가지 조정하여, 기본적으로 주 모듈에 귀속된 사용 중단 경고를 표시할 것을 제안합니다.

이 변경으로 대화형 프롬프트에 입력한 코드와 단일 파일 스크립트의 코드는 이러한 경고를 기본적으로 다시 보고하게 되지만, 가져올 수 있는 모듈의 일부로 배포되는 패키지화된 코드에서는 계속 기본적으로 표시되지 않습니다.

또한 이 PEP에서는 새로운 Python 개발자가 경고 하위 시스템에 더 쉽게 접근할 수 있도록 참조 인터프리터와 표준 라이브러리 문서에 여러 가지 작은 조정을 제안합니다.

문서 업데이트의 일환으로, unittest 테스트 실행기가 테스트 케이스를 실행할 때 기본적으로 모든 경고를 표시한다는 점과 다른 테스트 실행기도 이 사례를 따를 것을 권장한다는 점을 더욱 명확히 설명합니다.

사양

새로운 기본 경고 필터 항목

현재 기본 경고 필터 집합은 다음으로 구성됩니다.:

ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::BytesWarning
ignore::ResourceWarning

그런 다음 기본 unittest 테스트 실행기는 테스트 케이스를 실행하는 동안 warnings.catch_warnings()warnings.simplefilter('default')를 사용하여 기본 필터를 재정의합니다.

이 PEP에서 제안하는 변경은 기본 경고 필터 목록을 다음과 같이 업데이트하는 것입니다.:

default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::BytesWarning
ignore::ResourceWarning

이는 경고의 명목상 위치(warnings.warnstacklevel 매개변수로 결정됨)가 __main__ 모듈에 있는 경우, 각 DeprecationWarning의 최초 발생이 다시 보고된다는 의미입니다.

이 변경으로 다음 코드에서는 DeprecationWarning이 기본적으로 표시됩니다.

  • 대화형 프롬프트에서 직접 실행되는 코드
  • 단일 파일 스크립트의 일부로 직접 실행되는 코드

다음 코드에서는 계속 기본적으로 표시되지 않습니다.

  • zipapp 아카이브의 __main__.py 파일에서 다른 모듈로부터 가져온 코드
  • 실행 가능한 패키지의 __main__ 서브모듈에서 다른 모듈로부터 가져온 코드
  • console_scripts 또는 gui_scripts 진입점 정의를 기반으로 설치 시 생성된 실행 가능한 스크립트 래퍼에서 가져온 코드

이는 사용자를 대상으로 배포하기 위해 설치 가능하거나 실행 가능한 아티팩트(예: zipapp 아카이브)를 만드는 도구 개발자에게는 현재 상태와 달라지는 점이 없다는 의미입니다. 반면 보다 임시적인 개인용 또는 로컬 배포 스크립트의 사용자는 관련 사용 중단 경고를 다시 보기 시작할 가능성이 높습니다(Python 2.6 및 그 이전 버전에서 그랬던 것처럼).

FutureWarning의 추가 사용 사례

표준 라이브러리 문서는 애플리케이션의 사용자에게 표시되도록 의도된 하위 호환성 경고에는 DeprecationWarning 대신 FutureWarning을 사용하도록 명시적으로 권장하는 방향으로 업데이트됩니다. (이는 앞으로도 유효한 코드로 남지만 의미가 달라질 구문에 대해 경고하는 기존의 FutureWarning 사용에 더해지는 것입니다.)

이에 따라 하위 호환성 경고는 다음과 같이 서로 다른 대상 독자를 갖는 세 가지 구별되는 범주로 나뉩니다.

  • PendingDeprecationWarning: 모든 코드에서 기본적으로 숨겨집니다. 대상 독자는 소프트웨어의 향후 호환성을 보장하는 데 적극적인 관심을 두는 Python 개발자입니다(예: 특정 지원 의무가 있는 전문 Python 애플리케이션 개발자).
  • DeprecationWarning: __main__ 모듈에서 직접 실행되는 코드에 대해서는 기본적으로 보고되지만(이러한 코드는 전용 테스트 모음을 갖고 있을 가능성이 상대적으로 낮다고 간주되기 때문임), 다른 모듈의 코드에서는 기본적으로 숨겨집니다. 대상 독자는 의존성 업그레이드(Python 자체의 업그레이드 포함)로 인해 소프트웨어가 손상될 위험이 있는 Python 개발자입니다(예: 다른 사람이 의존성 업그레이드 시점을 관리하는 환경을 Python으로 스크립팅하는 개발자).
  • FutureWarning: 모든 코드에서 기본적으로 보고됩니다. 대상 독자는 다른 Python 개발자가 아니라 Python으로 작성된 애플리케이션의 사용자입니다(예: 구성 파일 형식에서 사용 중단된 설정의 사용에 대한 경고).

API 호환성 경고가 사용자에게 더 안정적으로 표시되도록 하려는 라이브러리 및 프레임워크 작성자에게는 Python 3.7 이상에서는 DeprecationWarning에서 파생되는 사용자 지정 경고 클래스를 사용하고, 이전 버전에서는 FutureWarning에서 파생되는 클래스를 사용할 것을 권장합니다.

테스트 실행기를 위한 권장 필터 설정

테스트 실행기 개발자는 기본 경고 필터를 결정할 때 다음과 동등한 로직을 구현하는 것이 좋습니다.:

if not sys.warnoptions:
    warnings.simplefilter("default")

이는 명령줄 옵션 -Wd를 전달한 것처럼 기본적으로 모든 경고를 활성화합니다.

테스트 모음에서 BytesWarning을 실제로 활성화하려면 명령줄에서 인터프리터에 -b 옵션을 전달해야 한다는 점에 유의하십시오. 암시적 바이트 변환 및 바이트 비교 경고의 경우, 경고 필터 메커니즘은 해당 경고를 경고로 출력할지 예외로 발생시킬지만 결정합니다. 명령줄 플래그가 설정되지 않으면 인터프리터는 애초에 경고를 발생시키지도 않습니다.

대화형 셸을 위한 권장 필터 설정

대화형 셸 개발자는 사용자 코드가 입력되고 실행되는 네임스페이스에서 DeprecationWarning을 활성화하는 필터를 추가하는 것이 좋습니다.

해당 네임스페이스가 __main__이라면(기본 CPython REPL의 경우처럼), 이 PEP에서 변경하는 사항 외에는 아무것도 변경할 필요가 없습니다.

__main__이 아닌 네임스페이스를 사용하는 대화형 셸 구현은 자체 필터를 추가해야 합니다. 예를 들어 IPython은 적절한 필터를 설정하기 위해 다음 명령([6])을 사용합니다.:

warnings.filterwarnings("default", category=DeprecationWarning,
                                   module=self.user_ns.get("__name__"))

기타 문서 업데이트

현재 경고 시스템의 참조 문서는 특정 최종 결과를 얻을 수 있는 -W 명령줄 옵션 또는 PYTHONWARNINGS 환경 변수의 가능한 설정 예시를 구체적으로 설명하는 부분이 비교적 부족합니다.

이 PEP의 구현의 일부로 다음 개선 사항을 제안합니다.

  • PYTHONWARNINGS 환경 변수에 대한 설명 아래에 다음 항목을 명시적으로 나열합니다.:
    PYTHONWARNINGS=error # Convert to exceptions
    PYTHONWARNINGS=always # Warn every time
    PYTHONWARNINGS=default # Warn once per call location
    PYTHONWARNINGS=module # Warn once per calling module
    PYTHONWARNINGS=once # Warn once per Python process
    PYTHONWARNINGS=ignore # Never warn
    
  • -W 명령줄 스위치 문서에 나열된 각 경고 동작에 해당하는 단축 옵션(-We, -Wa, -Wd, -Wm, -Wo, -Wi)을 명시적으로 나열합니다.
  • action::categoryaction::category:module표기법을 사용하여 warnings 모듈 문서에 기본 필터 집합을 명시적으로 나열합니다.
  • PYTHONWARNINGS 또는 -W 명령줄 스위치를 통해 경고를 다시 활성화할 수 있도록 하면서 Python 애플리케이션에서 기본적으로 모든 경고를 끄는 권장 방법으로, 다음 코드 조각을 warnings.simplefilter 문서에 명시적으로 나열합니다.:
    if not sys.warnoptions:
        warnings.simplefilter("ignore")
    

이들 중 어느 것도 새로운 것은 아닙니다(아직 지원되는 모든 Python 버전에서 이미 작동합니다). 그러나 관련 문서의 현재 구조를 고려하면 특히 명확하지 않습니다.

참조 구현

이 PEP의 관련 트래커 이슈 [5]에 링크된 PR [4]에서 참조 구현을 확인할 수 있습니다.

이 PEP를 구현한 부수적인 결과로, 내부 경고 필터 목록은 기존의 컴파일된 정규 표현식 사용에 더해 필터 정의의 일부로 일반 문자열을 사용할 수 있게 됩니다. 일반 문자열이 있으면 정확히 일치하는 경우에만 비교됩니다. 이 방법을 사용하면 re 모듈에 조기에 접근할 필요 없이 인터프리터 시작 중에 새로운 기본 필터를 추가할 수 있습니다.

동기

[1]에서 논의되고 [2]에서 언급된 것처럼, Python 2.7과 Python 3.2는 DeprecationWarning의 기본 처리를 다음과 같이 변경했습니다.

  • 정상적인 코드 실행 중에는 기본적으로 경고가 숨겨졌습니다.
  • unittest 테스트 실행기는 테스트를 실행할 때 해당 경고를 다시 활성화하도록 업데이트되었습니다.

그 목적은 다음과 같은 도구 출력이 발생하는 경우를 피하는 것이었습니다.:

$ devtool mycode/
/usr/lib/python3.6/site-packages/devtool/cli.py:1: DeprecationWarning: 'async' and 'await' will become reserved keywords in Python 3.7
  async = True
... actual tool output ...

devtool이 Python 프로그래머를 위한 도구라고 하더라도, 이 경고는 호출할 때마다 표시되므로 특별히 유용하지 않습니다. 최종 사용자가 취할 수 있는 가장 유용한 조치는 devtool개발자에게 버그를 보고하는 것뿐이기 때문입니다.

이 경고는 Python 이외의 여러 언어에서 사용되는 범용 개발 도구에는 더욱 덜 유용하며, 단지 Python으로 작성되었을 뿐이고 반드시 개발자 대상이 아닌 애플리케이션에는 거의 전혀 *도움이 되지 않습니다*.

그러나 이 변경은 다음 사용자층에 의도하지 않은 결과를 초래하는 것으로 밝혀졌습니다.

  • unittest에 내장된 기본 테스트 실행기 이외의 테스트 실행기를 사용하는 모든 사람입니다(서드파티 테스트 실행기가 기본 경고 필터를 변경해 달라는 요청이 명시적으로 이루어진 적이 없으므로, 많은 테스트 실행기가 여전히 배포된 애플리케이션에 맞게 설계된 인터프리터 기본값에 의존합니다).
  • 기본 unittest 테스트 러너를 사용해 서브프로세스에서 자신의 Python 코드를 테스트하는 사람(unittest조차 현재 프로세스의 경고 설정만 조정하기 때문입니다)
  • 대화형 프롬프트에서 또는 Python 수준의 테스트 스위트가 전혀 없는 직접 실행 스크립트의 일부로 Python 코드를 작성하는 사람

이러한 경우, DeprecationWarning은 결국 PendingDeprecationWarning과 거의 완전히 동등해졌습니다: 그저 전혀 보이지 않았을 뿐입니다.

PEP 범위의 한계

이 PEP는 3.7을 위해 제안된 기본 경고 필터 추가 사항을 설명함과 동시에, Python 2.7과 3.2에서 있었던 DeprecationWarning 처리에 대한 원래 변경의 근거를 더 명확하게 설명하기 위해 존재합니다.

이 PEP는 폐지 예정 경고 처리에 대한 현재 접근 방식이 가진 모든 알려진 문제를 해결하지는 않습니다. 특히 다음이 그러합니다:

  • 기본 unittest 테스트 러너는 현재 모듈 임포트 시점에 발생하는 폐지 예정 경고를 보고하지 않는데, 경고 필터 재정의가 테스트 발견 및 로딩 중이 아니라 테스트 실행 중에만 적용되기 때문입니다.
  • 기본 unittest 테스트 러너는 현재 서브프로세스에서 발생하는 폐지 예정 경고를 보고하지 않는데, 경고 필터 재정의가 PYTHONWARNINGS 환경 변수가 아니라 로드된 warnings 모듈에 직접 적용되기 때문입니다.
  • 표준 라이브러리는 특정 의존성을 업그레이드하기 전에 그 의존성에 의해 발생하는 모든 경고를 확인하도록 선택 가입할 수 있는 간단한 방법을 제공하지 않습니다(서드파티 warn 모듈 [3] 은 이를 제공하지만, 활성화하려면 표준 라이브러리의 warnings 모듈을 몽키패치해야 합니다).
  • 소프트웨어가 지원 모듈로 분리되었지만 그 모듈들에 자동화된 테스트 커버리지가 거의 또는 전혀 없는 경우, __main__에서 폐지 예정 경고를 기본으로 다시 활성화한다고 해서 API 호환성 문제를 찾는 데 도움이 될 가능성은 낮습니다. 단기적으로, 현재 사용 가능한 최선의 답은 영향을 받는 애플리케이션을 PYTHONWARNINGS=default::DeprecationWarning 또는 python -W default::DeprecationWarning으로 실행하고 그 stderr 출력에 주의를 기울이는 것입니다. 장기적으로, 이는 실제로 Python 코드의 정적 분석을 연구하는 연구자들을 위한 질문입니다: 폐지 예정 API의 사용을 어떻게 신뢰성 있게 찾아낼 것인가, 그리고 API를 제공하는 코드나 그것에 접근하는 코드를 실제로 실행하지 않고서 warnings.warn 호출을 근거로 어떤 API나 매개변수가 폐지 예정임을 어떻게 추론할 것인가 하는 것입니다.

이들이 현재 상태가 가진 실제 문제이기는 하지만, 기본 경고 필터에 항목 하나를 추가하는 것보다 더 복잡한 해법이 필요할 것이고, 이를 해결하는 데 적어도 잠재적으로는 PEP 절차를 거칠 필요가 없을 것이기 때문에 이 PEP의 고려 대상에서 제외됩니다.

이를 더 추진하는 데 관심이 있는 사람을 위해 말하자면, 앞의 두 가지는 unittest 모듈 개선 요청이 될 것이고, 세 번째는 warnings 모듈 개선 요청이 될 것이며, 마지막 것은 그 내용으로부터 API 폐지 예정을 추론하는 것이 다루기 어려운 코드 분석 문제로 판명되어 어노테이션에 명시적인 함수 및 매개변수 마커 구문이 대신 제안되는 경우에만 PEP가 필요할 것입니다.

CPython 참조 구현에는 3.7에서 다음과 같은 관련 변경 사항도 포함될 것입니다:

이 PEP에서 제안하는 기본 필터 변경과는 별개로, 이슈 32229 [7]는 애플리케이션 개발자가 일반 운영 중에는 경고를 쉽게 숨기고 테스트 시에는 쉽게 보이게 만들 수 있도록 warnings.hide_warnings API를 추가하자는 제안입니다.

참고 문헌