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

Python 개선 제안 한국어 번역

PEP 794 – 임포트 이름 메타데이터

Author:
Brett Cannon <brett at python.org>
Discussions-To:
Discourse thread
Status:
Accepted
Type:
Standards Track
Topic:
Packaging
Created:
05-Jun-2025
Post-History:
02-May-2025, 05-Jun-2025
Resolution:
05-Sep-2025

Table of Contents

번역·라이선스 안내

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

Important

This PEP is a historical document. The up-to-date, canonical spec, Core metadata specifications, is maintained on the PyPA specs page.

×

See the PyPA specification update process for how to propose changes.

초록

이 PEP는 Python 패키징을 위한 핵심 메타데이터 사양을 확장하여, 프로젝트가 설치된 후 제공하는 임포트 이름을 기록할 수 있도록 Import-NameImport-Namespace라는 두 개의 새로운 반복 가능 필드를 포함할 것을 제안합니다. 새로운 핵심 메타데이터 필드에 값을 제공하기 위해 import-namesimport-namespaces라는 새 키를 pyproject.toml[project] 테이블에 추가합니다. 이에 따라 핵심 메타데이터 버전 2.5도 도입됩니다.

동기

Python 패키징에서는 프로젝트 이름이 해당 프로젝트에 대해 임포트할 수 있는 이름과 일치해야 한다는 요구 사항이 없습니다. 따라서 임포트 이름에서 프로젝트 이름으로, 또는 그 반대로 변환할 수 있는 깔끔하고 쉽고 정확한 방법이 없습니다. 이로 인해 임포트 이름을 알고 있을 때 설치할 올바른 프로젝트를 찾도록 돕거나, 설치 후 프로젝트가 제공할 임포트 이름을 파악하도록 돕는 도구가 어려움을 겪을 수 있습니다.

예를 들어 코드 편집기는 선택한 가상 환경에서 사용자의 충족되지 않은 임포트를 감지할 수 있습니다. 그러나 여러 프로젝트가 어떤 임포트 이름을 제공하는지 신뢰성 있게 알 방법이 없으면, 코드 편집기는 해당 임포트 요구 사항을 충족하기 위해 설치할 수 있는 프로젝트 후보 목록을 사용자에게 정확하게 제공할 수 없습니다(예: import PIL이 사용자가 Pillow 프로젝트를 설치하기를 원한다는 의미일 가능성이 매우 높다는 점은 명확하지 않습니다). 이는 사용자가 프로젝트 이름을 어렴풋이 기억하지만 임포트 이름을 기억하지 못하는 경우에도 적용되며, 패키지가 제공하는 임포트 이름 목록을 보면 기억을 되살릴 수 있습니다. 마지막으로, 도구는 프로젝트를 설치한 후 어떤 임포트 이름을 사용할 수 있게 되는지 사용자에게 알릴 수 있습니다.

또한 제공하는 임포트 이름을 기준으로 두 프로젝트를 설치할 때 서로 충돌하는지 알 수 있는 쉬운 방법도 없습니다. 예를 들어 서로 다른 두 프로젝트에 _utils 모듈이 있으면, 한 프로젝트의 _utils 모듈이 다른 프로젝트의 파일을 덮어써 다른 프로젝트의 모듈보다 우선하게 되므로 두 프로젝트를 모두 설치할 때 충돌이 발생합니다. 이 문제는 실제 환경에서 확인되었습니다.

이는 스팸 탐지에도 도움이 될 수 있습니다. 어떤 프로젝트가 매우 인기 있는 프로젝트와 동일한 임포트 이름을 지정한다면, 이는 인기가 덜한 프로젝트의 유효성을 더 면밀히 살펴보라는 신호로 작용할 수 있습니다. 제공한다고 주장하는 임포트 이름에 대해 거짓말하는 것으로 밝혀진 프로젝트도 또 다른 신호가 됩니다.

근거

이 PEP는 프로젝트 소유자가 어떤 플랫폼에 설치될 때 해당 프로젝트가 제공하는 최상위 임포트 이름을 지정할 수 있도록 패키징 Core metadata specifications를 확장할 것을 제안합니다.

