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

Python 개선 제안 한국어 번역

PEP 650 – Python 프로젝트의 설치 프로그램 요구 사항 지정

Author:
Vikram Jayanthi <vikramjayanthi at google.com>, Dustin Ingram <di at python.org>, Brett Cannon <brett at python.org>
Discussions-To:
Discourse thread
Status:
Withdrawn
Type:
Standards Track
Topic:
Packaging
Created:
16-Jul-2020
Post-History:
14-Jan-2021

Table of Contents

번역·라이선스 안내

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

초록

Python 패키지 설치 프로그램은 서로 완전히 상호 운용되지 않습니다. pip은 가장 널리 사용되는 설치 프로그램이자 사실상의 표준이지만, Poetry나 Pipenv 같은 다른 설치 프로그램도 널리 사용됩니다. 이들은 특정 워크플로에 최적화되어 있으며 pip의 동작 방식과 직접적으로 일치하지 않는 고유한 기능을 제공하기 때문입니다.

설치 프로그램 선택지가 풍부하다는 점은 특정한 요구가 있는 최종 사용자에게 좋지만, 설치 프로그램 간의 상호 운용성이 부족하여 잠재적인 모든 설치 프로그램을 지원하기가 어렵습니다. 구체적으로, 의존성을 선언하기 위한 표준 요구 사항 파일이 없기 때문에 각 도구의 형식으로 지정된 의존성을 설치하려면 해당 도구를 명시적으로 사용해야 합니다. 그렇지 않으면 도구가 요구 사항 파일을 내보내야 하는데, 이는 설치 프로그램 입장에서 정보 손실로 이어질 수 있을 뿐만 아니라 개발자의 워크플로에 내보내기 단계가 추가되는 결과를 낳습니다.

호환되는 설치 프로그램을 호출하는 데 사용할 수 있는 표준화된 API를 제공하면, 서로 다른 설치 프로그램과 그 잠금 파일 사이의 개별적인 우려 사항, 고유한 요구 사항, 비호환성을 해결하지 않고도 이 문제를 해결할 수 있습니다.

이 명세를 구현하는 설치 프로그램은 일관된 방식으로 호출할 수 있으므로, 사용자는 자신이 선택한 설치 프로그램을 직접 호출하는 것처럼 사용할 수 있습니다.

용어

설치 프로그램 인터페이스
설치 프로그램 백엔드와 범용 설치 프로그램이 상호 작용하는 인터페이스입니다.
범용 설치 프로그램
설치 프로그램 인터페이스의 선택적 호출 메서드를 호출하여 설치 프로그램 백엔드를 호출할 수 있는 설치 프로그램입니다. 이는 PEP 517의 build 프로젝트와 같은 설치 프로그램 프런트엔드로 생각할 수도 있습니다.
설치 프로그램 백엔드
설치 프로그램 인터페이스를 구현하여 범용 설치 프로그램이 호출할 수 있도록 하는 설치 프로그램입니다. 설치 프로그램 백엔드가 동시에 범용 설치 프로그램일 수도 있지만, 반드시 그래야 하는 것은 아닙니다. PEP 517과 비교하면 이는 Flit에 해당합니다. 설치 프로그램 백엔드는 기반 설치 프로그램을 감싸는 래퍼 패키지일 수도 있습니다. 예를 들어 Poetry가 이 API를 지원하지 않기로 하더라도, 어떤 패키지가 래퍼 역할을 하여 Poetry를 적절히 호출함으로써 Poetry로 설치를 수행할 수 있습니다.
의존성 그룹
서로 관련되어 있으며 어떤 목적을 위해 함께 설치되어야 하는 의존성의 집합입니다. 예를 들어, “test” 의존성 그룹에는 테스트 스위트를 실행하는 데 필요한 의존성이 포함될 수 있습니다. 의존성 그룹을 지정하는 방식은 설치 프로그램 백엔드가 결정합니다.

