파이썬 프로젝트 시작하기 - Setuptools

이 글은 Setuptools 를 사용하여 프로젝트의 틀을 구성하는 방법에 관한 것으로, Virtualenv 와 Distutils 에 관한 내용을 담고 있는 다음 포스트에 이어지는 세 번째 글입니다.

Setuptools

지난 글에서 파이썬의 표준 적인 설치 관행에 대해 살펴봤습니다. 기본적인 setup.py 파일도 제작했고요. 오늘은 Distutils 을 떠나, Setuptools 로 작업을 확장합니다. 지금 소개해 드리는 관행이 실제로 저희가 사용하고 있는 것인데 다음과 같은 기능들을 setup.py 에 추가하게 됩니다.

  • 모듈 의존성 관리 — install_requires
  • 비공개 모듈 설치 — dependency_links
  • 콘솔 스크립트 설치 — entry_points
  • 개발 모드 디플로이 — setup.py develop

전과 마찬가지로 Flowdas Books 라는 장고 애플리케이션을 사용해서 설명 드리겠습니다.

setup.py

Setuptools 를 사용하도록 수정된 setup.py 은 이렇게 됩니다.

from setuptools import setup, find_packages

setup_requires = [
    ]

install_requires = [
    'django==1.6b4',
    'markdown==2.3.1',
    'pyyaml==3.10',
    'pillow==2.1.0',
    'lxml==3.2.3',
    'beautifulsoup4==4.3.1',
    ]

dependency_links = [
    'git+https://github.com/django/django.git@stable/1.6.x#egg=Django-1.6b4',
    ]

setup(
    name='Flowdas-Books',
    version='0.1',
    description='Flowdas Books',
    author='Flowdas',
    author_email='spammustdie@flowdas.com',
    packages=find_packages(),
    install_requires=install_requires,
    setup_requires=setup_requires,
    dependency_links=dependency_links,
    scripts=['manage.py'],
    entry_points={
        'console_scripts': [
            'publish = flowdas.books.script:main',
            'scan = flowdas.books.script:main',
            'update = flowdas.books.script:main',
            ],
        },
    )

setup(), find_packages()

Setuptools 에서 제공하는 두 개의 함수 setup()find_packages() 를 사용합니다. setup() 은 표준 라이브러리에 포함된 Distutils 의 setup() 을 대체하는 것입니다. Distutils 의 것에 비해 더 다양한 옵션들을 처리합니다.

find_packages()

예전에는 packages 옵션에 패키지 이름들을 일일이 적어주었습니다. 최상단 패키지만 적어주어야 한다면 크게 문제될 것이 없지만, 하위 패키지들을 많이 만드는 방식의 프로그래밍을 하시는 분들은 영 불편해합니다. Setuptools 가 제공하는 find_packages() 함수는 폴더를 뒤져서 패키지들의 목록을 만들어 줍니다. 혹 뒤져야 할 폴더가 다른 곳에 있거나, 포함시키지 말아야 할 패키지가 있다면 인자로 지정할 수 있습니다.

install_requires

가장 중요한 부분은 이 프로젝트가 사용하는 패키지들을 지정하는 것인데, install_requires 옵션을 사용합니다. 전부 6개의 패키지를 지정했는데, 모두 django==1.6b4 와 같이 구체적인 버전을 지정했습니다. 처음부터 버전을 지정하지는 않고, 어느 정도 호환성 확인이 된 후에 버전을 확인하여 고정하게 됩니다. 버전 확인에는 pip freeze 명령을 사용하면 됩니다. 패키지 이름의 대소문자는 중요하지 않습니다.

setup_requires

install_requires 에 지정하는 것은 프로젝트를 위해 필요한 패키지들인데, 때로 setup.py 자신을 위해 필요한 패키지가 있을 수 있습니다. 이런 패키지들은 setup_requires 옵션을 사용하여 지정합니다. 이런 경우에 해당하는 패키지의 예는 setuptools_git 가 있습니다만, 저희는 사용하지 않기 때문에 자리만 마련하고 비워둡니다.

콘솔 스크립트

Setuptools 는 플랫폼 별로 콘솔 스크립트를 설치할 수 있습니다. entry_points 옵션에 console_scripts 키를 사용하여 지정하면 되는데, 이 예에서는 세 개의 콘솔 스크립트 publish, scan, update 를 설치하는데, 셋 모두 flowdas.books.script 모듈의 main 함수가 호출되게 됩니다. 이 경우는 main 함수가 어떤 명령이 호출되었는지 판단하도록 구성한 것인데, 보통은 각 콘솔 스크립트 별로 별도의 모듈이나 함수를 지정합니다.

