나의 첫 PyPI(pip) 패키지 릴리즈

오늘은 처음으로 제가 만든 Python 라이브러리를 PyPI에 릴리즈해보았습니다. 간단한 과정이지만, 배포부터 릴리즈까지 한 번에 따라하실 수 있도록 글로 정리해보았습니다.

2019. 06. 05. #development #ci/cd #python

오늘은 처음으로 제가 만든 Python 라이브러리를 PyPI에 릴리즈해보았습니다. 간단한 과정이지만, 배포부터 릴리즈까지 한 번에 따라하실 수 있도록 글로 정리해보았습니다.

setup.py 파일 만들기

setup.py는 Python 패키지에 필요한 각종 정보들을 기술해놓은 파일입니다. setup.py에서는 distutils와 setuptools 두 종류의 라이브러리를 사용할 수 있는데, 여기서는 더 대중적으로 사용되는 setuptools를 사용하여 패키지를 만들겠습니다.

setuptools는 distutils의 불편한 점들과 구조적 한계를 개선한 패키지로, 별도의 설치가 필요합니다.

아래는 telegrambot-py 패키지에 사용한 setup.py 파일의 예시입니다.

from setuptools import setup, find_packages

setup(
    name='telegrambot-py',
    version='0.0.1',
    description='Make your own telegram bot easily',
    author='Do Hoerin',
    author_email='[email protected]',
    url='https://github.com/hellodhlyn/telegrambot-py',
    python_requires='>=3.5',
    packages= ['telegrambot'],
    install_requires=[
        'python-telegram-bot>=11.1.0,<12.0.0',
    ],
    license='MIT',
    classifiers=[
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
    ],
)

대부분의 argument는 메타 정보입니다. 메타 정보가 다양할 수록 PyPI 패키지 인덱스에 보이는 정보가 더욱 풍성해지게 됩니다.

메타 정보 이외에, 실질적으로 패키지에 가장 중요한 정보들은 다음과 같습니다.

  • install_requires : 패키지를 설치하는데 필요한 의존성 목록입니다.
  • python_requires : 해당 패키지가 지원하는 Python 버전 목록입니다. 위 예시에서는 3.5 버전 이상을 지원한다는 의미의 >= 3.5로 기술되어있습니다.
  • packages : 실제 구동에 필요한 python 파일이 들어있는 패키지 정보입니다. 예시와 같이 ['telegrambot'] 이라고 되어있다면 telegrambot/__init__.py 파일을 기준으로 패키지를 생성합니다.

telegrambot-py는 순수 Python으로만 작성된 패키지이므로 특별히 외부 라이브러리를 사용하지 않습니다. 만약 C++, Rust 등으로 작성된 외부 라이브러리의 인용이 필요하다면 ext_modules 파라미터를 제공해야합니다.

이 외에도 다양한 종류의 argument가 있으며, setup 함수에 대한 상세한 스펙은 Python 공식 도큐먼트setuptools 문서를 참조하시기 바랍니다.

README 문서화

PyPI 인덱스에 더 다양한 정보를 제공하기 위해 README 문서를 이용할 수 있습니다.

앞서 추가한 setup.py 파일에 다음 내용을 추가해줍니다. 여기서는 마크다운 문서인 README.md 파일을 이용해보겠습니다.

from os import path

this = path.abspath(path.dirname(__file__))
with open(path.join(this, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    ...
    long_description=long_description,
    long_description_content_type='text/markdown',
    ...
)

패키지 만들기

패키징의 가장 대중적인 방법은 wheel을 사용하는 것입니다. wheel 패키지를 설치한 후, 다음 커맨드를 실행합니다.

python setup.py bdist_wheel

dist 폴더에 .whl 확장자의 파일이 생성됩니다.

생성된 패키지를 로컬에서 설치해보고 싶으시다면 pip install dist/[your_package_name].whl 명령어를 통해 간단히 테스트해보실 수 있습니다.

테스트 릴리즈

패키지가 원하는 의도대로 잘 생성되었는지, 메타 정보에 문제는 확인해보려면 TestPyPI를 이용하는 것이 좋습니다. TestPyPI는 오로지 테스트를 위해서만 사용되는 패키지 인덱스로, 프로덕션 환경과는 완전히 분리되어있습니다. 한 번 릴리즈한 버전은 다시는 되돌릴 수 없으므로 반드시 TestPyPI에서 한 번 테스트를 거친 후 프로덕션에 릴리즈를 하실 것을 권장합니다.

릴리즈에도 여러 가지 방법이 있지만, twine 패키지를 사용하는 것이 일반적입니다. python 기본 릴리즈 툴에 비해 twine은 HTTPS를 사용하고 있다는 점, gpg 사이닝 및 업로드가 간단하다는 점에서 강점을 보입니다.

우선 TestPyPI 홈페이지에 가입한 후 이메일 인증을 수행합니다. 프로덕션 PyPI와는 완전히 격리된 서비스이므로 별도의 가입이 필요합니다. 또한 이메일 인증을 수행하지 않으면 업로드가 정상적으로 이루어지지 않으므로 반드시 실제 사용하는 이메일 주소로 인증을 진행하셔야합니다.

인증이 완료되었다면 twine 패키지를 설치한 후 다음 명령어를 실행합니다.

twine upload --repository-url https://test.pypi.org/legacy/ dist/[your_package_name].whl

아이디와 비밀번호를 묻는 프롬프트가 뜰 것입니다. 인증에 성공했다면 정상적으로 업로드가 완료됩니다. TestPyPI 홈페이지에서 여러분이 업로드 한 패키지가 정상적으로 올라와있는지 확인해보시기 바랍니다.

프로덕션 릴리즈!

프로덕션 릴리즈 과정 자체는 테스트 릴리즈와 동일합니다. PyPI 홈페이지에 가입한 후, 이메일 인증을 마친 뒤 twine 커맨드를 통해 업로드를 진행합니다. 단, TestPyPI를 위해 추가되었던 --repository-url 옵션을 빼야한다는 점 잊지 마세요.

twine upload dist/[your_package_name].whl

프로덕션 PyPI 홈페이지는 캐시 주기가 다소 길어, 업로드 후 즉시는 보이지 않을 수도 있습니다. 다만 패키지 업로드 자체가 안된 것은 아니므로 pip install 명령어를 통해 실제로 패키지가 잘 설치되는지 테스트해보시기 바랍니다.

이렇게 프로덕션 릴리즈가 완료되었습니다! 처음에 다소 헤메셨을 수는 있겠지만, 한 번 경험해보면 그렇게 복잡하지 않다는 것을 느끼셨을 겁니다.

다음 포스트에서는 위의 일련의 과정들을 Travis CI를 이용하여 자동화, 고도화하는 과정에 대해 작성하도록 하겠습니다.

크리에이티브 커먼즈 라이선스

이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© 2011 - 2020 Do Hoerin, LYnLab