본문 바로가기
IT/python

[python] 패키지관리

by 통섭이 2023. 8. 31.

python 패키지 관리 툴들의 발전

disutils 와 PyPI(인덱스 서버)의 등장

  • 과거에는 개발자들을 위한 패키지 저장소는 커녕 패키지를 검색하기도 어려서 커뮤니티를 사용해서 공유했다.
  • 문제는 설치하는 방법이 정해지지 않다보니 작성자가 사용법을 명시해서 공유했다.
  • 1998년, 이런 불편함을 해결하고자, 코드를 패키징하고 빌드할 수 있는 disutils 가 등장.
    • 패키지의 메타데이터를 담은 파이썬 스크립트를 사용하는 setup.py 방식 제공
    • 패키지 배포, 설치하는 표준화된 방법 제공
      from disutils.core import setup
      setup(name='test', version='1.0', py_modules=['test'],)
  • 이렇게 하여 개발자는 쉽게 패키지를 공유 가능한 형태로 만들 수 있게 되었고, 파이썬 1.6에 표준 라이브러리가 됨.
  • 그리고 개발된 패키지들이 한곳에 모인 PyPI(Python Packaging Index) 인덱스 서버가 등장.
  • 하지만, disutils 만으로는 PyPI에서 다운도 받을 수 없고, 의존성 처리도 할수 없는, 단순히 설치가 전부라 제약이 있었음. 그래서 setuptools 가 등장.
  • disutils 는 3.10부터 deprecate 되어, 3.12 에서 삭제

setuptools

  • distuils 기능에 더해 PyPI에 패키지를 업로드 하거나, 패키지 테스트 수행하는 등 다양한 기능도 제공 (다만 업로드는 twine, 테스트는 unittest, pytest 가 대체). 요즘은 본연의 패키징 기능에 집중하는 도구가 됨.
  • python 프로젝트를 배포하기 위해서는 패키지로 만들어야 하는데, setuptoolssetup.py 사용하면 유용하니 이를 사용하는 방법을 알아본다.
my_project
├── myproject
│   ├── __init__.py 
│   └── example.py
└── README.md
  • 만약 위와 같은 패키지를 외부에서 사용할때는 from myproject import example 과 같은 식으로 사용

    • 이때, myproject가 동일한 경로에 없다면 에러 no module named 'example' 에러 발생
  • 환경 변수 PYTHONPATH 나 sys.path 를 이용해 경로 맞춰 줄 수도 있지만, 이것은 다른 환경에서 에러 발생하니 권장하지 않는다

  • 이를 해결하기 위한 방법이 setup.py + setuptools + pip 을 사용하는 방법!!

  • setup.py

from setuptools import setup, find_packages

setup(
    name='myproject', # pip 에서 사용하는 패키지 이름. 즉, pip install myproject 가 됨
    version='0.1.0', # PyPI에 배포할때에도 사용하는 버전
    packages=find_packages(include=['myproject', 'myproject.*']), # setuptools 에 있는 find_packages 모듈로 이 패키지에 포함하거나 제외할 파일 명시
    install_reuqires=[ # dependencies는 보통 `requirements.txt` 나 `environment.yml` 로 관리하지만, setup.py 에서는 이렇게 사용
        'numpy',
        'pandas==0.23.3'
    ],
    extras_require={ # 특정 상황에서만 설치하고 싶은 경우 이렇게 사용
        'interactive': ['matplotlib>=2.2.0'],
    }
)
  • setup 안에 들어갈 수 있는 정보는 이 외에도 많기 때문에 더 자세한 내용은 문서를 참고하시기 바란다
  • 이렇게 작성된 setup.py 를 myproject와 동일한 위치에 두고 아래처럼 실행하여 설치
    • 여기서 pip 은 패키지를 설치하고 관리하는 도구로, easy_install 이 가지고 있던 패키지 관리 측면 문제들을 해결하면서 git 에서 패키지를 바로 설치할 수 있게하는 등의 부가 기능 제공. py 3.4 부터 디폴트 패키지 인스톨러
    • 참고로, pip은 패키지 설치 시 소스를 직접 빌드하는 설치 방식만 제공하지만, 이로 인해 C-extension을 사용하는 패키지의 경우 빌드할때 컴파일러 없으면 설치 불가능. 그래서 미리 플랫폼에 맞추어 빌드된 바이너르 포맷 패키지를 설치하는 방식을 지원하는데, 이것이 현재도 사용되는 wheel 이라는 zip 파일 형태의 바이너리 패키지 포맷.