장고에서는 애플리케이션이 manage.py 의 명령어를 추가하도록 지원합니다. 위의 세 명령어도 이런 방식으로 추가된 manage.py 의 명령어 입니다. flowdas.books.script 모듈의 main 함수는 manage.py 를 실행하도록 구성된 것입니다. flowdas.books.script 모듈은 이렇게 구성됩니다.

import os
import sys

def main():
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
    from django.core.management import execute_from_command_line
    argv = ['manage.py']
    argv.append(os.path.basename(sys.argv[0]))
    argv.extend(sys.argv[1:])
    execute_from_command_line(argv)

이렇게 설치하는 콘솔 스크립트는, 앞서 scripts 옵션으로 설치한 manage.py 와는 다릅니다. 배포 판에 포함된 파일을 복사하는 것이 아니라, 설치 시에 Setuptools 가 콘솔 스크립트를 만들게 됩니다. 이 방법이 가장 쓸모 있는 곳은 윈도우즈 환경입니다. 그 곳에서는 publish.exe, scan.exe, update.exe 파일이 만들어집니다.

한편 장고 프로젝트에서도 콘솔 스크립트가 유용한 경우들이 많습니다. 대표적인 경우는 crontab 에 등록할 스크립트가 필요할 경우인데, Flowdas Books 의 scan 이 여기에 해당합니다. 가상 환경에서 만들어진 콘솔 스크립트를 가상환경 밖에서 실행하더라도, 가상 환경 내에서 실행되게 됩니다. 정확히 저희가 원하는 것이기도 합니다.

boot 스크립트

지금까지 setup.py 파일의 내용과, 이전 글에서 소개한 MANIFEST.in 파일을 살펴봤습니다. 마지막으로 저희가 항상 프로젝트에 포함시키는 두 개의 파일이 있는데, 저희는 boot 스크립트라고 부릅니다. 두 파일을 MANIFEST.in에 추가하는 것은 여러분의 몫입니다.

boot.sh 파일은 이렇습니다.

#!/bin/sh
python virtualenv.py venv
venv/bin/python setup.py develop

boot.bat 파일은 이렇습니다.

python virtualenv.py venv
venv\Scripts\python setup.py develop

이 파일의 주 역할은 프로젝트를 최초 설치할 때 실행하는 것입니다. 다시 말해 git clone 하자마자 실행하는 것입니다. 그렇게 하면 venv 디렉터리에 가상환경이 만들어지고, 그 환경에 setup.py 를 실행해서 설치하게 됩니다. install 대신에 develop 을 사용했는데, 이렇게 하면 프로젝트의 패키지 파일들은 venv 밑으로 복사되지 않고 제자리에 남아있게 됩니다. 대신에 Python Path 가 프로젝트 디렉터리들을 가리키게 되지요. 개발 도중 파일을 수정해도 즉시 반영되는 장점이 있습니다.

실제 실행환경에서도 같은 스크립트를 사용해도 상관없고, 저희는 그렇게 하고 있습니다. 지금은 boot 파일을 두 개만 준비했지만, 더 많은 개수가 준비되기도 합니다. 파이썬 패키지가 아닌 것들이 사전 설치되어야 하는 경우도 있습니다. 가령 lxml 패키지는 libxml2 가 설치되어 있어야 합니다. 이런 것들을 설치하는 명령은 boot 파일에 추가하는데, 플랫폼마다 좀 달라질 수 있기 때문에 여러 개의 스크립트를 만들기도 합니다.

폴더 구조

이제 boot 파일을 실행한 직후의 프로젝트 폴더는 이렇게 구성됩니다. venv 폴더를 제외한 모든 파일은 코드 저장소에 들어가 있는 파일들 입니다. 중간에 생성되는 파일들과 지금까지 언급하지 않은 파일들은 표시하지 않았습니다.

~/works/PROJECT/
    boot.bat
    boot.sh
    setup.py
    MANIFEST.in
    virtualenv.py
    setuptools-x.x.x.tar.gz
    pip-x.x.x.tar.gz
    venv/

원래는 장고를 언급하지 않고 쓰려고 했는데, 쓰다 보니 두 편으로 나누는 것이 귀찮아서 그냥 갑니다. 장고를 사용하지 않는 분들은 약간 불편할 수 있겠으나, 대부분 걸러서 보실 수 있으리라 봅니다. 별도의 글에서 다룰 문서화와 테스트는 일부러 모두 제거했습니다. 나머지 이야기들을 할 기회가 있겠지요.