Python

pip 는 어떻게 작동할까?

둔진 2025. 1. 19. 23:14

poetryuv 같은 새로운 툴들이 나왔지만 파이썬 패키지 관리의 대세는 아직 pip입니다. 파이썬 패키지를 설치하고 싶으면 당연하게 pip install <package>라고 치죠. 인터넷에서 <package>를 다운로드해서 설치해 주고, 종속성이 있는 패키지가 있다면 같이 설치해 주는 아주 편리한 툴입니다.

그런데 가만 생각해보면 패키지를 다운로드하여 설치한다는 동작이 그리 단순히지 않습니다. 사용자 마다 쓰고 있는 파이썬 버전이 다르고, OS도 다르고, 하드웨어도 다르기 때문입니다. 패키지가 C 코드를 가지고 있다면 OS나 하드웨어를 따져야 하고, 순수 파이썬 코드라고 하더라도 파이썬 버전을 따져보아야 합니다.

오늘은 pip가 실제로 어떻게 이 모든 문제를 해결하고 패키지를 다운로드하여 설치하는지 알아보려고 합니다.

pip install <package> 명령이 하는 일

자세한 이야기를 하기 전에 pip install <package> 명령이 하는 일을 간단히 알아보겠습니다. pip install <package>가 하는 일을 한마디로 하면 "PyPI에서 해당하는 패키지를 다운로드받아 설치"하는 것입니다.

파이썬 패키지의 배포 형태(Distribution이라고 부릅니다)는 7가지인데 이번 글에서는 가장 대중적인 Wheel 패키지에 대해서만 다루려고 합니다. Wheel 패키지에 대해서는 뒤에서 다시 이야기해 보겠습니다.

pip install <package> 명령이 하는 일을 조금 더 자세한 단계로 나눠보겠습니다.

  1. 후보 패키지 목록 얻기: https://pypi.org/simple/<package>의 내용을 다운로드합니다.
  2. 최적 패키지 선택하기: 1번에 나열된 목록을 PEP 440PEP 425에 따라 해석하고 이 중 내 시스템에 맞는 최적 패키지를 선택합니다. 그리고 선택된 최적 패키지를 다운로드 합니다.
  3. 패키지 설치하기: 2번에서 선택한 패키지를 설치합니다.

각 단계를 더 자세히 살펴보겠습니다.

후보 패키지 목록 얻기

pip install tqdm이라고 명령을 내렸다고 가정해 보겠습니다. (tqdm은 손쉽게 진행상태를 콘솔에 표현해 주는 유명한 파이썬 라이브러리입니다.)

piphttps://pypi.org/simple/tqdm/ 을 다운로드합니다. https://pypi.org/simple/tqdm/ 은 간단한 HTML 문서인데요. tqdm 개발자가 제공하는 다양한 버전의 파이썬 패키지의 링크를 담고 있습니다. 실제로 접속해 보면 아래 목록을 포함해서 수많은 목록을 볼 수 있습니다.

  • tqdm-4.66.6-py3-none-any.whl
  • tqdm-4.66.6.tar.gz
  • tqdm-4.67.0-py3-none-any.whl
  • tqdm-4.67.0.tar.gz
  • tqdm-4.67.1-py3-none-any.whl
  • tqdm-4.67.1.tar.gz

Source Distribution

이번 글에서는 Source Distribution은 간단히 언급만 하려고 합니다. 위의 목록에서 *.tar.gz에 해당하는 것들이 Source Distribution입니다.

Source Distribution은 말 그대로 해당 패키지의 소스코드를 묶어서 배포한 경우입니다. 소스코드는 파이썬 코드일 수도 있지만, C 코드가 있을 수도 있습니다. 그래서 Source Distribution을 사용하려면 소소코드를 설치하려는 환경에 맞게 빌드하고 설치해야 합니다.

Built Distribution

*.whl 파일은 Wheel이라고 부르는 파이썬 패키지 방식입니다. Wheel 패키지는 Built Distribution인데요. 이미 패키지 개발자가 특정 환경에 맞도록 코드를 빌드해서 배포했기 때문에 Built라고 부릅니다. Source Distribution은 내 환경에 맞게 빌드한 후에 설치가 가능하지만, Wheel은 이미 빌드가 된 결과물이기 때문에 바로 설치하면 됩니다.