동기

이 명세를 통해 누구나 지정된 인터페이스를 구현하는 설치 프로그램 백엔드를 호출하고 상호 작용할 수 있으며, 기존의 도구별 설치 과정 위에 보편적으로 지원되는 계층을 마련할 수 있습니다.

이를 통해 지정된 인터페이스를 구현하는 모든 설치 프로그램을 단일 범용 설치 프로그램을 지원하는 환경에서 사용할 수 있게 됩니다. 단, 해당 범용 설치 프로그램도 이 명세를 구현해야 합니다.

아래에서는 Python 커뮤니티의 이해관계자와 Python 패키지 설치 프로그램을 사용하는 모든 사람에게 해당하는 여러 사용 사례를 살펴봅니다. 개발자나 기업은 이 PEP를 통해 Python 패키지 설치 프로그램에서 더 많은 기능과 유연성을 얻을 수 있습니다.

제공자

제공자는 Python 패키징, 나아가 Python 패키지 설치 프로그램과 상호 작용하는 서비스나 소프트웨어 도구를 공급하는 주체(조직, 개인, 커뮤니티 등)입니다. 여기서는 두 가지 유형의 제공자를 고려합니다.

플랫폼/인프라 제공자

플랫폼 제공자(클라우드 환경, 애플리케이션 호스팅 등)와 인프라 서비스 제공자는 사용자가 Python 의존성을 설치할 수 있도록 패키지 설치 프로그램을 지원해야 합니다. 대부분은 pip만 지원하지만, 다른 Python 설치 프로그램에 대한 사용자 수요도 있습니다. 대부분의 제공자는 둘 이상의 설치 프로그램을 계속 지원하려 하지 않습니다. 그만큼 소프트웨어나 서비스가 복잡해지고 자원도 많이 들기 때문입니다.

이 명세를 통해 제공자가 지원하는 범용 설치 프로그램이 사용자가 원하는 설치 프로그램 백엔드를 호출할 수 있게 됩니다. 이때 제공자의 플랫폼은 해당 백엔드를 구체적으로 알 필요가 없습니다. 예를 들어 Poetry가 이 PEP에서 제안하는 설치 프로그램 백엔드 API를 구현하면(또는 다른 패키지가 Poetry를 감싸서 이 API를 제공하면), 플랫폼 제공자는 별도의 작업 없이 Poetry를 지원하게 됩니다.

IDE 제공자

통합 개발 환경은 Python 패키지 설치 및 관리와 상호 작용할 수 있습니다. 대부분은 Python 패키지 설치 프로그램으로 pip만 지원하므로, 사용자가 다른 패키지 설치 프로그램으로 의존성을 설치하려면 우회 방법을 찾아야 합니다. PaaS 및 IaaS 제공자와 마찬가지로, IDE 제공자도 N개의 서로 다른 Python 설치 프로그램을 계속 지원하려 하지 않습니다. 대신 IDE가 범용 설치 프로그램 역할을 하여 설치 프로그램 인터페이스의 구현체(설치 프로그램 백엔드)를 호출할 수 있습니다.

개발자

개발자는 Python 패키지 설치 프로그램과 Python 패키지를 사용하고 코드를 작성하는 팀, 개인 또는 커뮤니티입니다. 다음 세 가지 유형의 개발자를 고려합니다:

PaaS 및 IaaS 제공자를 사용하는 개발자

대부분의 PaaS 및 IaaS 제공자는 Python 패키지 설치 프로그램을 pip 하나만 지원합니다. (예외로 Heroku의 Python buildpack은 pip와 Pipenv를 지원합니다.) 따라서 이러한 제공자를 이용하는 개발자는 쓸 수 있는 설치 프로그램이 정해져 있으며, 이 설치 프로그램이 자신의 애플리케이션이나 워크플로에 최적이 아닐 수도 있습니다.

