본문 바로가기

Python_Beginer/Study

[Python]패키징 가이드(PypI 패키지)

반응형

개요

Python 에서는 project를 packaging 할 수 있는 방법들을 제공하고 있습니다. 이 가이드에서는  어떻게 Python project를 간단하게 packaging 할 수 있는지 알려드립니다. Package를 만들기 위해  필요한 파일들과 구조들을 어떻게 추가하는지, 어떻게 Package를 빌드하는지, 그리고 어떻게  PyPI에 업로드 하는지를 다루게 됩니다.

간단한 프로젝트

이 가이드는 example_pkg 라는 간단한 project 를 사용합니다.

만약 Python module 과 Package를 import 하는 것에 익숙하지 않다면, 조금 시간을 투자하셔서 아래 링크에 있는 내용을 읽어보시는 것을 추천드립니다.

https://docs.python.org/3/tutorial/modules.html#packages

혹시나 Packaging 을 원하는 Project 를 이미 가지고 계시더라도, 일단은 이 가이드에서 다루고  있는 example package를 사용해 따라오시고, 이후에 원하는 project 를 Packaging 하는 것을  추천드립니다.

아래 구조에 따라 project 를 생성해주세요.

packaging_tutorial
└── example_pkg  
        └── __init__.py

일단 이 구조로 생성하면, 이 가이드에서 사용하고 있는 모든 Commands를 top-level-folder 에서  사용할 수 있으니  cd packaging_tutorial 명령어를 꼭 실행해주세요.

example_pkg/init.py 는 Directory를 package 안에 포함 시키기 위해 꼭 필요한 파일입니다.  해당 파일은 빈 파일이어도 무방합니다.

Package files 만들기

이제 이 Project 를 packaging 하기 위한 몇 가지 파일들을 생성하고, 배포 준비를 해보려고 합니다.  아래에 명시된 파일들을 생성하고 project 의 Root directory 에 옮기세요. 다음 단계를 따라가며  파일들의 내용을 채워나가면 됩니다.

packaging_tutorial
├── LICENSE
├── README.md
├── example_pkg
│     └── __init__.py
├── setup.py
└── tests

Tests 폴더 만들기

이 폴더는 Unit Test를 위한 폴더입니다. 지금은 비워두고 넘어갑시다.

Setup.py 만들기

setup.py 는 setuptools 를 위한 build script 파일입니다. 이 파일은 setuptools 에게 패키지 관련한  정보를 알려줍니다. (예를들어, Name and Version etc.) 또한, 어떤 Code file 이 포함되어야하는지도 알려줍니다.

setup.py 를 열고 아래 내용을 넣어주세요. package name을 여러분의 username (예를들어, example-pkg-theacodes)로 바꿔주세요. 이 과정은 유일한 package name을  생성하고 이 가이드를 따라한 다른 사람들이 Pypi에 올린 package들과 충돌하지 않도록 해줍니다.

setup.py

import setuptools
 
with open("README.md", "r") as fh:
    long_description = fh.read()
 
setuptools.setup(
    name="example-pkg-YOUR-USERNAME-HERE", # Replace with your own username
    version="0.0.1",
    author="Example Author",
    author_email="author@example.com",
    description="A small example package",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="<https://github.com/pypa/sampleproject>",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
)