이 메타데이터를 핵심 메타데이터에 포함하면 데이터가 (잠재적으로) sdist나 wheel과 독립적으로 색인 서버에서 제공될 수 있습니다. 따라서 전체 wheel 등을 다운로드하지 않아도 되도록 메타데이터를 도구에 노출하는 방법을 별도로 마련할 필요가 없어집니다.

이 메타데이터를 모든 릴리스 아티팩트에서 동일하게 유지하면, 프로젝트가 릴리스된 모든 파일을 확인하는 대신 단일 파일의 핵심 메타데이터만 확인하여 가능한 모든 임포트 이름을 얻을 수 있습니다. 이는 핵심 메타데이터를 읽을 때 파일이 누락되었는지 걱정할 필요가 없거나, 메타데이터가 제공되는 경우 sdist만으로 작업할 수 있다는 의미이기도 합니다. 또한 pyproject.tomlproject.import-namesproject.import-namespaces 키를 두는 것도 간소화됩니다. 동일한 버전의 릴리스 파일마다 고유하게 두는 대신 전체 프로젝트 버전에서 일관되게 유지할 수 있기 때문입니다.

모듈과 패키지를 포함하는 배포 파일은 모듈/패키지 수준에서 공개 API와 비공개 API를 어떤 조합으로든 포함할 수 있습니다. 배포 파일에 어떤 종류의 모듈이나 패키지도 포함되지 않을 수도 있습니다. 이러한 상황을 구별할 수 있으면 사용자에게 유익할 수 있는 다양한 도구상의 활용이 가능합니다. 예를 들어 공개인지 비공개인지와 관계없이 모든 임포트 이름을 알면 설치 시 충돌을 감지하는 데 도움이 됩니다. 그러나 명시적으로 공개된 임포트 이름과 비공개인 임포트 이름을 알면 편집기와 같은 도구가 자동 완성의 일부로 비공개 임포트 이름을 제안하지 않도록 할 수 있습니다.

이 PEP는 제안된 메타데이터에 무엇을 나열해야 하거나 나열하지 않아야 하는지에 대해 의도적으로 지나치게 엄격하지 않습니다. Python의 import 시스템이 매우 유연하기 때문에, 나열할 수 있는 항목에 대해 어떤 식으로든 엄격한 사양을 프로젝트가 정확히 따르는지 빌드 백엔드가 검증하도록 하는 것은 거의 올바르게 구현하기 어렵습니다. 따라서 이 PEP는 유효한 import 이름을 사용하고 프로젝트가 거짓말하지 않을 것만 요구합니다(후자의 요구 사항은 프로그래밍 방식으로 검증할 수 없다는 점을 인정합니다). 그러나 프로젝트는 자신이 나열하는 이름의 모든 수준을 고려해야 합니다(예를 들어 a.b.c를 나열하면서 aa.b를 고려하지 않을 수는 없습니다).

이 문제를 해결하려는 다양한 다른 시도도 있었지만, 모두 절충이 필요합니다. 예를 들어 모든 프로젝트 릴리스의 모든 wheel을 다운로드하고 Binary distribution format을 통해 제공되는 파일을 살펴볼 수 있지만, 이는 정적인 정보에 비해 CPU와 대역폭을 많이 사용합니다(물론 zip 파일의 목차만 읽도록 HTTP 범위 요청을 사용하는 등 데이터 요청을 줄이는 기법을 사용할 수 있습니다). 또한 이러한 종류의 계산은 메타데이터를 PyPI와 같은 중앙 색인 서버에서 호스팅하는 대신 현재도 모든 사용자가 독립적으로 반복하고 있습니다. 또한 wheel의 구조가 아직 알려져 있지 않으므로 sdist에는 작동하지 않으며, 따라서 설치되는 코드의 구조를 추론할 수 없습니다. 게다가 이러한 해결책은 프로젝트 소유자가 명시적으로 제공한 정보가 아니라 추론에 기반하므로 반드시 정확하지는 않습니다. 이러한 모든 정확성 문제는 정보를 수집하는 계산 비용을 피하기 위해 색인이 해당 정보를 호스팅하도록 하는 경우에도 영향을 미칩니다.

사양