설치 프로그램이 이 PEP를 채택하여 설치 프로그램 백엔드가 되면, 제공자가 범용 설치 프로그램을 사용하는 한 사용자는 어떤 Python 패키지 설치 프로그램을 써야 하는지 신경 쓰지 않고 서드파티 플랫폼/인프라를 사용할 수 있습니다.

IDE를 사용하는 개발자

대부분의 IDE는 pip 또는 소수의 Python 패키지 설치 프로그램만 지원합니다. 따라서 지원되지 않는 패키지 설치 프로그램을 쓰는 개발자는 우회 방법이나 임시변통으로 의존성을 설치해야 합니다.

IDE가 범용 설치 프로그램을 사용하거나 제공하면, 개발자가 원하는 어떤 설치 프로그램 백엔드로든 의존성을 설치할 수 있습니다. 그러면 개발자는 IDE 워크플로와 더 긴밀하게 통합하기 위해 의존성 설치에 추가로 손을 쓸 필요가 없어집니다.

다른 개발자와 함께 일하는 개발자

개발자는 다른 개발자와 협업할 때도 자신이 고른 설치 프로그램을 쓰고 싶어 합니다. 그러나 현재는 의존성 설치 호환성 때문에 서로 같은 설치 프로그램을 맞춰 써야 합니다. 선호하는 설치 프로그램이 모두 지정된 인터페이스를 구현한다면 설치 프로그램을 서로 섞어 쓸 수 있습니다. 그러면 개발자는 협업자가 무엇을 선호하든 자신의 설치 프로그램을 고를 수 있습니다.

업그레이드 도구 및 패키지 인프라 제공자

Dependabot, PyUP 등 CI/CD의 패키지 업그레이드 도구와 패키지 인프라는 현재 소수의 설치 프로그램만 지원합니다. 이들은 설치 프로그램별 의존성 파일(requirements.txt나 poetry.lock 등)을 직접 파싱하고, 업그레이드, 다운그레이드, 새 해시 같은 관련 패키지 정보로 편집하는 방식으로 동작합니다. 플랫폼 및 IDE 제공자와 마찬가지로, 이러한 제공자 대부분도 N개의 서로 다른 Python 패키지 설치 프로그램을 지원하려 하지 않습니다. 그러려면 N개의 서로 다른 파일 형식을 지원해야 하기 때문입니다.

현재 이러한 서비스/봇은 패키지 설치 프로그램마다 지원을 따로 구현해야 합니다. 그러다 보니 가장 인기 있는 설치 프로그램부터 지원하게 되고, 덜 알려진 도구는 끝내 지원되지 않는 경우가 많습니다. 이러한 서비스/봇은 이 명세를 구현하면 명세를 준수하는 모든 설치 프로그램을 지원할 수 있으므로, 사용자는 원하는 도구를 선택할 수 있습니다. 플랫폼과 IDE가 더 이상 “승자”를 서둘러 고르지 않아도 되므로, 이 분야에서 더 많은 혁신이 가능해질 것입니다.

오픈 소스 커뮤니티

설치 프로그램 요구 사항을 지정하고 이 PEP를 채택하면 Python 패키지 설치 프로그램과 사람들의 워크플로 사이의 마찰이 줄어듭니다. 그 결과 Python 패키지 설치 프로그램과 PaaS나 IDE 같은 서드파티 인프라/기술 사이의 마찰도 줄어듭니다. 전반적으로 Python 패키지 설치가 더 단순해지고 상호 운용성이 높아짐에 따라 Python 프로젝트의 개발, 배포, 유지 관리가 더 쉬워집니다.

요구 사항을 명시하고 설치 프로그램을 위한 인터페이스를 만들면 설치 프로그램 분야의 혁신 속도도 높일 수 있습니다. 이를 통해 설치 프로그램은 나머지 생태계에 같은 일을 요구하지 않고도 실험하고 고유한 기능을 추가할 수 있습니다. 새 설치 프로그램이 어떤 기능을 추가하든, 의존성을 어떤 형식으로 기록하든 지원이 더 쉬워지고 지원받을 가능성도 높아집니다. 동시에 이에 필요한 개발자 시간과 자원도 줄어듭니다.