setup() 은 몇 가지 속성들을 가지고 있습니다. 이 예제에서는 상대적으로 최소의 구성 요소만 쓰고 있습니다.

  • name 은 Package의 배포 이름입니다. 이 이름에는 문자, 숫자, '_', '-' 가  포함된 어떤 이름이든  사용할 수 있습니다. 또한, 이름은 pypi.org에 있는 package 명들과 중복되어서는 안됩니다.  이 가이드에선 반드시 본인의 username으로 업데이트를 시켜주세요. 이 작업은 Package를  업로드할 때 이미 존재하는 Package 명과의 중복을 방지해줍니다. (Package 명이 중복되면  업로드 되지 않습니다.)
  • version 은 Package version을 말합니다.  자세한 정보는 PEP 440 를 확인해주세요.
  • author 와 author_email 은 Package 작성자를 보여줍니다.
  • description 은 Package 에 대해 짧게 한 문장으로 요약한 내용입니다.
  • long_description 은 Package의 자세한 description 을 보여줍니다.  이것은 Pypi에 있는 Package detail package 에 표시됩니다.  여기서 long description 은 README.md 파일에서 불러와지는데 보통 이런 패턴으로 많이  쓰입니다.
  • long_description_content_type 은 index 에 long_description의 markup 유형을 알려줍니다.  여기서는 Markdown 입니다.
  • url 은 Project 홈페이지의 URL 입니다. 많은 Project 에서 여기에 GitHub, GitLab, Bitbucket  또는 유사한 Code hosting Service 링크를 입력합니다.
  • package 는 배포 Package 에 포함되어야 하는 Python import packages 들의 리스트 입니다.  일일히 각 package들을 나열하는 것보다, find_package() 를 써서 자동으로  모든 Packages 와 Subpackages 를 찾을 수 있습니다.  여기에서는 example_pkg 가 Package 목록에 들어가고 이것은 현재 project 구조에서  유일한 Package 입니다.
  • classifiers 는 index 를 제공하고 pip 에 Package 에 대한 추가적인 metadata 를 제공합니다.  여기서 이 Package 는 Python3에서만 호환이 가능하고, 라이센스는 MIT License 에 있고, OS 독립적입니다.  적어도 Package가 작동하는 Python version과 어떤 라이센스를 사용할 수 있는지,  어떤 OS에서 Package가 작동하는지를 포함해야합니다. classifiers에 대한 추가적인  정보는 https://pypi.org/classifiers/ 를 확인하세요.

더 자세한 정보를 보려면 Packaging and distributing projects 를 참조하세요.

README.md 만들기

README.md 파일을 열고 아래의 내용을 넣어주세요. 아래 내용을 본인이 원하는 대로 수정해서 사용이 가능합니다.