이 PEP는 핵심 메타데이터에 새 필드를 도입하므로 최신 핵심 메타데이터 버전을 2.5로 올립니다.

Import-NameImport-Namespace필드는 “다중 사용” 필드입니다. 두 필드의 각 항목은 유효한 import 이름이어야 하며, Import-Name의 경우에는 비어 있을 수 있습니다. 지정된 모든 이름은 동일한 프로젝트 버전에 대해 프로젝트가 일부 플랫폼에 설치될 때 반드시 임포트할 수 있어야 합니다(예: 프로젝트 릴리스의 모든 sdist와 wheel에서 메타데이터가 일관되어야 합니다). 이는 해당 정보가 그 정보가 포함된 배포 아티팩트에 특정된 것이 아니라, 해당 배포 아티팩트가 속한 릴리스 버전에 특정된다는 의미입니다.

import 이름 뒤에는 세미콜론과 “private”라는 용어가 올 수 있습니다(예: ; private). 이는 해당 import 이름이 프로젝트의 공개 API에 속하지 않음을 도구에 알립니다. ;앞뒤에는 공백을 얼마든지 사용할 수 있습니다.

Import-Name은 프로젝트를 설치했을 때 프로젝트가 독점적으로 제공하는 import 이름을 나열합니다(즉, Import-Name에 동일한 import 이름을 나열한 두 프로젝트가 설치되면 두 프로젝트 중 하나가 다른 프로젝트의 이름을 가리게 됩니다). Import-Namespace는 설치했을 때 프로젝트가 제공하지만 독점적이지는 않은 import 이름을 나열합니다(즉, Import-Namespace에 동일한 import 이름을 나열한 프로젝트들을 함께 설치해도 해당 공유 이름들이 서로를 가리지 않습니다).

프로젝트 메타데이터를 선언하는 pyproject.toml specificationimport-names 키가 추가됩니다. 이는 Import-Name에 기록될 내용을 저장하는 문자열 배열입니다. 사용자가 project.dynamic에 키를 선언한 경우, 빌드 백엔드는 원한다면 사용자를 대신하여 값을 동적으로 계산하는 기능을 지원할 수 있습니다. Import-Namespace에 대한 import-namespaces에도 동일하게 적용됩니다.

프로젝트는 모든 import 이름 시나리오를 포괄하는, 프로젝트가 독점적으로 제공하는 가장 짧은 import 이름을 모두 나열해야 합니다. 가장 짧은 이름 중 하나라도 점으로 구분된 이름이라면, 해당 이름부터 최상위 이름까지의 모든 중간 이름도 Import-Namespace및/또는 Import-Name에 적절하게 나열해야 합니다. 예를 들어 여러 하위 모듈이 있는 spam이라는 단일 패키지인 프로젝트는 project.import-names = ["spam"]만 나열합니다. spam.bacon.eggs를 나열하는 프로젝트는 import-namesimport-namespaces에서 spamspam.bacon도 적절하게 고려해야 합니다. 모든 이름을 나열하면 import 이름의 의도가 예상대로인지 확인할 수 있습니다. 또한 프로젝트는 공개 이름과 비공개 이름을 구분하지 않고 모든 import 이름을 나열해야 하며, 적절한 경우 ; private수정자를 사용해야 합니다.

프로젝트가 Import-NameImport-Namespace에 동일한 이름을 나열하면 모호성으로 인해 도구는 오류를 발생시켜야 합니다. 이는 각각 import-namesimport-namespaces에도 적용됩니다.

도구는 한 도구로 설치될 예정인 두 프로젝트가 서로의 Import-Name 항목에 겹치는 이름을 나열하는 경우(즉, 동일한 명령/작업으로 설치되는 경우) 오류를 발생시켜야 합니다. 이는 프로젝트가 다른 프로젝트의 코드를 예기치 않게 가리는 것을 방지하기 위한 것입니다. 한 프로젝트의 Import-Name 항목이 다른 프로젝트의 Import-Namespace 항목과 겹치는 경우에도 동일하게 적용됩니다. Import-Namespace 항목 간의 중복에는 적용되지 않는데, 네임스페이스 패키지가 존재하는 목적이 바로 그것이기 때문입니다. 도구는 이미 설치된 프로젝트와 가져오기 이름이 겹치는 기존 환경에 프로젝트를 설치할 때 경고하거나 오류를 발생시킬 수 있습니다. 일부 사용자는 동일한 환경에서 서로 다른 설치 도구를 사용하는 등 여러 단계로 설치할 때 가져오기 이름을 의도적으로 덮어쓰기 때문에 이는 “MAY”이지 “SHOULD”가 아닙니다.