명세

PEP 517이 빌드 시스템을 명시하는 방식과 유사하게, 설치 시스템 정보는 pyproject.toml 파일의 install-system 테이블 아래에 위치합니다.

[install-system]

install-system 테이블은 설치 시스템과 관련된 데이터와 정보를 저장하는 데 사용됩니다. 이 테이블에는 requires와 install-backend라는 여러 필수 키가 있습니다. requires 키에는 설치 프로그램 백엔드가 실행되는 데 필요한 최소 요구 사항을 담으며, 이 요구 사항은 범용 설치 프로그램이 설치합니다. install-backend 키에는 설치 백엔드의 진입점 이름이 담깁니다. 이를 통해 범용 설치 프로그램은 설치 프로그램 백엔드를 호출할 수 있을 뿐 아니라 설치 프로그램 백엔드 자체가 실행되는 데 필요한 요구 사항(설치 프로그램 백엔드 자체가 설치할 요구 사항이 아님)도 설치할 수 있습니다.

필수 키 중 하나라도 없거나 비어 있으면 범용 설치 프로그램은 오류를 발생시켜야 합니다(SHOULD).

이 인터페이스와 상호 작용하는 모든 패키지 이름은 PEP 508의 “Python 소프트웨어 패키지를 위한 의존성 명세(Dependency specification for Python Software Packages)” 형식을 따른다고 가정합니다.

install-system 테이블 예시:

#pyproject.toml
[install-system]
#Eg : pipenv
requires = ["pipenv"]
install-backend = "pipenv.api:main"

설치 프로그램 요구 사항:

requires 키로 명시된 요구 사항은 PEP 517이 명시하는 제약 조건을 충족해야 합니다. 구체적으로, 의존성 순환은 허용되지 않으며 순환이 감지되면 범용 설치 프로그램은 의존성 설치를 거부해야 합니다(SHOULD).

추가 매개변수 또는 도구별 데이터

추가 매개변수나 도구(설치 프로그램 백엔드) 데이터를 pyproject.toml 파일에 저장할 수도 있습니다. 이 데이터는 PEP 518에 명시된 대로 “tool.*” 테이블에 위치합니다. 예를 들어 설치 프로그램 백엔드가 Poetry이고 여러 의존성 그룹을 지정하려는 경우 tool.poetry 테이블은 다음과 같을 수 있습니다:

[tool.poetry.dev-dependencies]
dependencies = "dev"

[tool.poetry.deploy]
dependencies = "deploy"

데이터는 설치 프로그램 백엔드가 적절하다고 판단하는 다른 방식(예: 별도의 설정 파일)으로 저장할 수도 있습니다.

설치 프로그램 인터페이스:

설치 프로그램 인터페이스에는 필수 훅과 선택 훅이 있습니다. 규격을 준수하는 설치 프로그램 백엔드는 필수 훅을 구현해야 하며(MUST) 선택 훅을 구현할 수 있습니다(MAY). 범용 설치 프로그램은 범용 설치 프로그램이자 설치 프로그램 백엔드로 동작하기 위해 설치 프로그램 백엔드 훅 중 어느 것이든 직접 구현할 수 있지만(MAY), 반드시 그래야 하는 것은 아닙니다.

모든 훅은 **kwargs로 임의의 매개변수를 받습니다. 이 매개변수는 설치 프로그램 백엔드에 필요할 수 있지만 아직 명시되지 않은 것으로, 하위 호환성을 보장합니다. 예상하지 못한 매개변수가 설치 프로그램 백엔드에 전달되면 백엔드는 이를 무시해야 합니다.