# Example Package
This is a simple example package. You can use
[Github-flavored Markdown](<https://guides.github.com/features/mastering-markdown/>)
to write your content.

LICENSE 만들기

Pypi에 업로드된 모든 Package 에 라이센스를 포함하는 것은  중요합니다. 이 라이센스 파일은 Package 를 설치하는 사용자에게 Package를 사용할 수 있는 조건에 대해서 알려줍니다.

라이센스 선택 도움말은 여기를 보시면 됩니다.

https://choosealicense.com/

일단 라이센스를 선택하고 나면, LICENSE를 열고 lincense text를 입력하세요.

아래는 MIT License 를 예시로 들었습니다.

Copyright (c) 2018 The Python Packaging Authority

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Distribution archives 만들기

다음 단계는 Distribution packages 를 만드는 것입니다. Pypi 에 올라간 이러한 archives 들은 pip를 통해 설치할 수 있습니다.

반드시 setuptools 와 wheel 을 최신 버전으로 업데이트 해주세요.

python3 -m pip install --user --upgrade setuptools wheel

이제 setup.py 가 위치한 곳에서 아래 Command 를 실행해주세요.

python3 setup.py sdist bdist_wheel

명령어 실행 후에는 text 형태의 많은 output이 나옵니다. 그리고 완료된 이후에는 /dist 에 2가지 파일을 생성하게 됩니다.

dist/

   example_pkg_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl

   example_pkg_YOUR_USERNAME_HERE-0.0.1.tar.gz

tar.gz 파일은 Source Archive  이고 .whl 파일은 Built Distribution입니다.  최신 pip 버전에서는 built distributions install 을 선호하고 있습니다만, 필요하다면  Source Archive를 사용할 수 있습니다.  항상 Source Archive 를 업로드하고 Project 가 호환되는 Platform 에 대한 built archives 을  제공해야 합니다.  여기서는 example package는 어떤 Platform 에 있는 Python 과도 호환이 가능하므로  built distribution 만 필요합니다.

Distribution archives 업로드 하기

마지막으로, Pypi에 Package를 업로드할 시간입니다!

처음으로 할 일은 Test PyPI 에 계정 등록을 해야합니다. Test PyPI는 Package index 의 테스트와 실험 목적으로 만들어진 분리된 인스턴스입니다. 이 가이드에서 하는 것과 같이 실제 index에 업로드 할 필요성이 없을 때 굉장히 좋습니다. 등록을 위해  https://test.pypi.org/account/register/ 로 이동하고 이 페이지에 있는 모든 단계들을 수행하시면 됩니다. Package를 업로드하기 전에 이메일 인증을 받아야합니다. 더 자세한 내용은 Using TestPyPI 를 참조하세요.

이제 여러분은 PyPI API Token을 만들어서 여러분의 Project를 안전하게 업로드할 수 있습니다.

https://test.pypi.org/manage/account/#api-tokens 여기로 가서 새로운 API Token을 만드세요. 새로운 Project 를 만들고 있으므로 Project 의 범위를 특정 Project 에 맞춰 제한하지 마십시오.

Token을 저장하거나 Copy하기 전까지 절대로 페이지를 닫지 마십시오! - 페이지를 닫으면 다시 볼 수 없습니다.

이제 등록이 끝났으면, twine 을 이용해서 distribution packages 업로드할 수 있습니다. Twine을 설치해야합니다.

python3 -m pip install --user --upgrade twine

설치가되면, /dist 아래에 있는 archives 전부를 업로드 하기 위해 Twine을 실행합니다.

python3 -m twine upload --repository testpypi dist/*

username 과 password를 입력하라는 메시지를 받게됩니다. username에 __token__을 넣고, password에 token value 값을 pypi- prefix 와 함께 넣어주세요.

명령어가 모두 수행되고 나면, 아래와 같은 output과 비슷한 형태로 보여집니다.

Uploading distributions to <https://test.pypi.org/legacy/>

Enter your username: [your username]

Enter your password:

Uploading example_pkg_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl

100%|█████████████████████| 4.65k/4.65k [00:01<00:00, 2.88kB/s]

Uploading example_pkg_YOUR_USERNAME_HERE-0.0.1.tar.gz

100%|█████████████████████| 4.25k/4.25k [00:01<00:00, 3.05kB/s]

업로드된 Package는 TestPyPI에서 볼 수 있습니다.  (예시) https://test.pypi.org/project/example-pkg-YOUR-USERNAME-HERE

새로 업로드 된 Package 설치하기

pip 를 통해 새로운 Package를 설치하고 동작하는지 검증할 수 있습니다. 새로운 virutalenv를 만들고 TestPyPI에서 올린 Package를 설치하세요.

python3 -m pip install --index-urlhttps://test.pypi.org/simple/ --no-deps example-pkg-YOUR-USERNAME-HERE

Package name에 사용자 이름을 지정하십시오!

pip는 TestPyPI에서 해당 Package를 가져와서 아래처럼 output 을 보여줍니다.

Collecting example-pkg-YOUR-USERNAME-HERE

Downloading https://test-files.pythonhosted.org/packages/.../example-pkg-YOUR-USERNAME-HERE-0.0.1-py3-none-any.whl

Installing collected packages: example-pkg-YOUR-USERNAME-HERE

Successfully installed example-pkg-YOUR-USERNAME-HERE-0.0.1

Note: 이 예제에서는 --index-url flag를 사용하였는데 이는 live PyPI 대신 TestPyPI 주소를 명시해준 것입니다.추가적으로, --no-deps 도 명시해줬습니다.TestPyPI package 들은 live PyPI에 있는 Package 들과 같지않기 때문에, 종속성 있는 package 설치가 실패할 수도 있고,원하는 Package가 아닌 엉뚱한 Package가 설치될 수도 있습니다.예제 Package 는 종속성이 없지만 TestPyPI를 사용할 때는 종속성이 없게 만드는 것이 좋습니다.

Package 를 import 하면서 제대로 설치되었는지 테스트 해볼 수 있습니다. Python Interpreter를 실행해주세요.(가상환경에서 실행하는 것을 잊지마세요.)

Python

그리고 interpreter shell 에서 Package 를 import 하세요.

>>> import example_pkg
반응형