하지만 여기에는 한 가지 문제점이 있습니다. 같은 소스코드라고 하더라도 OS나 하드웨어에 따라 빌드 결과물이 달라진다는 점입니다. 특히 C 코드 같은 경우가 그렇습니다. 이 문제를 해결하기 위해서 패키지 개발자들은 여러 환경의 빌드 결과를 각각 다른 Wheel 파일로 제공합니다.

유명한 딥러닝 패키지인 pytorch의 예를 살펴보겠습니다. 헷갈리지만 pytorch의 패키지명은 torch입니다. https://pypi.org/simple/torch/ 에 접속해 보면 tqdm보다 다양한 파일들이 존재하는 것을 볼 수 있습니다.

  • torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl
  • torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl
  • torch-2.5.1-cp312-cp312-win_amd64.whl
  • torch-2.5.1-cp312-none-macosx_11_0_arm64.whl

같은 pytorch 2.5.1 버전이지만 첫 번째 Wheel 패키지는 리눅스 OS와 X86 64비트 CPU를 위한 것입니다. 네 번째는 Mac OS와 arm64 CPU를 위한 것이고요.

패키지 개발자들은 인기 있는 OS와 하드웨어 조합에 대해서 Wheel 패키지를 제공합니다. 하지만 얼마나 다양한 환경을 지원할지는 패키지 개발자에게 달려있습니다. 만약에 내가 사용하는 환경에 맞는 Wheel 패키지가 없다면 어떻게 해야 할까요? Source Distribution을 사용해서 빌드해서 설치하면 됩니다.

한 가지 이상한 점이 있습니다. pytorch와 다르게 tqdm은 OS, 하드웨어 관계없이 tqdm 버전별로 하나의 Wheel 패키지만 제공하는 것을 볼 수 있습니다. 무슨 차이일까요?

최적 패키지 선택하기

이 질문의 답은 https://pypi.org/simple/ 에서 받은 목록 중 최적 패키지를 선택하는 2단계와 관련이 있습니다. pip는 정책에 따라 https://pypi.org/simple/에 있는 패키지들 중에 최적 패키지를 선택합니다.

  1. 내 환경과 맞는 패키지들만 남깁니다.
  2. 1번 결과 중 최신 버전들만 남깁니다.
  3. 2번 결과 중 Wheel이 있다면 Wheel 패키지만 남깁니다.
    (Wheel이 없이 Source Distribution만 있는 경우는 이 글에서는 다루지 않습니다. pip 옵션을 통해 Wheel보다 Source Distribution을 선호하게 할 수도 있습니다.)
  4. 3번 결과 중 내 환경과 가장 근접한 패키지를 선택합니다.

PEP 425

1번 내 환경과 맞는 패키지 고르기외 4번 내 환경과 가장 근접한 패키지 고르기를 이해하려면 먼저 PEP 425를 이해해야 합니다. PEP 425Compatibility Tags for Built Distributions라는 제목 그대로 Built Distribution이 어떤 환경에 쓰일 수 있는지 나타내는 Tag들에 대한 명세입니다.

Tag는 {python tag}-{abi tag}-{platform tag}으로 구성됩니다.

  • python tag: 호환되는 파이썬 구현(CPython, IronPython, PyPy 등)과 버전을 나타냅니다. 예를 들어 cp312는 CPython 3.12 버전과 호환된다는 의미입니다. py3는 파이썬 구현과 관계없이 모든 파이썬 3 버전과 호환된다는 의미입니다.
  • abi tag: ABI는 Application Binary Interface의 약자로 주로 C/C++로 된 Extentions이 어떤 파이썬 구현/버전과 호환되는지를 명시합니다. 특별한 제약이 없다면 none으로 표기합니다.
  • platform tag: platform tag는 운영체제, 하드웨어 등 플랫폼 정보를 표시합니다. win32, linux_x86_64 같은 것들이 될 수 있고, 특별한 제약이 없다면 any로 표시합니다.

예를 들어서 살펴보겠습니다.