다음 정보는 PEP 517의 해당 절과 유사합니다. 훅은 키워드 인자로 호출될 수 있으므로, 훅을 구현하는 설치 프로그램 백엔드는 시그니처가 위 인자의 순서와 이름 모두와 일치하도록 주의해야 합니다.

모든 훅은 stdout과 stderr에 임의의 정보성 텍스트를 출력할 수 있습니다(MAY). 훅은 stdin에서 읽어서는 안 되며(MUST NOT), 범용 설치 프로그램은 훅을 호출하기 전에 stdin을 닫을 수 있습니다(MAY).

범용 설치 프로그램은 백엔드의 stdout 및/또는 stderr를 캡처할 수 있습니다. 백엔드가 출력 스트림이 터미널/콘솔이 아님을 감지하면(예: sys.stdout.isatty()가 아닌 경우), 해당 스트림에 쓰는 모든 출력이 UTF-8로 인코딩되도록 해야 합니다(SHOULD). 캡처한 출력이 유효한 UTF-8이 아니더라도 범용 설치 프로그램은 실패해서는 안 되지만(MUST NOT), 그 경우 모든 정보를 보존하지 못할 수도 있습니다(MAY)(예: Python의 replace 오류 핸들러를 사용해 디코딩할 수 있습니다). 출력 스트림이 터미널이라면, 터미널에서 실행되는 다른 모든 프로그램과 마찬가지로 설치 프로그램 백엔드가 출력을 정확하게 표시할 책임을 집니다.

훅이 예외를 발생시키거나 프로세스를 종료시키면, 이는 오류를 나타냅니다.

필수 훅:

invoke_install

의존성을 설치합니다:

def invoke_install(
    path: Union[str, bytes, PathLike[str]],
    *,
    dependency_group: str = None,
    **kwargs
) -> int:
    ...
  • path : 설치 프로그램 백엔드를 호출할 위치의 절대 경로입니다(예: pyproject.toml이 있는 디렉터리).
  • dependency_group : 설치 프로그램 백엔드가 설치할 의존성 그룹을 지정하는 선택적 플래그입니다. 의존성 그룹이 존재하지 않으면 설치 시 오류가 발생합니다. 설치 프로그램 백엔드가 의존성 그룹을 지원하면 사용자는 get_dependency_groups()를 호출해 모든 의존성 그룹을 확인할 수 있습니다.
  • **kwargs : 설치 프로그램 백엔드에 필요할 수 있지만 아직 명시되지 않은 임의의 매개변수로, 하위 호환성을 보장합니다.
  • 반환값 : 종료 코드(int)입니다. 성공하면 0, 실패하면 임의의 양의 정수입니다.

범용 설치 프로그램은 종료 코드로 설치 성공 여부를 판단하며, 그 종료 코드를 그대로 반환해야 합니다(SHOULD).

선택적 훅:

invoke_uninstall

지정된 의존성을 제거합니다:

def invoke_uninstall(
    path: Union[str, bytes, PathLike[str]],
    *,
    dependency_group: str = None,
    **kwargs
) -> int:
    ...
  • path : 설치 프로그램 백엔드를 호출할 위치의 절대 경로입니다(예: pyproject.toml이 있는 디렉터리).
  • dependency_group : 설치 프로그램 백엔드가 제거할 의존성 그룹을 지정하는 선택적 플래그입니다.
  • **kwargs : 설치 프로그램 백엔드에 필요할 수 있지만 아직 명시되지 않은 임의의 매개변수로, 하위 호환성을 보장합니다.
  • 반환값 : 종료 코드(int)입니다. 성공하면 0, 실패하면 임의의 양의 정수입니다.

범용 설치 프로그램은 범용 설치 프로그램 자체가 호출된 경로와 같은 경로에서 설치 프로그램 백엔드를 호출해야 합니다(MUST).

