Poetry를 통한 파이썬 패키지 관리

|

이 글은 macOS 10.15.2(Catalina) 환경을 기준으로 쓰여졌습니다.
윈도우 및 리눅스 환경에서는 사용법이 다를 수 있습니다.


파이썬의 기본 패키지 관리자인 pip는 패키지간 의존성 및 버전 호환 관리가 힘들며, 의존성 패키지를 제외한 실제 필요 패키지의 구분이 어렵다. 이를 해결하기 위해 파이썬 패키지를 관리할 수 있도록 도와주는 pipenv, pipx와 같은 여러 라이브러리들이 있지만, 항상 약간씩 기능에 아쉬움을 느껴 지금까지는 직접 requirements.txt를 버전별로 관리하는 방법을 사용했다.

그러던 중 최근에 Poetry라는 관리도구를 사용해보았는데, 다른 도구들에서 불편하던 점들이 많이 개선되어 사용법을 남겨본다.

Poetry가 자동으로 제공하는 가상환경을 사용하지 않고, Pyenv와 Pyenv-virtualenv로 직접 생성한 가상환경을 사용합니다.

Poetry 설치

현재 brew를 통한 설치가 가능한 것 같지만, brew를 통해 설치해보니 약간의 아쉬움이 있었다. (brew에서 제공한지 얼마 안되어 그런것 같다)
그러니 우선 스크립트를 통한 설치를 진행해보자

스크립트를 통한 설치

Poetry는 시스템 전역에 설치한다. pip를 사용한 설치는 권장되지 않으며, 시스템 전역에서 사용 시 몇 가지 필요 설정이 있다.

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python

(Pyenv 사용시) PATH설정

Pyenv를 사용하는 경우, Pyenv-virtualenv로 생성한 가상환경 중 단 하나에라도 존재하는 실행파일은 $HOME/.pyenv/shims/에서 찾게된다.
brew를 사용해 설치한 패키지나, 그 외에도 Pyenv로 관리되는 가상환경보다 우선하게 실행하고자 하는 명령어는 적절히 PATH의 순서를 조정해야 한다.

따라서zsh을 쓴다면 ~/.zshrc에 내용을 추가하며, bash나 다른 셸을 사용하는 경우, 해당 셸의 설정 파일을 수정해야 한다.

# ~/.zshrc
# pyenv의 PATH
export PYENV_PATH=$HOME/.pyenv
if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
if which pyenv-virtualenv-init > /dev/null; then eval "$(pyenv virtualenv-init -)"; fi

# poetry실행파일의 PATH가 pyenv의 PATH보다 우선되도록 설정
export PATH=$HOME/.poetry/bin:$PATH

사용법

프로젝트의 패키지를 Poetry가 관리하도록 초기화

npm init과 비슷하게, Poetry로 해당 폴더의 패키지 관리를 시작하는 명령어를 사용

# pyenv, pyenv-virtualenv를 사용하는 경우, 아래 명령어로 가상환경 생성&적용 후 실행
# pyenv virtualenv <버전> <env명>
# pyenv local <env명>

# 가상환경이 적용되지 않은 상태에서 초기화 시, Poetry가 임의의 가상환경을 생성
poetry init

이 명령어는 pyproject.toml 파일을 만들어준다.

패키지 추가

버전을 지정해주면 나머지는 그 버전에 맞게 호환될수 있는 버전으로 추가/설치된다.

poetry add <패키지명>

패키지 및 의존성패키지를 함께 삭제

poetry remove <패키지명>

설치된 패키지 목록 확인

내가 관리하는 패키지들과, 해당 패키지들에 의존성으로 설치된 패키지들을 분리해서 볼 수 있다.

