PEP 819 – JSON 패키지 메타데이터
- Author:
- Emma Harper Smith <emma at python.org>
- PEP-Delegate:
- Paul Moore
- Discussions-To:
- Discourse thread
- Status:
- Draft
- Type:
- Standards Track
- Topic:
- Packaging
- Created:
- 18-Dec-2025
- Post-History:
- 06-Jan-2026
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 Python 패키지에 JSON으로 인코딩된 코어 메타데이터 파일과 wheel 파일 형식 메타데이터 파일을 도입할 것을 제안합니다. Python 패키지 메타데이터(“코어 메타데이터”)는 PEP 241에서 처음 정의되었으며, 패키지에 관한 정보를 인코딩하는 데 RFC 822 이메일 헤더를 사용하도록 했습니다. 2001년에는 이것이 합리적인 선택이었습니다. 널리 쓰이는 표준화된 텍스트 형식 가운데 표준 라이브러리에 파서가 있는 것은 이메일 메시지가 유일했기 때문입니다. 그러나 서로 다른 인코딩 처리 문제, 줄바꿈 처리 방식의 차이, 그 밖의 구현 간 차이로 인해 수많은 패키징 버그가 발생했습니다. 메타데이터 파일을 인코딩하는 데 JSON 형식을 사용하면 이러한 잠재적 문제를 폭넓게 없앨 수 있습니다.
동기
이메일 메시지 형식에는 여러 가지 복잡성과 한계가 있어서, 패키징 메타데이터를 위한 이식 가능한 텍스트 교환 형식으로서의 유용성이 떨어집니다. 유효한 코어 메타데이터를 올바르게 생성하려면 email 파서의 설정을 변경해야 하기 때문에, 많은 프로젝트는 email 모듈을 사용하지 않고 자체적인 방식으로 코어 메타데이터를 생성합니다. 이러한 자체 생성기가 이메일 헤더를 생성할 때 빠질 수 있는 함정은 많습니다. 첫째, 코어 메타데이터 필드의 값에는 줄바꿈이 포함될 수 있습니다. 이러한 줄바꿈은 RFC 822에 따라 여러 줄을 “펼칠(unfold)” 수 있도록 올바르게 처리해야 합니다. 특히 인코딩하기 어려운 필드는 Description 필드로, 줄바꿈과 들여쓰기를 포함할 수 있습니다. 이 필드를 이메일 헤더로 인코딩하려면 CRLF 줄바꿈 뒤에 일곱(7) 개의 공백과 파이프(’|’) 문자가 와야 합니다. 이제 Description은 메시지 본문에 인코딩할 수 있지만, Author 및 Maintainer 필드에서도 비슷한 이스케이프 문제가 발생합니다. 줄바꿈을 잘못 이스케이프하면 코어 메타데이터가 누락되거나, 일부만 남거나, 유효하지 않게 될 수 있습니다. 둘째, 코어 메타데이터 명세에서는 다음과 같이 설명합니다:
메타데이터의 표준 파일 형식(휠과 설치된 프로젝트의 메타데이터를 포함합니다)은 이메일 헤더 형식을 기반으로 합니다. 그러나 이메일 형식은 여러 차례 개정되었으며, 패키징 메타데이터에 정확히 어떤 이메일 RFC가 적용되는지는 명시되어 있지 않습니다. 정확한 정의가 없으므로, 실질적인 표준은 표준 라이브러리의email.parser모듈이email.policy.compat32정책을 사용하여 파싱할 수 있는 것으로 정해집니다.
특정 이메일 RFC가 선택되어 있지 않기 때문에, 현재의 코어 메타데이터 명세로는 주어진 코어 메타데이터 문서가 유효한지 여부가 모호합니다. RFC 822는 PEP에 명시적으로 기재된 유일한 이메일 표준입니다. 그러나 코어 메타데이터 명세는 코어 메타데이터를 파일에 기록할 때 UTF-8로 인코딩할 것도 요구합니다. 이로 인해 코어 메타데이터는 사실상 이메일 헤더의 국제화를 규정하는 RFC 6532를 따르게 됩니다. 이는 실질적인 상호 운용성 문제를 낳습니다. 몇 년 전까지만 해도 코어 메타데이터에서 ASCII가 아닌 이메일을 올바르게 인코딩하는 방법이 명시되어 있지 않아 파싱이 모호했습니다. 셋째, 현재 형식은 올바르게 검증하고 파싱하기가 어렵습니다. 많은 도구가 email 파서의 출력에 문제가 있는지 확인하지 않습니다. 문서의 형식이 잘못되었더라도 email 모듈은 이를 오류 없이 유효한 이메일 메시지로 파싱할 수 있습니다. 또한 이메일 형식의 한계로 인해 Project-Url 같은 필드는 중첩된 키-값 항목을 자체적인 방식으로 인코딩해야 하므로, 파싱과 검증이 더욱 복잡해집니다. 마지막으로, 스키마가 없기 때문에 이메일 메시지로 인코딩된 메타데이터의 내용을 검증하기 어렵습니다. 현재 형식에 대한 명세를 도입하는 방안이 이전에 논의된 적 있지만 진전이 없었으며, 제기된 문제들의 해결책으로 JSON으로 전환하는 방안이 제안되었습니다.
WHEEL 파일 형식은 현재 사용자 정의 키-값 형식으로 인코딩되어 있습니다. 이 형식은 파싱하고 작성하기 쉽지만, 내용이 유효한지 확인하려면 수동으로 파싱하고 검증해야 합니다. JSON으로 인코딩된 형식으로 전환하면 내용을 더 쉽게 파싱하고 검증할 수 있으며, 배포 메타데이터에 일관된 형식을 사용함으로써 패키징 도구와 서비스를 단순화할 수 있습니다.
근거
잘 명세된 형식을 갖춘 새로운 코어 메타데이터 파일을 도입하면 메타데이터의 생성, 파싱, 검증이 크게 쉬워집니다. JSON은 패키지 코어 메타데이터를 저장하기에 자연스러운 선택입니다. JSON은 기계가 쉽게 읽고 쓸 수 있고, 사람이 이해할 수 있으며, 여러 언어에서 잘 지원됩니다. 또한 PEP 566은 이미 이메일 형식의 코어 메타데이터를 JSON으로 정규화하는 방법을 명세하고 있습니다. JSON은 웹에서 데이터 교환에 자주 사용되는 형식이기도 합니다. 검토한 다른 형식에 대한 논의는 기각된 아이디어 절을 참고하십시오.
하위 호환성을 유지하기 위해, JSON 메타데이터 파일은 반드시(MUST) 기존의 이메일 형식 메타데이터 파일과 함께 생성해야 합니다. 이를 통해 새 형식을 지원하지 않는 도구도 새 패키지의 패키지 메타데이터를 여전히 읽을 수 있습니다.
JSON 형식의 메타데이터 파일은 이메일로 인코딩된 파일과 의미상 동등해야 합니다. 이를 통해 두 형식 사이에서 메타데이터가 모호하지 않게 되며, 두 파일이 모두 있을 때 도구는 어느 쪽이든 읽을 수 있습니다. 성능을 유지하기 위해 설치 프로그램은 이 동등성을 검증하지 않아도 되지만, 다른 도구는 검증할 수 있습니다. 일부 도구는 이 검사를 설정 플래그에 따라 수행하도록 할 수도 있습니다.
패키지 색인은 패키지가 색인에 추가될 때 메타데이터 파일들이 의미상 동등한지 확인해야 합니다(SHOULD). 이는 비용이 적게 드는 일회성 검사로, 색인 사용자에게 유효한 패키지가 제공되도록 보장합니다.
명세
JSON 형식 코어 메타데이터 파일
선택 사항이지만 권장되는 새 파일 METADATA.json을 Python 배포 패키지의 메타데이터 파일로 도입합니다. 생성하는 경우, METADATA.json 파일은 반드시(MUST) 현재의 이메일 형식 METADATA 또는 PKG-INFO 파일과 같은 디렉터리에 두어야 합니다.
휠의 경우, 이는 METADATA.json이 반드시(MUST) .dist-info 디렉터리에 있어야 함을 뜻합니다.
METADATA.json 파일이 있다면, 이 파일은 소스 배포 패키지 안의 프로젝트 소스 루트 디렉터리에 위치해야 합니다(MUST). JSON 형식의 메타데이터 파일을 선호하는 도구는 파일을 읽기 전에 소스 배포판에 METADATA.json 파일이 존재한다고 가정해서는 안 됩니다(MUST NOT).
METADATA.json이 있는 경우, METADATA 파일과 METADATA.json 파일의 의미상 내용은 반드시(MUST) 동등해야 합니다. 설치 프로그램은 이 정보를 검증할 수 있습니다(MAY). 공개 패키지 색인은 두 파일이 의미상 동등한지 검증해야 합니다(SHOULD).
새 METADATA.json 파일이 배포 메타데이터에 있는 경우, 이 파일은 반드시(MUST) 설치된 프로젝트 메타데이터에 포함되어야 합니다.
METADATA를 JSON 인코딩으로 변환하기
코어 메타데이터를 현재의 이메일 형식에서 JSON으로 변환할 때는 PEP 566에 설명된 절차를 따르되, 다음과 같이 수정해야 합니다: Project-URL 항목은 원래 이메일 값의 레이블을 키로, URL을 값으로 하는 객체로 변환해야 합니다. 따라서 전체 절차는 다음과 같습니다:
- 원래의 키-값 형식은
email.parser.HeaderParser로 읽어야 합니다. - 변환된 모든 키는 소문자로 바꾸어야 합니다. 하이픈은 밑줄로 바꾸어야 하지만, 그 밖의 다른 문자는 모두 그대로 유지해야 합니다.
- “(Multiple-use”)로 표시된 모든 필드의 변환된 값은 해당 키의 원래 값을 모두 담은 단일 리스트여야 합니다.
Keywords필드는 원래 값을 쉼표로 분할하여 리스트로 변환해야 합니다.Project-URL필드는 원래 이메일 값에서 레이블을 키로, URL을 값으로 담은 JSON 객체로 변환해야 합니다.- 메시지 본문이 있다면
description키의 값으로 설정해야 합니다. - 결과는 문자열을 키로 하는 딕셔너리로 저장해야 합니다.
위 변환에서 한 가지 예외적인 경우는 Project-URL 레이블이 “최대 길이 32자의 자유 텍스트”라는 점입니다. 이 때문에 레이블을 디코딩하려 할 때 문제가 생깁니다. 따라서 이 PEP는 Project-URL 레이블이 쉼표(,) 문자를 제외한 임의의 텍스트여야 한다는 요구 사항을 정합니다. 이렇게 하면 텍스트를 가장 왼쪽의 쉼표(,) 문자에서 분할하여 Project-URL 항목을 모호함 없이 파싱할 수 있습니다.
코어 메타데이터를 위한 JSON 스키마
JSON으로 인코딩된 코어 메타데이터를 검증할 수 있도록 코어 메타데이터용 JSON 스키마를 만들었습니다. 이 스키마는 코어 메타데이터 명세가 개정될 때마다 갱신됩니다. 스키마는 부록: 코어 메타데이터를 위한 JSON 스키마에서 볼 수 있습니다.
Simple Repository API(단순 저장소 API)에서 METADATA.json 제공하기
PEP 658은 Simple Repository API(단순 저장소 API)에서 패키지 메타데이터를 제공하는 방법을 도입했습니다. Simple Repository API(단순 저장소 API)를 다음과 같이 수정하여 JSON으로 인코딩된 버전의 패키지 메타데이터도 제공할 수 있습니다:
Simple API의 앵커 태그에 새 속성 data-dist-info-metadata-json을 추가할 수 있습니다. 이 속성은 METADATA.json 파일의 해시 정보를 data-dist-info-metadata와 같은 형식으로 담은 값을 가져야 합니다(SHOULD). data-dist-info-metadata-json이 있으면, 저장소는 배포 파일의 경로 뒤에 .metadata.json을 덧붙인 경로에서 JSON으로 인코딩된 메타데이터 파일을 제공해야 합니다(MUST). 예를 들어 배포 파일이 /simple/foo-1.0-py3-none-any.whl에서 제공된다면, JSON으로 인코딩된 코어 메타데이터 파일은 /simple/foo-1.0-py3-none-any.whl.metadata.json에서 제공되어야 합니다(MUST).
JSON 형식 휠 메타데이터 파일
WHEEL 파일을 JSON으로 인코딩한 버전으로, 선택 사항이지만 권장되는 새 파일 WHEEL.json을 도입합니다. WHEEL.json 파일을 생성한다면, 현재의 키-값 형식 WHEEL 파일과 같은 디렉터리, 즉 .dist-info 디렉터리에 두어야 합니다(MUST). WHEEL 파일과 WHEEL.json 파일의 의미상 내용은 동등해야 합니다(MUST). WHEEL.json의 도입을 반영하기 위해 wheel 파일 형식 버전은 1.1로 올라갑니다.
두 파일이 모두 있을 때는 WHEEL 파일보다 WHEEL.json 파일을 우선해야 합니다(SHOULD).
WHEEL을 JSON 인코딩으로 변환하기
wheel 파일 형식 메타데이터를 현재의 키-값 형식에서 JSON으로 변환하는 작업은 다음과 같이 진행해야 합니다.
- 원래의 키-값 형식을 읽어야 합니다.
- 변환된 모든 키는 소문자로 바꿔야 합니다. 하이픈은 밑줄로 바꾸되, 그 외의 모든 문자는 그대로 유지해야 합니다.
Tag필드의 항목은 원래 값들을 담은 리스트로 변환해야 합니다.- 결과는 문자열을 키로 하는 딕셔너리로 저장해야 합니다.
이는 METADATA를 JSON 인코딩으로 변환하는 과정과 비슷한 절차를 따릅니다.
휠 메타데이터용 JSON 스키마
JSON으로 인코딩된 wheel 파일 형식 메타데이터를 검증할 수 있도록 wheel 메타데이터용 JSON 스키마를 만들었습니다. 이 스키마는 휠 메타데이터 명세가 개정될 때마다 갱신됩니다. 스키마는 부록: 휠 메타데이터용 JSON 스키마에서 확인할 수 있습니다.
METADATA, PKG-INFO, WHEEL 파일의 폐지 예정
이제 METADATA, PKG-INFO, WHEEL 파일은 폐지 예정입니다. 이는 향후 PEP에서 METADATA, PKG-INFO, WHEEL 파일을 선택 사항으로 바꾸고 METADATA.json과 WHEEL.json이 반드시 존재하도록 요구할 수 있다는 뜻입니다. 그러한 변경에 따른 하위 호환성 관련 주의 사항은 다음 절을 참고하십시오.
METADATA와 PKG-INFO 파일이 폐지 예정이더라도, 새로운 코어 메타데이터 개정 사항은 두 형식이 의미상 동등하게 유지될 수 있도록 JSON과 이메일 형식 모두에 구현해야 합니다. 마찬가지로 새로운 WHEEL 메타데이터 키도 두 형식이 의미상 동등하게 유지될 수 있도록 JSON과 키-값 형식 모두에 구현해야 합니다.
하위 호환성
METADATA.json과 WHEEL.json의 명세는 새 형식이 완전한 하위 호환성을 갖도록 설계되었습니다. 기존 도구는 기존의 이메일 형식 파일에서 메타데이터를 읽을 수 있고, 새로운 도구는 새 형식을 활용할 수 있습니다.
향후 휠 명세의 주요 개정에서 METADATA, PKG-INFO, WHEEL 파일을 선택 사항으로 바꾸고 METADATA.json과 WHEEL.json 파일을 필수로 만들 수 있습니다.
METADATA, PKG-INFO, WHEEL 파일만 있는 오래된 패키지의 메타데이터를 파싱할 수 있도록, 도구는 이메일 메타데이터와 키-값 형식의 WHEEL 파일에 대한 파싱 기능을 무기한 유지해야 한다는 점에 유의하십시오.
보안 영향
JSON으로 인코딩된 코어 메타데이터와 관련된 공격 벡터 중 하나는 서비스 거부(DoS) 공격을 위해 JSON 페이로드가 과도한 메모리나 CPU 자원을 소모하도록 조작되는 경우입니다. 이 공격은 자원을 많이 소모하는 대화형 작업을 취소할 수 있는 사용자에게는 영향을 줄 가능성이 낮지만, 패키지 색인에는 문제가 될 수 있습니다.
이를 방지하기 위해 적용할 수 있는 완화 조치는 여러 가지가 있습니다.
- JSON 페이로드의 길이를 적절한 크기로 제한할 수 있습니다.
- 읽는 쪽에서는
JSONDecoder를 사용해int와float값의 파싱을 생략함으로써, 숫자 파싱의 이차 시간 복잡도를 노린 공격을 피할 수 있습니다. - 저는 Python 3.15+에서
JSONDecoder가 JSON 페이로드의 중첩을 적절한 깊이로 제한하도록 설정할 수 있게 하는 변경 사항을 기여할 계획입니다. 현재 코어 메타데이터는 매핑과 리스트 필드를 인코딩하기 위해 최대 2단계의 깊이를 가집니다.
이러한 완화 조치를 적용하면 JSON으로 인코딩된 코어 메타데이터를 이용한 서비스 거부 공격에 대한 우려는 최소화됩니다.
참조 구현
JSON 코어 메타데이터용 JSON 스키마의 참조 구현은 부록: 코어 메타데이터를 위한 JSON 스키마에서 확인할 수 있습니다.
또한 packaging 라이브러리의 참조 구현도 공개되어 있습니다.
METADATA.json과 WHEEL.json을 모두 생성하는 참조 구현도 uv 빌드 백엔드에 마련되어 있습니다.
기각된 아이디어
다른 파일 형식 사용(TOML, YAML 등)
새로운 코어 메타데이터 파일 형식으로 TOML이나 다른 형식을 사용할 수도 있지만, 몇 가지 이유로 JSON을 선택했습니다.
- 코어 메타데이터는 주로 상호 운용하려는 도구와 서비스가 사용하는 기계 간 교환 형식입니다. 따라서 이 선택에서 TOML이 사람이 읽기 좋다는 점은 중요한 고려 사항이 아닙니다.
- JSON 파서는 여러 언어의 표준 라이브러리에 구현되어 있으며,
json모듈은 아주 오래전부터 Python 표준 라이브러리에 포함되어 있었습니다. - JSON은 파싱과 출력이 빠릅니다.
- JSON 스키마는 JSON 자체로 작성되며 널리 사용됩니다.
미해결 문제
JSON 스키마는 어디에서 제공해야 합니까?
표준 JSON 스키마는 어디에서 제공해야 합니까? 선택지로는 packaging.python.org, pypi.org, python.org, pypa.org 등이 있습니다.
저는 packaging.python.org를 가장 먼저 고려하지만, 다른 선택지도 열어 두고 있습니다.
감사의 글
uv 빌드 백엔드에 이 PEP의 참조 구현을 만들고 명세에 대해 귀중한 피드백을 주신 Konstantin Schütze에게 감사드립니다.
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.