범용 설치 프로그램은 종료 코드를 사용하여 제거가 성공했는지 판단하며, 그 종료 코드를 그대로 반환해야 합니다(SHOULD).

get_dependencies_to_install

invoke_install(...)에 의해 설치될 의존성을 반환합니다. 이를 통해 패키지 업그레이드 도구(예: Dependabot)가 의존성 파일을 파싱하지 않고도 설치하려는 의존성을 가져올 수 있습니다:

def get_dependencies_to_install(
    path: Union[str, bytes, PathLike[str]],
    *,
    dependency_group: str = None,
    **kwargs
) -> Sequence[str]:
    ...
  • path : 설치 프로그램 백엔드를 호출할 위치의 절대 경로입니다(예: pyproject.toml이 있는 디렉터리).
  • dependency_group : 의존성 그룹을 지정하면 해당 의존성 그룹에 대해 invoke_install(...)이 설치할 의존성을 얻습니다.
  • **kwargs : 설치 프로그램 백엔드가 필요로 할 수 있으나 아직 명시되지 않은 임의의 매개변수로, 하위 호환성을 가능하게 합니다.
  • 반환값: 설치할 의존성(PEP 508 문자열)의 목록입니다.

그룹이 지정된 경우, 설치 프로그램 백엔드는 제공된 의존성 그룹에 해당하는 의존성을 반환해야 합니다(MUST). 지정된 그룹이 존재하지 않거나 설치 프로그램 백엔드가 의존성 그룹을 지원하지 않는 경우, 설치 프로그램 백엔드는 오류를 발생시켜야 합니다(MUST).

그룹이 지정되지 않았고 설치 프로그램 백엔드가 기본/미지정 그룹이라는 개념을 제공하는 경우, 설치 프로그램 백엔드는 기본/미지정 그룹의 의존성을 반환할 수 있지만(MAY), 그렇지 않은 경우에는 오류를 발생시켜야 합니다(MUST).

get_dependency_groups

설치할 수 있는 의존성 그룹을 반환합니다. 이를 통해 범용 설치 프로그램은 설치 프로그램 백엔드가 알고 있는 모든 의존성 그룹을 열거할 수 있습니다.:

def get_dependency_groups(
    path: Union[str, bytes, PathLike[str]],
    **kwargs
) -> AbstractSet[str]:
    ...
  • path : 설치 프로그램 백엔드를 호출할 위치의 절대 경로입니다(예: pyproject.toml이 있는 디렉터리).
  • **kwargs : 설치 프로그램 백엔드가 필요로 할 수 있으나 아직 명시되지 않은 임의의 매개변수로, 하위 호환성을 가능하게 합니다.
  • 반환값: 알려진 의존성 그룹을 문자열로 담은 집합입니다. 빈 집합은 의존성 그룹이 없음을 나타냅니다.

update_dependencies

입력된 패키지 목록을 바탕으로 의존성 파일을 출력합니다:

def update_dependencies(
    path: Union[str, bytes, PathLike[str]],
    dependency_specifiers: Iterable[str],
    *,
    dependency_group=None,
    **kwargs
) -> int:
    ...
  • path : 설치 프로그램 백엔드를 호출할 위치의 절대 경로입니다(예: pyproject.toml이 있는 디렉터리).
  • dependency_specifiers : 갱신되는 의존성을 PEP 508 문자열로 담은 이터러블입니다. 예: ["requests==2.8.1", ...]. 특정 의존성 그룹에 대해 선택적으로 지정할 수 있습니다.
  • dependency_group : 패키지 목록이 속한 의존성 그룹입니다.
  • **kwargs : 설치 프로그램 백엔드가 필요로 할 수 있으나 아직 명시되지 않은 임의의 매개변수로, 하위 호환성을 가능하게 합니다.
  • 반환값 : 종료 코드(int)입니다. 성공하면 0이고, 실패하면 임의의 양의 정수입니다.

예시