프로젝트는 pyproject.toml 파일에서 import-names를 빈 배열로 설정하고 import-namespaces는 전혀 설정하지 않을 수 있습니다(예: import-names = []). 이에 맞춰 프로젝트는 메타데이터에 빈 Import-Name 필드를 포함할 수 있습니다. 이는 공개 또는 비공개 가져오기 이름이 전혀 없는 프로젝트를 나타냅니다(즉, 배포 파일에 어떤 종류의 Python 모듈도 없습니다).

프로젝트에 Import-Name 메타데이터가 없을 수 있으므로(프로젝트가 이전 메타데이터 버전을 사용하거나 아무것도 지정하지 않았기 때문), 도구는 프로젝트가 제공하는 이름에 대한 정보를 알 수 없습니다. 그러나 실제로는 대다수 프로젝트에서 프로젝트 이름이 가져오기 이름과 일치합니다. 따라서 어떤 답이 필요한 경우, 어떤 방식으로든 가져오기 이름으로 정규화된 프로젝트 이름(예: packaging.utils.canonicalize_name(name, validate=True).replace("-", "_"))을 사용할 수 있다고 합리적으로 가정할 수 있습니다.

프로젝트는 프로젝트 이름과 일치하는(정규화 여부와 무관하게) 가져오기 이름을 import-names 또는 import-namespaces에, 그리고 각각 Import-Name 또는 Import-Namespace에 설정하여 프로젝트 이름이 가져오기 이름이기도 함을 명시적으로 선언할 수 있습니다.

예시

scikit-learn 1.7.0의 경우:

[project]
import-names = ["sklearn"]

pytest 8.3.5의 경우 예상되는 항목은 3개입니다.

[project]
# The pytest docs list code out of all of these modules, so it isn't
# obvious whether they would mark any as private.
import-names = ["_pytest", "py", "pytest"]

azure-mgmt-search 9.1.0의 경우 azure.mgmt.search에 대해 네임스페이스 항목 2개와 이름 항목 1개가 있어야 합니다.

[project]
import-names = ["azure.mgmt.search"]
import-namespaces = ["azure", "azure.mgmt"]

하위 호환성

이는 핵심 메타데이터의 새 필드이자 새로운 핵심 메타데이터 버전이므로 하위 호환성 문제는 없어야 합니다.

보안 영향

도구는 메타데이터가 부정확할 가능성이 있다고 간주해야 합니다. 따라서 제공된 메타데이터에 기반한 모든 결정은 어떤 방식으로든 악의적일 수 있다고 가정해야 합니다.

이 내용을 가르치는 방법

프로젝트 소유자는 이제 자신의 프로젝트가 가져오기를 위해 제공하는 이름을 기록할 수 있다는 점을 배워야 합니다. 프로젝트 이름이 프로젝트가 제공하는 모듈 또는 패키지 이름과 일치한다면 아무것도 할 필요가 없습니다. 그러나 차이가 있다면 프로젝트가 제공하는 모든 가져오기 이름을 가능한 한 짧은 이름으로 기록해야 합니다. 이름 중 암시적 네임스페이스가 있다면 pyproject.tomlproject.import-namespaces에 넣고, 그렇지 않으면 이름을 project.import-names에 넣어야 합니다.

프로젝트 사용자는 이 새로운 메타데이터를 반드시 알 필요는 없습니다. 도구를 통해 이에 노출될 수는 있지만, 해당 데이터가 어디에서 비롯되었는지에 관한 세부 사항은 중요하지 않습니다. 색인 서버가 이를 노출하는 경우(예: Import-Name에서 값을 나열하고 파일 구조가 메타데이터의 주장을 뒷받침하는지 표시하는 경우) 사용자가 이를 접할 가능성은 있지만, 그렇다고 해서 사용자가 이 PEP의 기술적 세부 사항을 알아야 하는 것은 아닙니다.

