Python Package Index(PyPI)와의 연동 기초

PyPI의 개념과 역할

Python Package Index(PyPI)는 파이썬 패키지를 업로드하고 배포할 수 있는 표준 중앙 저장소 역할을 한다. ROS2 Humble 환경에서 파이썬 기반의 기능을 개발하고, 이를 전 세계 사용자들과 공유하려면 PyPI를 적극적으로 활용할 수 있다. 예를 들어, 자율주행 로봇에서 특정 알고리즘을 파이썬 라이브러리 형태로 구축하였다면, 해당 라이브러리를 PyPI로 배포해 다른 ROS2 개발자들이 손쉽게 가져다 쓰도록 할 수 있다.

PyPI를 활용하면 다음과 같은 장점을 얻을 수 있다.

  • 간단한 설치: 파이썬 환경에서 $pip$ 명령만으로 패키지를 빠르게 설치 가능

  • 표준화된 배포: 많은 파이썬 사용자 커뮤니티가 이미 정립해 둔 표준 배포 가이드를 그대로 활용 가능

  • 종속성 관리: 요구되는 종속 패키지들을 자동으로 설치하게 하여 일관성 있는 개발환경을 구성 가능

기본 준비사항

PyPI 배포를 위해서는 다음과 같은 준비가 필요하다.

PyPI 계정: PyPI에 패키지를 업로드하려면 먼저 PyPI 공식 사이트arrow-up-right에서 계정을 만들어야 한다.

프로젝트 구조: ROS2 노드라 하더라도, 순수 파이썬 패키지 구조를 준수해야 PyPI로 업로드할 수 있다. 아래는 일반적인 파이썬 패키지 예시 구조이다.

my_ros2_python_pkg/
├── my_ros2_python_pkg
│   ├── __init__.py
│   └── main.py
├── tests
│   └── test_main.py
├── setup.py
└── README.md

필수 메타데이터: $setup.py$ 또는 $pyproject.toml$ 등에 들어가는 패키지 이름, 버전, 라이선스, 저자 정보 등을 정확히 기입해야 한다.

ROS2 패키지와 PyPI 패키지의 차이점

ROS2 패키지를 만들 때는 $package.xml$과 같은 ROS2 전용 설정 파일이 필요하다. 그러나 PyPI 배포를 위해서는 $setup.py$ 혹은 $pyproject.toml$의 설정 파일이 필수다. ROS2 Humble 패키지를 PyPI로 배포하려면 결국 두 가지 설정 파일 모두를 함께 관리하는 경우가 많다.

예시:

두 파일의 역할을 정리하면 아래와 같다.

  • package.xml: ROS2 빌드 툴(예: colcon)에서 사용하는 ROS2 패키지 메타데이터

  • setup.py: 파이썬 배포(예: PyPI)를 위한 패키지 메타데이터

PyPI에서 관리되는 버전 규칙

PyPI에 업로드되는 패키지는 버전 관리가 매우 중요하다. 일반적으로 파이썬 세계에서는 SemVer(Semantic Versioning)arrow-up-right 방식이 널리 사용된다. 버전 표시는 주로 MAJOR.MINOR.PATCH 형태로 구성하며, 아래와 같은 의미를 가진다.

  • MAJOR: 호환이 크게 달라지는 수준의 대규모 변경 시 증가

  • MINOR: 새로운 기능이 추가되었으나 이전 버전과 호환성을 어느 정도 유지할 때 증가

  • PATCH: 주로 버그 수정이나 호환성 문제가 없는 사소한 변경일 때 증가

예컨대 $0.1.0$에서 $0.2.0$으로 바뀌었다면, 새로운 기능이 포함되었음을 의미한다. ROS2의 빌드나 배포 환경에서도 이런 버전 규칙을 철저히 지켜야 사용자들에게 혼란을 주지 않는다.

PyPI 업로드 방식 개요

PyPI에 업로드하기 위해서는 일반적으로 아래 과정을 거친다:

패키지 소스 준비: $setup.py$(또는 $pyproject.toml$)를 갖춘 상태에서, $README.md$ 등 문서 파일과 함께 프로젝트 디렉터리에 놓는다.

빌드 및 배포용 파일 생성: 다음과 같이 setuptools 혹은 build 모듈을 사용해 패키지를 빌드하고 .whl(wheel 파일) 및 .tar.gz(소스 배포용 아카이브) 파일을 생성한다.

이 명령을 실행하면 dist/ 디렉터리에 wheel 파일과 tar.gz 파일이 생긴다.

테스트PyPI 업로드: 정식 PyPI 업로드 전, TestPyPIarrow-up-right라는 테스트용 PyPI에 패키지를 올려 검증하는 과정을 거치는 것이 좋다.

정식 PyPI 업로드: 테스트를 마친 뒤 문제 없으면 정식 PyPI에 업로드한다.

아래는 이 과정을 간단히 나타낸 플로차트 예시이다.

spinner

ROS2 환경 내에서의 PyPI 패키지 활용

ROS2 Humble 환경에서 PyPI 패키지를 활용하는 방법은 크게 다음과 같다.

python3 -m pip install을 통한 설치: 단순히 $pip$ 명령으로 패키지를 설치하고, Python import 방식으로 모듈을 불러서 ROS2 노드에서 사용한다.

colcon build와의 연동: 패키지 종속성을 $setup.py$에 명시해 두면, ROS2의 빌드 툴 colcon에서 해당 패키지 설치 과정을 트리거할 수도 있다.

활용 예시:

PyPI 보안 토큰 관리와 자동 배포

PyPI에 업로드하기 위해서는 사용자의 인증 정보(계정, 패스워드 또는 API 토큰)가 필요하다. 이를 매번 터미널에 입력할 수도 있지만, CI/CD 환경 등에서 자동 배포를 구현하려면 다음과 같은 방법을 고려해볼 수 있다.

PyPI API 토큰 발급: PyPI 계정 설정(Security 탭)에서 프로젝트별 API 토큰을 발급받을 수 있다. 이 토큰을 발급받으면, 계정 비밀번호 대신 토큰을 이용해 업로드할 수 있다.

  • 예: $pypi-AgENdGVzdC5... 형태의 긴 문자열

환경 변수로 관리: 배포 과정에서 민감 정보를 노출하지 않기 위해, CI 환경(예: GitHub Actions, GitLab CI/CD 등)에서 발급받은 PyPI 토큰을 암호화된 방식(Secrets)으로 저장한다. 예를 들어 GitHub Actions에서는 PYPI_TOKEN 같은 이름으로 시크릿을 등록하고, 워크플로에서 이를 참조한다.