pip와 pip의 requirements 파일을 의존성 그룹으로 사용하는 설치 프로그램 백엔드를 구현하는 경우를 생각해 봅시다. 구현은 (아주 대략적으로) 다음과 같은 모습일 수 있습니다:

import subprocess
import sys


def invoke_install(path, *, dependency_group=None, **kwargs):
    try:
        return subprocess.run(
            [
                sys.executable,
                "-m",
                "pip",
                "install",
                "-r",
                dependency_group or "requirements.txt",
            ],
            cwd=path,
        ).returncode
    except subprocess.CalledProcessError as e:
        return e.returncode

이 패키지의 이름을 pep650pip이라고 한다면, pyproject.toml에 다음과 같이 지정할 수 있습니다:

[install-system]
  #Eg : pipenv
  requires = ["pep650pip", "pip"]
  install-backend = "pep650pip:main"

근거

모든 훅은 **kwargs를 받아 하위 호환성을 보장하고, 훅이 요구하지 않는 추가 정보를 사용자가 제공해야 하는 도구별 설치 프로그램 백엔드 기능을 가능하게 합니다.

설치 프로그램 백엔드는 Python 패키지여야 하지만, 호출되었을 때 무엇을 하는지는 해당 도구의 구현 세부 사항입니다. 예를 들어, 설치 프로그램 백엔드는 플랫폼 패키지 관리자(예: apt)의 래퍼 역할을 할 수 있습니다.

이 인터페이스는 설치 프로그램 백엔드의 함수가 어떻게 동작해야 하는지를 어떤 식으로도 명세하려 하지 않습니다. 이는 설치 프로그램 백엔드가 혁신을 이루고 자신만의 방식으로 문제를 해결할 수 있도록 하기 위한 의도적인 결정입니다. 이는 또한 이 PEP가 OS 패키징에 대해 어떠한 입장도 취하지 않는다는 의미이기도 합니다. 그것은 설치 프로그램 백엔드의 영역이기 때문입니다.

Python으로 API를 정의한다는 것은 결국 일부 Python 코드를 실행해야 한다는 뜻입니다. 하지만 그렇다고 해서 Python이 아닌 설치 프로그램 백엔드(예: mamba)를 사용할 수 없는 것은 아닙니다. Python 코드에서 하위 프로세스로 실행할 수 있기 때문입니다.

하위 호환성

이 PEP는 범용 설치 프로그램에 새로운 기능을 추가할 뿐이므로 기존 코드와 기능에는 아무런 영향을 미치지 않습니다. 기존의 모든 설치 프로그램은 기존 기능과 사용 사례를 그대로 유지해야 하므로, 하위 호환성 문제가 발생하지 않습니다. 이 새로운 기능을 활용하려는 코드만 기존 코드를 변경할 동기가 생깁니다.

보안 영향

표준화된 설치 프로그램 명세가 추가되더라도 악의적인 사용자의 능력이 커지거나 무언가에 더 쉽게 접근할 수 있게 되지는 않습니다. 이 PEP에 명시된 인터페이스를 통해 범용 설치 프로그램이 호출할 수 있는 설치 프로그램은 사용자가 명시적으로 선언한 것입니다. 사용자가 악의적인 설치 프로그램을 선택했다면, 그것을 범용 설치 프로그램으로 호출하는 것은 사용자가 그 설치 프로그램을 직접 호출하는 것과 다르지 않습니다. 악의적인 설치 프로그램이 설치 프로그램 백엔드라고 해서 추가적인 권한이나 능력을 얻게 되지는 않습니다.

기각된 아이디어

표준화된 잠금 파일