tqdm-4.67.1-py3-none-any.whl은 파이썬 3이라면 모두 사용가능하고, ABI나 OS/CPU 제약 없이 사용가능합니다.

torch-2.5.1-cp312-none-macosx_11_0_arm64.whl은 CPython 3.12에서 사용가능하고, arm64 기반의 Mac OS에서 사용가능합니다.

실제 예로 살펴보기

이 글을 쓰는 시점에 저는 Mac에서 최신 버전인 파이썬 3.13을 사용하고 있습니다. pip를 이용해서 pytorch를 설치해 보겠습니다.

(.venv) ➜  python --version
Python 3.13.1
(.venv) ➜  pip install torch
ERROR: Could not find a version that satisfies the requirement torch (from versions: none)
ERROR: No matching distribution found for torch

그런데 위와 같이 요구사항을 만족하는 버전을 찾을 수 없다고 나옵니다. 왜일까요?

https://pypi.org/simple/torch/ 에 접속해 봅니다. 패키지 목록들을 살펴보니 Wheel 패키지들이 파이썬 버전, AIB, Platform 따라 구분된 것을 볼 수 있습니다. 제 파이썬 버전인 3.13에 해당하는 cp313으로 검색하자 아래 두 가지 파일이 나옵니다.

  • torch-2.5.0-cp313-cp313-manylinux1_x86_64.whl
  • torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl

두 가지 모두 Mac은 지원하지 않습니다. 앞에 말한 4단계 중 1단계에서 모두 탈락입니다. 저런 에러가 나오는 것이 당연합니다. 어떻게 해야 할까요? 한 가지 방법은 pytorch 개발자들이 파이썬 3.13용 Wheel을 올려줄 때까지 기다리는 것입니다. 하지만 마냥 기다리기에는 마음이 너무 급합니다.

혹시 하는 마음에 cp312로 검색해 봅니다.

  • torch-2.5.0-cp312-cp312-manylinux1_x86_64.whl
  • torch-2.5.0-cp312-cp312-manylinux2014_aarch64.whl
  • torch-2.5.0-cp312-cp312-win_amd64.whl
  • torch-2.5.0-cp312-none-macosx_11_0_arm64.whl
  • torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl
  • torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl
  • torch-2.5.1-cp312-cp312-win_amd64.whl
  • torch-2.5.1-cp312-none-macosx_11_0_arm64.whl

확실히 이전 파이썬 버전이라서인지 Mac OS를 포함한 Wheel들이 많습니다. 이번에는 torch-2.5.1로 검색해 봅니다.

  • torch-2.5.1-cp310-cp310-manylinux1_x86_64.whl
  • torch-2.5.1-cp310-cp310-manylinux2014_aarch64.whl
  • torch-2.5.1-cp310-cp310-win_amd64.whl
  • torch-2.5.1-cp310-none-macosx_11_0_arm64.whl
  • torch-2.5.1-cp311-cp311-manylinux1_x86_64.whl
  • torch-2.5.1-cp311-cp311-manylinux2014_aarch64.whl
  • torch-2.5.1-cp311-cp311-win_amd64.whl
  • torch-2.5.1-cp311-none-macosx_11_0_arm64.whl
  • torch-2.5.1-cp312-cp312-manylinux1_x86_64.whl
  • torch-2.5.1-cp312-cp312-manylinux2014_aarch64.whl
  • torch-2.5.1-cp312-cp312-win_amd64.whl
  • torch-2.5.1-cp312-none-macosx_11_0_arm64.whl
  • torch-2.5.1-cp313-cp313-manylinux1_x86_64.whl
  • torch-2.5.1-cp39-cp39-manylinux1_x86_64.whl
  • torch-2.5.1-cp39-cp39-manylinux2014_aarch64.whl
  • torch-2.5.1-cp39-cp39-win_amd64.whl
  • torch-2.5.1-cp39-none-macosx_11_0_arm64.whl

파이썬 3.12까지는 Mac용 Wheel이 있지만 파이썬 3.13은 아직 리눅스만 지원합니다. 아무래도 pytorch 사용자가 가장 많은 리눅스 버전을 먼저 배포하고 윈도와 Mac은 그다음인가 봅니다.