pip install -e .                    # install_requires만 설치
pip install -e .[interactive]        # extras_require도 같이 설치!
pip install -e myproject[interactive] # extras_require도 같이 설치!
  • 이렇게 하면 위에서 하려고 했던, from myproject import example 을 사용할 수 있게 된다!!
  • 여기서 단점은 setup.py 가 setuptools 에 의존적이라는 것이다.
    • 이것이 문제인 이유는 setuptools 는 파이썬 표준 라이브러리가 아니고, 사람들은 명시된 규칙을 따라 새로운 패키지 빌드 시스템 만들도록 권장되고 있음.
      • 그런데, setup.py 는 setuptools 가 필수적. 만약 다른 빌드 툴 사용하려면 setup.py 에 명시해야 함. 그런데, setup.py 를 파싱하기 위해서는 setuptools를 사용. 즉 다른걸 사용해도 setuptools 가 필요...
      • 또, 사용하려는 setuptools 의 버전이 달라져도 setup.py에 명시해야 하는데, 이 정보를 파싱하는게 미리 설치된 setuptools... 상충됨
  • 이를 해결하기 위한 특정 빌드 시스템에 종속되지 않는 선언적인 설정 파일이 pyproject.toml!

TOML 등장

  • 파이썬 패키지를 어떻게 빌드하는지, 어떤 빌드 시스템을 사용해야 하는지 명시된 파일.
  • 물론, setuptools 와 같이 사용할 수 있고, 그렇게 작성된 .toml 파일의 예시는 아래와 같다.
[build-system]  
requires = [“setuptools”]  
build-backend = “setuptools.build_meta”

[project]  
name = “cool_project”  
version = “1.0.0”
  • project : name, readme, description, authors, dependencies 등을 명시
  • 다른 tool 사용하려면 아래와 같이 가능
[build-system] 
requires = ["flit_core >=2,<4"] 
build-backend = "flit_core.buildapi"

.

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
  • 여기서는 패키지 빌드뿐 아니라, pytest, mypy, linter 등 다양한 툴들의 설정 파일과 project metadata 를 저장
  • 원래는 빌드툴 specific 하게 메타데이터를 작성해야 했다. (setuptools - setup.cfg, Poetry - project.toml)
  • 하지만 이제는 setuptools 가 PEP-621 를 따르기 때문에, flit 과 같은 방식으로 .toml 파일을 작성할 수 있고, Poetry 도 PEP-621 을 따르기 위한 로드맵 이 있기 때문에, 빌드 시 .toml 은 더욱 사실상 project metadata 를 기술하는 표준 방식이 될 것이다.
  • [project] 테이블에 들어가는 자세한 내용은 문서 참조하시기 바란다.
  • 이외에 setuptools 특화 설정들은 [tool.setuptools] 아래에 명시하면 된다.
  • 마찬가지로, pytest 특화 설정들은 [tool.pytest], pylint 는 [tool.pylint] , mypy 는 [tool.mypy] 에 명시하면 된다. 이렇게 하면 더이상 mypy.ini 파일에 설정 값들을 쓸 필요 없어진다.
  • PEP-621 의 setuptools 관련 설정 방법들은 더 보려면 문서 를 참조하시기 바란다.

사용 후기

해당 내용을 다시 정리하게된 이유는 회사에서 한 패키지를 쓰는데, 이 패키지의 특정 부분을 수정하고 싶어서였다. 하여 특정 부분의 코드를 수정하고, 해당 내용을 사내 private repository에 올리고 pip install git+http://company.git.repo 인스톨해서 사용해보았다. 코드를 작성하고, toml 파일에 [build-system] 은 setuptools 를 사용했고, [project] 에는 패키지 이름과 원래 패키지의 Dependencies 정보를 복사해서 나만의 패키지로 만들 수 있었다. 아직 다양한 기능은 사용해보지 않았지만, 매우 쉽게 패키지를 관리 할 수 있겠다는 생각이다.

참고 https://ryanking13.github.io/2021/07/11/python-packaging.html

댓글