표준화된 잠금 파일은 설치 프로그램 요구 사항을 명시하는 방식이 해결하는 문제 중 상당수를 똑같이 해결할 것입니다. 예를 들어, PaaS/IaaS가 표준화된 잠금 파일을 만든 설치 프로그램이 무엇이든 관계없이 그 파일을 읽을 수 있는 설치 프로그램 하나만 지원하면 되도록 할 것입니다. 표준화된 잠금 파일의 문제는 Python 패키지 설치 프로그램 간의 요구 사항 차이와 더불어, 잠금 파일을 통해 재현 가능한 환경을 만드는 것(주요 이점 중 하나)에 근본적인 문제가 있다는 점입니다.

설치 프로그램마다 요구 사항과 의존성 파일에 저장되는 정보가 크게 다르며, 이는 설치 프로그램의 기능에 따라 달라집니다. 예를 들어, Poetry와 같은 Python 패키지 설치 프로그램은 모든 Python 버전과 플랫폼에 대한 정보를 필요로 하고 적절한 해시를 계산하지만, pip는 그렇지 않습니다. 또한 pip는 같은 환경을 다시 만드는 것(정확히 같은 의존성을 설치하는 것)이 기능 범위 밖이므로 이를 보장할 수 없습니다. 이 때문에 표준화된 잠금 파일은 구현하기가 더 어려우며, 잠금 파일은 도구별로 따로 두는 편이 더 적절해 보입니다.

설치 프로그램 백엔드가 가상 환경 생성을 지원하도록 하기

설치 프로그램 백엔드는 가상 환경과 가상 환경에 설치하는 방법이라는 개념을 가지고 있을 가능성이 매우 높으므로, 가상 환경 생성도 지원하도록 하는 방안이 잠시 검토되었습니다. 하지만 결국 이는 별개의 아이디어로 판단했습니다.

미해결 문제

dependency_group 인자가 이터러블을 받아야 합니까?

그렇게 하면 서로 겹치지 않는 의존성 그룹 여러 개를 한 번의 호출로 지정할 수 있습니다. 예를 들어 “docs” 그룹과 “test” 그룹은 의존성이 서로 독립적이지만, 개발자는 개발하는 동안 두 그룹을 함께 설치하고 싶을 수 있습니다.

설치 프로그램 백엔드는 프로세스 내에서 실행됩니까?

설치 프로그램 백엔드가 프로세스 내에서 실행되면, 실행 중인 Python 환경에 적절한 정보를 질의할 수 있으므로 어떤 환경을 대상으로, 또는 어떤 환경에 설치할지 파악하기가 크게 단순해집니다.

프로세스 외부에서 실행하면 설치 대상 환경과 설치 프로그램 백엔드(그리고 경우에 따라 범용 설치 프로그램) 사이의 충돌로 생길 수 있는 문제를 최소화할 수 있습니다.

제안된 인터페이스의 결과를 인터페이스의 다른 부분에 전달하도록 강제해야 합니까?

예를 들어 get_dependencies_to_install()과 get_dependency_groups()의 결과를 invoke_install()에 전달할 수 있습니다. 그렇게 하면 제안된 인터페이스의 여러 부분이 내놓는 결과가 서로 어긋나는 것을 막을 수 있지만, 인터페이스에서 선택 사항이 아니라 필수인 부분이 더 많아집니다.

실패 조건에 대해 종료 코드 대신 예외 발생시키기

API가 종료 코드를 반환하는 대신 예외를 발생시켜야 한다는 제안이 있었습니다. 이 PEP를 현재의 설치 프로그램을 설치 프로그램 백엔드로 전환하는 데 도움을 주는 것으로 본다면, 종료 코드에 의존하는 것이 타당합니다. 또한 API에는 특정한 반환값이 없으므로, 종료 코드를 전달해도 함수의 반환값에 지장을 주지 않는다는 점도 있습니다.

이를 오류가 발생했을 때 예외를 발생시키는 방식과 비교해 보십시오. 예외를 발생시키는 방식은 오류 발생을 더 구조적으로 다룰 수 있는 방법이 될 수 있지만, 오류를 포착하려면 예외 타입을 인터페이스의 일부로 명시해야 합니다.

참고 문헌