pytorch-2.5.0 마찬가지입니다. 지금까지 상황을 봤을 때 pytorch를 쓰고 싶다면 파이썬 버전을 3.12로 내리는 수밖에 없습니다. 파이썬을 3.12로 바꾸고 다시 실행해 봅니다.

(.venv) ➜  python --version
Python 3.12.8
(.venv) ➜  pip install torch
Collecting torch
  Downloading torch-2.5.1-cp312-none-macosx_11_0_arm64.whl.metadata (28 kB)
Collecting filelock (from torch)
  Downloading filelock-3.16.1-py3-none-any.whl.metadata (2.9 kB)
Collecting typing-extensions>=4.8.0 (from torch)
  Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting networkx (from torch)
  Downloading networkx-3.4.2-py3-none-any.whl.metadata (6.3 kB)
Collecting jinja2 (from torch)
  Downloading jinja2-3.1.5-py3-none-any.whl.metadata (2.6 kB)
Collecting fsspec (from torch)
  Downloading fsspec-2024.12.0-py3-none-any.whl.metadata (11 kB)
Collecting setuptools (from torch)
  Downloading setuptools-75.8.0-py3-none-any.whl.metadata (6.7 kB)
Collecting sympy==1.13.1 (from torch)
  Downloading sympy-1.13.1-py3-none-any.whl.metadata (12 kB)
Collecting mpmath<1.4,>=1.1.0 (from sympy==1.13.1->torch)
  Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)
Collecting MarkupSafe>=2.0 (from jinja2->torch)
  Downloading MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl.metadata (4.0 kB)