poetry show --no-dev --tree
# 아래와 같이 설치된 패키지와 의존성 패키지 정보를 표시
boto3 1.11.9 The AWS SDK for Python
├── botocore >=1.14.9,<1.15.0
│   ├── docutils >=0.10,<0.16
│   ├── jmespath >=0.7.1,<1.0.0
│   ├── python-dateutil >=2.1,<3.0.0
│   │   └── six >=1.5
│   └── urllib3 >=1.20,<1.26
├── jmespath >=0.7.1,<1.0.0
└── s3transfer >=0.3.0,<0.4.0
    └── botocore >=1.12.36,<2.0.0
        ├── docutils >=0.10,<0.16
        ├── jmespath >=0.7.1,<1.0.0
        ├── python-dateutil >=2.1,<3.0.0
        │   └── six >=1.5
        └── urllib3 >=1.20,<1.26
django 2.2.9 A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
├── pytz *
└── sqlparse *
django-extensions 2.2.6 Extensions for Django
└── six >=1.2
django-secrets-manager 0.1.7 Django SecretsManager is custom secret managers for Django
├── boto3 *
│   ├── botocore >=1.14.9,<1.15.0
│   │   ├── docutils >=0.10,<0.16
│   │   ├── jmespath >=0.7.1,<1.0.0
│   │   ├── python-dateutil >=2.1,<3.0.0
│   │   │   └── six >=1.5
│   │   └── urllib3 >=1.20,<1.26
│   ├── jmespath >=0.7.1,<1.0.0 (circular dependency aborted here)
│   └── s3transfer >=0.3.0,<0.4.0
│       └── botocore >=1.12.36,<2.0.0 (circular dependency aborted here)
└── django *
    ├── pytz *
    └── sqlparse *
django-storages 1.8 Support for many storage backends in Django
└── django >=1.11
    ├── pytz *
    └── sqlparse *
gunicorn 20.0.4 WSGI HTTP Server for UNIX
└── setuptools >=3.0
pillow 7.0.0 Python Imaging Library (Fork)
requests 2.22.0 Python HTTP for Humans.
├── certifi >=2017.4.17
├── chardet >=3.0.2,<3.1.0
├── idna >=2.5,<2.9
└── urllib3 >=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26

poetry.lock파일로부터 requirements.txt생성

Poetry패키지 자체는 필요하지 않은 작업(ex: Docker Image생성)시에는 현재 설치된 패키지에 대한 requirements만 필요하다. 이 때, export명령어를 사용

poetry export -f requirements.txt > requirements.txt
# 아래와 같은 requirements.txt생성
amqp==2.5.2 \
    --hash=sha256:6e649ca13a7df3faacdc8bbb280aa9a6602d22fd9d545336077e573a1f4ff3b8 \
    --hash=sha256:77f1aef9410698d20eaeac5b73a87817365f457a507d82edf292e12cbb83b08d
billiard==3.6.1.0 \
    --hash=sha256:01afcb4e7c4fd6480940cfbd4d9edc19d7a7509d6ada533984d0d0f49901ec82 \
    --hash=sha256:b8809c74f648dfe69b973c8e660bcec00603758c9db8ba89d7719f88d5f01f26
boto3==1.10.14 \
    --hash=sha256:cb8f2531c22a4cf7847f62a9e23c2611300b6fdbcad577f67a9b56b686f78dd5 \
    --hash=sha256:aa40df7958bb274fad45ce6cc9ae1c77aac3b4cf33c34684646b42583a52d7e0
botocore==1.13.14 \
    --hash=sha256:48ad5efd98e0570df13a73e6463da2a9d9422f47a943b6ef74f950695c23dbb0 \
    --hash=sha256:d789f30a5def264b9d21a917aeadc4e5fc2b6a03a61f222befcfaf80eaba86e5
celery==4.3.0 \
    --hash=sha256:528e56767ae7e43a16cfef24ee1062491f5754368d38fcfffa861cdb9ef219be \
    --hash=sha256:4c4532aa683f170f40bd76f928b70bc06ff171a959e06e71bf35f2f9d6031ef9
django==2.2.7 \
    --hash=sha256:89c2007ca4fa5b351a51a279eccff298520783b713bf28efb89dfb81c80ea49b \
    --hash=sha256:16040e1288c6c9f68c6da2fe75ebde83c0a158f6f5d54f4c5177b0c1478c5b86