twine 설정: $twine upload dist/* 명령을 실행할 때 환경변수를 활용하거나, $~/.pypirc$ 파일에 토큰을 저장해 인증을 수행한다.

자동화 예시(GitHub Actions): 아래는 GitHub Actions를 활용해 PR이 머지될 때마다 PyPI로 자동 배포하는 예시이다.

pyproject.toml vs setup.py

최근 파이썬 패키징 생태계에서는 pyproject.toml 파일을 활용하는 방식이 권장되고 있다.

  • pyproject.toml: 빌드 시스템 관련 설정(build-system, project 섹션 등)을 기술한다.

  • setup.py: 기존 방식으로, 패키지의 메타데이터와 스크립트를 포함해 빌드 시 동적으로 처리하는 로직을 담을 수 있다.

ROS2 패키지를 PyPI에 배포할 때도 pyproject.toml 방식이 점차 보편화되는 추세이므로, 신규 프로젝트라면 다음과 같은 스켈레톤을 고려해볼 수 있다.

기존 setup.py 파일 없이도, 이 pyproject.toml 만으로 패키징이 가능해진다. 단, ROS2 패키지 구조와 충돌되지 않도록, ROS2 관련 메타데이터(package.xml, CMakeLists.txt 등)는 별도로 유지해야 한다.

테스트PyPI 환경에서의 종속성 검증

PyPI에 바로 업로드하기 전, TestPyPI를 이용해 패키지를 배포하고 설치 테스트를 수행하는 것이 좋다. 특히, ROS2와의 종속성(예: rclpy 버전 등)을 확인해야 한다면 TestPyPI에 업로드 후 테스트용 가상환경에서 실제 설치 시도를 해보면 된다.

  • --index-url https://test.pypi.org/simple/로 TestPyPI에서 우선 패키지를 찾도록 설정

  • --extra-index-url https://pypi.org/simple로, TestPyPI에 없는 종속 패키지는 정식 PyPI에서 가져오도록 설정

ROS2 의존 라이브러리도 제대로 가져와서 충돌 없이 동작하는지 확인할 수 있다.

Wheel 파일과 플랫폼 호환성

파이썬 패키지에서 확장 모듈(C/C++로 작성된 .so, .dll, .pyd 등)을 포함하거나, 특정 플랫폼(ARM, x86 등)에 한정된 로직을 포함하는 경우라면 Wheel 파일 빌드와 플랫폼 호환성 문제가 발생할 수 있다.

  • pure-python 패키지: Wheel 파일 이름에 py3-none-any.whl 같은 형태로 표시된다. 어떠한 OS/아키텍처에도 호환되는 순수 파이썬 패키지라는 뜻이다.

  • C 확장 모듈 포함 시: 예) my_pkg-0.1.0-cp39-cp39-linux_x86_64.whl 형태로, 파이썬 버전과 시스템 아키텍처 등이 Wheel 파일명에 표시된다.

ROS2에서 rclpy 확장을 사용하는 경우, 이를 PyPI에 올릴 때 특정 OS(Linux, Windows, macOS 등)마다 별도의 Wheel 파일을 만들어 배포해야 할 수도 있다. CI/CD 시스템에서 다양한 OS에 대해 Wheel을 빌드하고 twine upload dist/*.whl 명령으로 여러 파일을 동시에 업로드하는 식이다.

PyPI 배포시 유의사항

  1. 버전 충돌 이미 등록된 버전으로는 다시 업로드가 불가능하므로, $setup.py$나 $pyproject.toml$의 버전을 배포할 때마다 올바르게 업데이트해야 한다.

  2. 라이선스 명시 ROS2는 Apache License 2.0을 채택하고 있으나, 종속 라이브러리에 따라 라이선스가 달라질 수 있다. 종속성 목록을 꼼꼼히 확인하고 최종 배포물의 라이선스 호환성을 체크해야 한다.

  3. 코드 서명 (선택 사항) 대규모 프로젝트의 경우 배포 파일에 대한 서명(.asc 파일)을 추가해서 배포할 수도 있다.

  4. 문서화 $README.md$ 뿐만 아니라, Sphinx 등을 이용해 Read the Docs나 GitHub Pages 등으로 API 문서를 제공하면 사용자 접근성을 높일 수 있다.

사설 PyPI 서버(DevPi) 활용

사내 혹은 특정 네트워크 내부에서만 접근 가능한 파이썬 패키지 저장소를 운용하고자 할 때는 사설 PyPI 서버를 세팅하는 방법을 고려할 수 있다. 대표적인 예시로 DevPi, Artifactory, Nexus 등이 있다. ROS2 Humble 환경에서도 다음과 같은 시나리오를 통해 사설 PyPI 서버를 유용하게 사용할 수 있다.

  1. 내부 전용 패키지 공유 사내 알고리즘, 회사 고유 로직, 또는 고객 전용 코드 등 외부에 공개하고 싶지 않은 파이썬 모듈들을 사설 PyPI 서버에 올려서 조직 내에서만 공유할 수 있다.

  2. 버전 고정 및 검증 불특정 다수에게 공개되는 PyPI보다는 사설 저장소에서 버전을 고정, 검증하며 내부 CI 파이프라인과 함께 관리하기 쉽다.

  3. ROS2 배포 파이프라인 연계 DevPi와 같은 사설 PyPI 서버를 GitHub Actions, GitLab CI/CD, Jenkins 등과 연동해, ROS2 패키지 빌드 성공 시 자동 업로드하고 개발팀이 즉시 설치·테스트할 수 있게 할 수 있다.

개인 서버에 DevPi를 간단히 세팅해보려면 다음과 같은 방식으로 진행할 수 있다.

서버가 동작한 뒤에는 devpi-client를 이용해 저장소를 구성하고, $twine upload 대신 devpi upload 등을 활용할 수 있다. 사설 PyPI이므로, 방화벽 설정과 사용자 권한 관리를 사전에 철저히 진행해야 한다.

PyPI 태그 활용

PyPI에서는 패키지를 업로드할 때 어떤 태그(Classifiers)를 달아서 검색 및 분류를 용이하게 할 수 있다. ROS2 같은 로봇 프레임워크나 특정 OS/하드웨어 환경을 명시해 주면, 사용자들이 패키지 호환성을 빠르게 파악할 수 있다.

  • Development Status: 알파, 베타, 프로덕션(Production/Stable) 등 패키지 성숙도를 나타내는 태그

  • Intended Audience: 패키지의 주요 타깃(개발자, 교육용, 산업용 등)

  • Operating System: 리눅스, 윈도우, 맥OS 등 호환 OS

  • Topic: 로보틱스, ROS, IoT 등

예컨대, classifiers 항목에 "Topic :: Scientific/Engineering :: Robotics"를 추가해두면 PyPI 검색 시 ROS2나 로보틱스 관련 키워드를 입력하는 사용자들에게 노출이 좋아진다.

로컬 테스트와 디버깅 방법

PyPI 업로드 전에 로컬에서 $pip install . 명령으로 설치 테스트를 진행하는 방법이 매우 유용하다.

로컬 환경에서 wheel/tar.gz 생성:

dist/ 디렉터리에 wheel 파일과 tar.gz가 생성된다.

로컬 설치:

이렇게 설치 후, 설치된 라이브러리가 잘 import 되고, 의존성 충돌이 없는지 확인한다. ROS2 노드에서 실제 동작하는지도 테스트한다.

Uninstall, Reinstall 루프:

버전을 자주 수정하거나, 기능 추가·버그 수정 후 반복 테스트할 때 $pip uninstall my_ros2_python_pkg && pip install dist/*.whl 과정을 여러 번 반복하면서 안정화시킬 수 있다.

유지보수 전략

ROS2 패키지를 PyPI로 배포하고 나면, 버그나 신규 기능 추가 시마다 꾸준히 버전을 갱신해야 한다. 아래와 같은 전략을 미리 수립해 두면 혼선을 줄일 수 있다.

배포 채널 분리:

예: 안정 버전(stable)과 개발 버전(dev)을 따로 관리. 필요하다면 main 브랜치와 develop 브랜치에 각각 CI를 붙여 TestPyPI와 PyPI로 구분 배포.

릴리즈 노트(Release Notes) 관리:

매 버전 업데이트 시 변경 내용을 문서화하여 사용자들에게 신속히 전달.

ROS2 Humble 외 다른 ROS2 디스트로 지원 여부:

Foxy, Galactic, Rolling 등 다른 버전의 ROS2와 호환성을 계속 유지하려면, 그에 맞춘 테스트 파이프라인도 운영해야 한다.

pyproject.toml 기반 멀티 플랫폼 빌드

ROS2 Humble 기반 패키지를 여러 플랫폼(리눅스, 윈도우, 맥 등)으로 동시에 빌드하여 PyPI에 업로드하려면, GitHub Actions와 같은 CI 환경에서 OS별로 워크플로를 구성하면 된다. 예:

이런 멀티 플랫폼 빌드 설정을 통해, 각 플랫폼별로 빌드된 .whl 파일이 PyPI에 업로드되어 사용자들이 손쉽게 설치할 수 있게 된다.

Last updated