PEP 534 – 누락된 표준 라이브러리 모듈에 대한 개선된 오류
- Author:
- Tomáš Orsava <tomas.n at orsava.cz>, Petr Viktorin <encukou at gmail.com>, Alyssa Coghlan <ncoghlan at gmail.com>
- Status:
- Withdrawn
- Type:
- Standards Track
- Created:
- 05-Sep-2016
- Post-History:
Table of Contents
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
Python은 전체 표준 라이브러리 없이 빌드되거나 배포되는 경우가 많습니다. 그러나 이러한 누락된 표준 라이브러리 모듈을 가져오지 못한 사실을 사용자에게 적절히 알리는 표준적이고 사용자 친화적인 방법은 아직 없습니다.
이 PEP는 예상되는 표준 라이브러리 모듈을 식별하고, 표준 라이브러리 모듈을 가져오려는 시도가 실패할 때 사용자에게 더 유용한 오류 메시지를 제공하는 메커니즘을 제안합니다.
PEP 철회
핵심 아이디어가 시간이 지나면서 구현되었으므로 저자들은 이 PEP를 철회했습니다. 관련 기능에는 표준 라이브러리 모듈을 나열하는 sys.stdlib_module_names API, 배포자가 사용자 지정 오류 메시지를 제공할 수 있도록 하는 --with-missing-stdlib-config 구성 옵션, 그리고 누락된 standard library 모듈에 대한 개선된 ModuleNotFoundError 오류 메시지가 포함됩니다. 예를 들면 다음과 같습니다.
>>> import zlib
Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
import zlib
ModuleNotFoundError: Standard library module 'zlib' was not found
동기
Python 표준 라이브러리의 일부만 포함해야 하는 몇 가지 사용 사례가 있습니다. 그러나 지금까지 stdlib 모듈이 누락된 이유와 상황을 적절히 해결하는 방법을 사용자에게 알리는 사용자 친화적인 메커니즘은 없습니다.
CPython
Python 표준 라이브러리 모듈 중 하나(예: _sqlite3)를 종속성(예: SQLite 헤더 파일) 누락으로 인해 CPython 빌드 중 컴파일할 수 없으면 해당 모듈은 단순히 건너뜁니다. 그런 다음 이 컴파일된 Python을 설치하고 이를 사용하여 누락된 모듈 중 하나를 가져오려고 하면 Python은 ModuleNotFoundError오류와 함께 실패합니다.
예를 들어 로컬 시스템에서 의도적으로 sqlite-devel을 제거한 후:
$ ./python -c "import sqlite3"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/ncoghlan/devel/cpython/Lib/sqlite3/__init__.py", line 23, in <module>
from sqlite3.dbapi2 import *
File "/home/ncoghlan/devel/cpython/Lib/sqlite3/dbapi2.py", line 27, in <module>
from _sqlite3 import *
ModuleNotFoundError: No module named '_sqlite3'
이로 인해 정상적으로 빌드된 Python에 표준 라이브러리 모듈이 누락된 이유를 이해하지 못하는 사용자가 혼란을 겪을 수 있습니다.
Linux 및 기타 배포판
많은 Linux 및 기타 배포판은 이미 표준 라이브러리의 일부를 독립 실행형 패키지로 분리하고 있습니다. 가장 흔히 제외되는 모듈로는 그래픽 환경에 대한 종속성을 끌어오는 tkinter 모듈, tkinter에 의존하는 idlelib(그리고 대부분의 Linux 데스크톱 환경은 자체 기본 코드 편집기를 제공함), Python을 내부적으로 테스트하는 용도로만 사용되며 표준 라이브러리의 나머지 부분을 모두 합친 것만큼 큰 test 패키지가 있습니다.
이러한 모듈을 제외하는 방법은 서로 다릅니다. 예를 들어 Debian은 Lib/tkinter/__init__.py 파일을 패치하여 import _tkinter 줄을 try-except 블록으로 감싸고, ImportError를 만나면 오류 메시지에 다음을 단순히 추가합니다: please install the python3-tk package [1]. Fedora 및 기타 배포판은 제외된 모듈을 단순히 포함하지 않으므로, 사용자는 해당 모듈을 어디서 찾아야 하는지 몰라 당황할 수 있습니다.
Fedora 29의 예:
$ python3 -c "import tkinter"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'tkinter'
사양
예상되는 표준 라이브러리 모듈을 나열하는 API
어떤 모듈 이름이 표준 라이브러리에서 확인될 것으로 예상되는지 더 쉽게 식별할 수 있도록 sysconfig 모듈을 다음 두 개의 추가 함수로 확장합니다.
sysconfig.get_stdlib_modules()는 모든 최상위 Python 표준 라이브러리 모듈(비공개 모듈 포함)의 이름 목록을 제공합니다.sysconfig.get_optional_modules()는 선택적 공개 최상위 표준 라이브러리 모듈 이름을 나열합니다.
sysconfig.get_optional_modules()의 결과와 기존 sys.builtin_module_names은 모두 새로운 sysconfig.get_stdlib_modules() 함수가 제공하는 전체 목록의 부분 집합입니다.
이러한 추가 목록은 Python 빌드 프로세스 중에 생성되며 다른 sysconfig 값과 함께 _sysconfigdata-*.py 파일에 저장됩니다.
모듈이 “optional” 목록에 포함되는 가능한 이유는 다음과 같습니다.
- 모듈이 선택적 빌드 종속성에 의존합니다(예:
_sqlite3,tkinter,idlelib) - 해당 모듈은 다른 이유로 비공개이므로 모든 구현에 존재하지 않을 수 있습니다(예:
_freeze_importlib,_collections_abc) - 해당 모듈은 플랫폼별 모듈이므로 모든 설치에 존재하지 않을 수 있습니다(예:
winreg) test패키지도 Python 런타임 설치에서 자유롭게 제외할 수 있습니다. Python 구현을 테스트하는 데 사용하기 위한 것이며 Python 프로젝트에서 사용할 런타임 라이브러리가 아니기 때문입니다(테스트 유틸리티를 제공하는 공개 API는unittest입니다)
(참고: ensurepip, venv, distutils 모듈은 모두 이 PEP에서 필수 모듈로 간주합니다. 현재 모든 재배포자가 이 관행을 따르는 것은 아니지만 말입니다)
기본 sys.excepthook 구현 변경
이후 기본 구현의 sys.excepthook 함수는 새 sysconfig 함수 두 개 중 하나에 의해 Python 표준 라이브러리에 속하는 것으로 식별된 모듈의 가져오기에 실패했음을 감지하면 적절한 메시지를 표시하도록 수정됩니다.
선택적 빌드 종속성에 의존하거나 Python 설치 시 기타 이유로 선택 사항으로 간주되는 모듈에 대한 수정된 오류 메시지:
$ ./python -c "import sqlite3"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/ncoghlan/devel/cpython/Lib/sqlite3/__init__.py", line 23, in <module>
from sqlite3.dbapi2 import *
File "/home/ncoghlan/devel/cpython/Lib/sqlite3/dbapi2.py", line 27, in <module>
from _sqlite3 import *
ModuleNotFoundError: Optional standard library module '_sqlite3' was not found
선택적 최상위 패키지 전체가 누락된 경우 해당 패키지의 하위 모듈에 대한 수정된 오류 메시지:
$ ./python -c "import test.regrtest"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: Optional standard library module 'test' was not found
선택적 최상위 패키지가 존재하는 경우 해당 패키지의 하위 모듈에 대한 수정된 오류 메시지:
$ ./python -c "import test.regrtest"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No submodule named 'test.regrtest' in optional standard library module 'test'
항상 사용 가능할 것으로 예상되는 모듈에 대한 수정된 오류 메시지:
$ ./python -c "import ensurepip"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: Standard library module 'ensurepip' was not found
최상위 패키지가 존재하는 경우 표준 라이브러리 패키지의 누락된 하위 모듈에 대한 수정된 오류 메시지:
$ ./python -c "import encodings.mbcs"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No submodule named 'encodings.mbcs' in standard library module 'encodings'
이러한 수정된 오류 메시지는 누락된 모듈이 표준 라이브러리에서 사용 가능할 것으로 예상되지만 어떤 이유로 사용할 수 없다는 점을 명확히 합니다. 현재 환경에서 서드 파티 종속성이 누락되었다는 표시가 아닙니다.
설계 논의
sys.excepthook 수정
sys.excepthook 함수는 발생한 예외가 처리되지 않아 프로그램이 종료되려 할 때 또는 대화형 세션에서 제어가 프롬프트로 반환될 때 호출됩니다. 따라서 이 함수는 사용자 지정 오류 메시지를 위한 완벽한 위치입니다. 처리된 오류에는 영향을 주지 않으므로 Python 스크립트의 정상 실행을 느리게 하지 않기 때문입니다.
예상되는 표준 라이브러리 모듈 이름을 조회하는 공개 API
sysconfig.get_stdlib_modules() 및 sysconfig.get_optional_modules() 함수를 포함하면 오랫동안 요구되어 온 Python 표준 라이브러리 모듈 이름의 간편한 목록화 방법 [2]을 제공할 수 있습니다. 이는 다른 이점과 함께 코드 분석, 프로파일링 및 오류 보고 도구가 런타임 --ignore-stdlib 플래그를 제공하기 쉽게 합니다.
최상위 모듈 이름만 포함
이 PEP는 새 조회 API가 최상위 모듈 및 패키지 이름만 보고하도록 제안합니다. 이는 제안된 오류 메시지를 생성하기에 충분한 정보이며, 필요한 항목 수를 한 자릿수 배로 줄이고, 빌드 과정에서 관련 메타데이터를 생성하는 절차를 단순화합니다.
이것이 결국 지나치게 제한적인 것으로 밝혀지면 새 include_submodules 플래그를 조회 API에 추가할 수 있습니다. 그러나 이렇게 하는 이점이 현재 추가적인 복잡성을 정당화한다고 여겨지지 않으므로, 이는 초기 제안의 일부가 아닙니다.
이 제한의 알려진 결과가 하나 있는데, 새 기본 excepthook 구현이 실제로 누락된 표준 라이브러리 하위 모듈을 보고하는 것과 동일한 방식으로 잘못된 하위 모듈 이름을 보고하게 된다는 점입니다.:
$ ./python -c "import unittest.muck"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No submodule named 'unittest.muck' in standard library module 'unittest'
비공개 최상위 모듈 이름을 선택적 표준 라이브러리 모듈로 나열
선택적 외부 빌드 종속성을 가진 많은 모듈은 하이브리드 모듈로 작성됩니다. 이러한 모듈에는 기본 외부 라이브러리에 대한 구현 종속 인터페이스를 감싸는 공용 Python 래퍼가 있습니다. 그 밖의 경우에는 비공개 최상위 모듈이 단순히 CPython 구현 세부 사항일 수 있으며, 다른 구현에서는 해당 모듈을 전혀 제공하지 않을 수 있습니다.
이러한 모듈과 관련된 가져오기 오류를 적절히 보고하려면 새 기본 excepthook 구현이 새 조회 API를 통해 해당 모듈을 보고해야 합니다.
패키징 관련 모듈을 필수로 간주
일부 재배포자는 Python별 패키징 관련 모듈(distutils, ensurepip, venv)을 기본적으로 설치하는 데 전적으로 동의하지 않으며, 대신 개발자가 플랫폼별 도구를 사용하기를 선호합니다.
이러한 접근 방식은 크로스 플랫폼 프로젝트를 작업하는 개발자와 플랫폼 독립적인 설정 지침을 작성하려는 교육자에게 상호 운용성 문제를 일으킵니다. 따라서 이 PEP는 이러한 모듈을 필수로 간주하고 선택적 모듈 목록에서 제외해야 한다는 입장입니다.
보류된 아이디어
이 절의 아이디어는 이 PEP가 잠재적으로 구현을 지원할 수 있는 개념이지만, 초기 제안의 범위에는 포함되지 않는 것으로 간주합니다.
플랫폼 종속 모듈
일부 표준 라이브러리 모듈은 특정 플랫폼에서만 제공되기 때문에 누락될 수 있습니다. 예를 들어, winreg 모듈은 Windows에서만 사용할 수 있습니다.:
$ python3 -c "import winreg"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'winreg'
현재 제안에서는 이러한 플랫폼 종속 모듈을 플랫폼 종속성 정보를 더 구조화된 방식으로 노출하려고 시도하는 대신, 다른 모든 선택적 모듈과 함께 단순히 포함합니다.
그러나 the documentation을 위해 플랫폼 종속성은 최소한 “Windows”, “Unix”, “Linux”, “FreeBSD” 수준으로 추적되고 있으므로, 이를 프로그래밍 방식으로도 노출할 수 있을 가능성이 있어 보입니다.
__main__이 표준 라이브러리 모듈을 가릴 때 경고 내보내기
새로운 쿼리 API가 제공되면 새로운 기본 excepthook 구현은 __main__.__file__ 또는 __main__.__spec__.name이 표준 라이브러리 모듈과 일치하는 경우를 감지하여 적절한 경고를 내보낼 수 있습니다.
그러나 이와 같은 작업을 실제로 수행하려면 사용자가 실제로 이 문제를 접하는 더 많은 사례와, 현재 즉시 통합할 필요 없이 상황 디버깅을 지원하기 위해 더 많은 정보를 제공할 수 있는 여러 선택지를 검토해야 합니다.
다운스트림 배포자에 대한 권고
자체 sys.excepthook 함수 구현을 제공하도록 site.py [*]를 패치하면, Python 배포자는 포착되지 않은 모든 예외에 대해 맞춤형 오류 메시지를 표시할 수 있으며, ModuleNotFoundError를 만났을 때 누락된 표준 라이브러리 모듈을 배포판별로 적절한 방법으로 설치하도록 사용자에게 안내할 수도 있습니다.
일부 다운스트림 배포자는 플랫폼 충돌 보고 메커니즘과 통합하기 위해 이미 sys.excepthook을 패치하는 이 방법을 사용하고 있습니다.
하위 호환성
하위 호환성 문제는 발생하지 않을 것으로 예상합니다. 누락된 의존성을 사용자 지정 방식으로 처리하기 위해 이미 Python 모듈을 패치하고 있는 배포판은 방해받지 않고 계속 그렇게 할 수 있습니다.
참조 및 예제 구현
TBD. 세부 사항은 CPython 빌드 시스템의 기능이 허용하는 실용적인 범위에 따라 달라질 것입니다(다른 구현체들은 스스로 데이터를 다시 생성할 필요 없이, 생성된 CPython 데이터를 사용할 수 있어야 합니다).
참고 사항 및 참조
이 PEP로 이어진 아이디어들은 python-dev mailing list에서, 이어서 python-ideas에서 논의되었습니다.
Copyright
This document has been placed in the public domain.