참조 구현

https://github.com/brettcannon/packaging/tree/pep-794 은 이 PEP를 지원하도록 ‘packaging’을 업데이트하는 브랜치입니다.

거부된 아이디어

Import-Namespace의 값 추론

이 PEP의 이전 버전에서는 Import-Name에 있는 점으로 구분된 이름을 바탕으로 Import-Namespace의 값이 무엇이었을지 추론했습니다. 암시적 네임스페이스로 해석될 항목을 실수로 나열하는 일을 피할 수 있을 뿐만 아니라 데이터 자체를 더 명확하게 설명할 수 있으므로, 명시적으로 지정하는 편이 더 낫다고 결정했습니다.

Import-Namespace에 나열된 이름이 Import-Name의 이름에 절대 포함되지 않도록 요구하십시오.

Python의 가져오기 시스템은 기본적으로 이러한 방식으로 작동하므로 가져오기 이름이 네임스페이스를 포함하도록 할 수 없습니다. 그러나 Python의 가져오기 시스템은 사용자 코드가 이를 가능하게 만들 수 있을 만큼 유연합니다. 따라서 가져오기 이름에 네임스페이스 이름이 포함된 경우 도구에서 오류를 발생시켜야 한다는 요구 사항, 즉 import-names = ["spam"]import-namespaces = ["spam.bacon"]에 대한 요구 사항은 제거되었습니다.

Provides 필드의 용도 변경

메타데이터 버전 1.1에서 도입되고 1.2에서 폐기된 Provides 필드는 이 PEP가 제안하는 구별되는 네임스페이스 대신 프로젝트가 제공하는 모든 이름에 대해 유사한 정보를 제공하기 위한 것이었습니다. 이러한 차이와 Provides가 폐기되어 기존 코드에서 무시될 수 있다는 사실을 바탕으로, 새로운 필드를 사용하기로 결정했습니다.

필드 이름을 Namespace로 지정

“namespace”라는 용어는 가져오기 관점에서는 기술적으로 정확하지만, 암시적 네임스페이스 패키지와 혼동될 수 있습니다.

RECORD 파일 제공

이 PEP의 프리-PEP 버전에 관한 논의 중에, 휠의 RECORD파일을 이 새로운 메타데이터 대신 패키지 색인 서버에서 제공하자는 제안이 있었습니다. 그렇게 하면 즉시 구현할 수 있다는 이점이 있습니다. 그러나 동등한 정보를 제공하려면 휠에 의해 설치될 파일 구조를 바탕으로 추론해야 합니다. 그러면 부정확한 정보가 생성될 수 있습니다. 또한 sdist를 지원하지도 않습니다.

결국 설문이 진행되었고, 이 PEP가 취하는 접근 방식이 채택되었습니다.

프로젝트가 지정하는 항목을 더 엄격하게 규정

이 PEP의 이전 버전은 Import-Name에 넣을 수 있는 내용에 훨씬 더 엄격했습니다. 여기에는 일부 “SHOULD” 지침을 “MUST” 요구 사항으로 바꾸고, 프로젝트가 무엇을 “소유”하는지 계산하는 방법을 구체적으로 명시하는 내용이 포함되었습니다. 결국 이는 지나치게 제한적이며 잘못 구현되거나 사양이 예상보다 지나치게 엄격해질 위험이 있다고 결정했습니다.

메타데이터는 검증할 수 없으므로 완전할 것으로 예상된 적이 없었기 때문에, 대신 현재 이 PEP에 포함된 보다 느슨한 사양을 선택했습니다.

미해결 문제

해당 없음

감사의 말

이 메타데이터가 제공할 유용성을 ~~불평하며~~ 정기적으로 제기해 주신 HeeJae Chang에게 감사드립니다. 이 PEP의 초안을 검토하고 의견을 제공해 주신 Josh Cannon(친척 관계 없음)에게 감사드립니다. 또한 이 주제에 관한 이전 논의에 참여해 주신 모든 분께 감사드립니다.