Downloading torch-2.5.1-cp312-none-macosx_11_0_arm64.whl (63.9 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.9/63.9 MB 39.3 MB/s eta 0:00:00
Downloading sympy-1.13.1-py3-none-any.whl (6.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.2/6.2 MB 56.2 MB/s eta 0:00:00
Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Downloading filelock-3.16.1-py3-none-any.whl (16 kB)
Downloading fsspec-2024.12.0-py3-none-any.whl (183 kB)
Downloading jinja2-3.1.5-py3-none-any.whl (134 kB)
Downloading networkx-3.4.2-py3-none-any.whl (1.7 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.7/1.7 MB 44.7 MB/s eta 0:00:00
Downloading setuptools-75.8.0-py3-none-any.whl (1.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 62.1 MB/s eta 0:00:00
Downloading MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl (12 kB)
Downloading mpmath-1.3.0-py3-none-any.whl (536 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 122.3 MB/s eta 0:00:00
Installing collected packages: mpmath, typing-extensions, sympy, setuptools, networkx, MarkupSafe, fsspec, filelock, jinja2, torch
Successfully installed MarkupSafe-3.0.2 filelock-3.16.1 fsspec-2024.12.0 jinja2-3.1.5 mpmath-1.3.0 networkx-3.4.2 setuptools-75.8.0 sympy-1.13.1 torch-2.5.1 typing-extensions-4.12.2

메시지가 길지만 중간쯤 보면 기대대로 torch-2.5.1-cp312-none-macosx_11_0_arm64.whl을 받아서 설치한 것을 볼 수 있습니다.

그런데 저는 pytorch 하나 설치하려고 했는데 저 긴 메시지는 다 무엇일까요? 이제 자연스럽게 다음 단계인 패키지 설치하기로 넘어갈 때입니다.

패키지 설치하기

앞 단계에서 꽤 복잡한 과정을 거쳐서 내 환경에 딱 맞는 Wheel 패키지를 선택하고 다운로드를 하였습니다. 이제 패키지를 실제로 설치하는 단계만 남았습니다. 앞에 이야기한 것대로 Wheel 은 Built Distribution, 즉 모든 빌드가 끝난 상태이기 때문에 설치라는 것은 단순히 패키지 구성 요소를 적절한 곳에 복사하는 것에 지나지 않습니다.

pip는 어떤 파일이 어디에 있는지 알고 파일들을 복사할까요? 궁금증을 해결하기 위해 Wheel 파일을 열어보겠습니다.

Wheel 파일

pytorch 보다는 상대적으로 작은 tqdm을 다운로드하여보겠습니다. 현재 기준으로 최신 버전인 tqdm-4.67.1-py3-none-any.whl을 받았습니다. 그런데 이 파일의 내부를 어떻게 볼 수 있을까요?

사실 Wheel 파일은 확장자만 whl일 뿐 일반적인 zip 파일입니다. 즉, 여러분이 사용하는 대부분의 압축 해제 프로그램으로 압축을 폴 수 있습니다. 저는 아래와 같이 Mac에서 압축을 해제했습니다.

➜  mkdir tqdm_wheel
➜  cd tqdm_wheel
➜  unzip ../tqdm-4.67.1-py3-none-any.whl
➜  ls
tqdm                  tqdm-4.67.1.dist-info

보시는 것처럼 tqdmtqdm-4.67.1.dist-info이라는 두 개의 디렉터리가 있는 것을 알 수 있습니다.

tree 명령으로 디렉토리 구조를 살펴보겠습니다.

➜  tree
.
├── tqdm
│   ├── __init__.py
│   ├── __main__.py
│   ├── _dist_ver.py
│   ├── _main.py
│   ├── _monitor.py
│   ├── _tqdm.py
│   ├── _tqdm_gui.py
│   ├── _tqdm_notebook.py
│   ├── _tqdm_pandas.py
│   ├── _utils.py
│   ├── asyncio.py
│   ├── auto.py
│   ├── autonotebook.py
│   ├── cli.py
│   ├── completion.sh
│   ├── contrib
│   │   ├── __init__.py
│   │   ├── bells.py
│   │   ├── concurrent.py
│   │   ├── discord.py
│   │   ├── itertools.py
│   │   ├── logging.py
│   │   ├── slack.py
│   │   ├── telegram.py
│   │   └── utils_worker.py
│   ├── dask.py
│   ├── gui.py
│   ├── keras.py
│   ├── notebook.py
│   ├── rich.py
│   ├── std.py
│   ├── tk.py
│   ├── tqdm.1
│   ├── utils.py
│   └── version.py
└── tqdm-4.67.1.dist-info
    ├── LICENCE
    ├── METADATA
    ├── RECORD
    ├── WHEEL
    ├── entry_points.txt
    └── top_level.txt

tqdm 디렉터리에는 패키지를 구현한 코드들이 들어있고, tqdm-4.67.1.dist-info 디렉토리에는 이 패키지를 설명하는 정보를 담은 파일들이 들어있습니다.

설치해 보자

이제 pip를 이용해서 tqdm을 설치해 보겠습니다.

(.venv) ➜  pip install tqdm
Collecting tqdm
  Downloading tqdm-4.67.1-py3-none-any.whl.metadata (57 kB)
Downloading tqdm-4.67.1-py3-none-any.whl (78 kB)
Installing collected packages: tqdm
Successfully installed tqdm-4.67.1

tqdm이 잘 설치된 것을 볼 수 있습니다. 실제로는 어디로 설치가 됐을까요? 파이썬 패키지가 어디에 설치되는지는 OS와 환경에 따라 매우 복잡한 규칙에 따라 정해집니다. 하지만 가상환경인 venv를 사용하고 있다면 간단합니다. 아래와 같이 venv를 만든 디렉터리의 lib/<python version>/site-packages/에 설치됩니다.

(.venv) ➜  cd .venv/lib/python3.12/site-packages
(.venv) ➜  ls | grep tqdm
tqdm
tqdm-4.67.1.dist-info

실제 설치된 내용물을 살펴보겠습니다.

(.venv) ➜  tree tqdm*
tqdm
├── __init__.py
├── __main__.py
├── __pycache__
│   ├── __init__.cpython-312.pyc
│   ├── __main__.cpython-312.pyc
│   ├── _dist_ver.cpython-312.pyc
│   ├── _main.cpython-312.pyc
│   ├── _monitor.cpython-312.pyc
│   ├── _tqdm.cpython-312.pyc
│   ├── _tqdm_gui.cpython-312.pyc
│   ├── _tqdm_notebook.cpython-312.pyc
│   ├── _tqdm_pandas.cpython-312.pyc
│   ├── _utils.cpython-312.pyc
│   ├── asyncio.cpython-312.pyc
│   ├── auto.cpython-312.pyc
│   ├── autonotebook.cpython-312.pyc
│   ├── cli.cpython-312.pyc
│   ├── dask.cpython-312.pyc
│   ├── gui.cpython-312.pyc
│   ├── keras.cpython-312.pyc
│   ├── notebook.cpython-312.pyc
│   ├── rich.cpython-312.pyc
│   ├── std.cpython-312.pyc
│   ├── tk.cpython-312.pyc
│   ├── utils.cpython-312.pyc
│   └── version.cpython-312.pyc
├── _dist_ver.py
├── _main.py
├── _monitor.py
├── _tqdm.py
├── _tqdm_gui.py
├── _tqdm_notebook.py
├── _tqdm_pandas.py
├── _utils.py
├── asyncio.py
├── auto.py
├── autonotebook.py
├── cli.py
├── completion.sh
├── contrib
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-312.pyc
│   │   ├── bells.cpython-312.pyc
│   │   ├── concurrent.cpython-312.pyc
│   │   ├── discord.cpython-312.pyc
│   │   ├── itertools.cpython-312.pyc
│   │   ├── logging.cpython-312.pyc
│   │   ├── slack.cpython-312.pyc
│   │   ├── telegram.cpython-312.pyc
│   │   └── utils_worker.cpython-312.pyc
│   ├── bells.py
│   ├── concurrent.py
│   ├── discord.py
│   ├── itertools.py
│   ├── logging.py
│   ├── slack.py
│   ├── telegram.py
│   └── utils_worker.py
├── dask.py
├── gui.py
├── keras.py
├── notebook.py
├── rich.py
├── std.py
├── tk.py
├── tqdm.1
├── utils.py
└── version.py
tqdm-4.67.1.dist-info
├── INSTALLER
├── LICENCE
├── METADATA
├── RECORD
├── REQUESTED
├── WHEEL
├── entry_points.txt
└── top_level.txt

Wheel의 내용물이 그대로 복사돼있는 것을 알 수 있습니다. 하나만 빼고 말이죠. Wheel과 달리 설치된 버전에는 *.pyc 파일들이 추가로 있는 것을 볼 수 있습니다. *.pyc는 파이썬 소스 코드를 바이트코드 형태로 컴파일한 버전입니다. 실행 속도를 빠르게 하기 위해 미리 *.pyc를 생성해 둔 것입니다. pyc 파일에 대해서는 제 블로그의 pyc 파일에 대해서라는 글을 추천드립니다.

Dependencies

torch를 설치할 때로 다시 돌아가보겠습니다.

(.venv) ➜  python --version
Python 3.12.8
(.venv) ➜  pip install torch
Collecting torch
  Downloading torch-2.5.1-cp312-none-macosx_11_0_arm64.whl.metadata (28 kB)
Collecting filelock (from torch)
  Downloading filelock-3.16.1-py3-none-any.whl.metadata (2.9 kB)
Collecting typing-extensions>=4.8.0 (from torch)
  Downloading typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting networkx (from torch)
  Downloading networkx-3.4.2-py3-none-any.whl.metadata (6.3 kB)
Collecting jinja2 (from torch)
  Downloading jinja2-3.1.5-py3-none-any.whl.metadata (2.6 kB)
Collecting fsspec (from torch)
  Downloading fsspec-2024.12.0-py3-none-any.whl.metadata (11 kB)
Collecting setuptools (from torch)
  Downloading setuptools-75.8.0-py3-none-any.whl.metadata (6.7 kB)
Collecting sympy==1.13.1 (from torch)
  Downloading sympy-1.13.1-py3-none-any.whl.metadata (12 kB)
Collecting mpmath<1.4,>=1.1.0 (from sympy==1.13.1->torch)
  Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)
Collecting MarkupSafe>=2.0 (from jinja2->torch)
  Downloading MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl.metadata (4.0 kB)
Downloading torch-2.5.1-cp312-none-macosx_11_0_arm64.whl (63.9 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.9/63.9 MB 39.3 MB/s eta 0:00:00
Downloading sympy-1.13.1-py3-none-any.whl (6.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.2/6.2 MB 56.2 MB/s eta 0:00:00
Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Downloading filelock-3.16.1-py3-none-any.whl (16 kB)
Downloading fsspec-2024.12.0-py3-none-any.whl (183 kB)
Downloading jinja2-3.1.5-py3-none-any.whl (134 kB)
Downloading networkx-3.4.2-py3-none-any.whl (1.7 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.7/1.7 MB 44.7 MB/s eta 0:00:00
Downloading setuptools-75.8.0-py3-none-any.whl (1.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 62.1 MB/s eta 0:00:00
Downloading MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl (12 kB)
Downloading mpmath-1.3.0-py3-none-any.whl (536 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 122.3 MB/s eta 0:00:00
Installing collected packages: mpmath, typing-extensions, sympy, setuptools, networkx, MarkupSafe, fsspec, filelock, jinja2, torch
Successfully installed MarkupSafe-3.0.2 filelock-3.16.1 fsspec-2024.12.0 jinja2-3.1.5 mpmath-1.3.0 networkx-3.4.2 setuptools-75.8.0 sympy-1.13.1 torch-2.5.1 typing-extensions-4.12.2

메시지만 봐도 단순히 torch-2.5.1-cp312-none-macosx_11_0_arm64.whl만 설치하는 것은 아님을 알 수 있습니다. 많은 복잡한 패키지들이 그렇듯이 torch도 의존적인 다른 패키지가 있습니다. 위 메시지를 보면 torch를 사용하기 위해서는 filelock, typing_extensions, network 패키지 등이 필요한 것을 알 수 있습니다.

pip는 어떻게 패키지 의존성을 알 수 있을까요? 비밀은 메시지 중 Downloading torch-2.5.1-cp312-none-macosx_11_0_arm64.whl.metadata (28 kB)라는 부분에 있습니다.

tqdm 때 했던 것처럼 torch-2.5.1-cp312-none-macosx_11_0_arm64.whl을 다운로드하여 압축을 풀어보겠습니다. 압축 해제된 결과를 보면 torch-2.5.1.dist-info라는 디렉터리가 있고 이 안에 METADATA라는 파일이 있습니다.

METADATA는 해당 패키지에 대한 다양한 정보를 담고 있는 파일입니다. 이 파일 중간 쯤에 가면 아래와 같은 부분들을 찾을 수 있습니다.

Requires-Dist: filelock
Requires-Dist: typing-extensions>=4.8.0
Requires-Dist: networkx
Requires-Dist: jinja2
Requires-Dist: fsspec
(중략)
Requires-Dist: setuptools; python_version >= "3.12"
Requires-Dist: sympy==1.13.1; python_version >= "3.9"

pip는 이 부분을 통해 이 torch 패키지가 filelock, typing_extensions, network 등을 필요로 한다는 것을 알 수 있습니다. 이제 pip가 할 일은 앞에 했던 것과 같은 과정을 거쳐 filelock, typing_extensions, network을 설치하는 것입니다.

위의 메시지를 보면 재미있는 부분이 하나 더 있습니다.

Collecting sympy==1.13.1 (from torch)
  Downloading sympy-1.13.1-py3-none-any.whl.metadata (12 kB)
Collecting mpmath<1.4,>=1.1.0 (from sympy==1.13.1->torch)
  Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)

torchMETADATA를 통해 sympy가 필요하다는 것을 알 수 있습니다. pipsympy를 설치하려고 했을 겁니다. 그리고 sympyMETADATA를 통해 mpmath라는 패키지가 필요하는 것을 알게 되고, mpmath를 설치하기 위한 동일한 과정을 시작합니다. 실제로 sympyMETADATA를 보면 아래와 같은 부분이 있습니다.

Requires-Dist: mpmath <1.4,>=1.1.0

마무리

이번 글에서는 pip install <package> 명령이 내부적으로 어떻게 동작하는지 알아보았습니다. 사실 이런 복잡한 과정을 몰라도 pip를 사용하는데 문제는 없습니다. 하지만 pip의 작동 방식에 대해 조금 더 깊이 이해한다면 문제가 발생했을 때 더 잘 대처할 수 있지 않을까 합니다. 무엇보다 개발자로서 이런 정보를 알아가는 것 자체가 재미있는 일이기도 하고요.