PyPIデビューしたい人の為のPyPI登録の手順


はじめに

最近PyPIデビューを果たしました。
そこで同じ用にPyPIデビューを考えている人の為に登録手順を書きます。

PyPIってなに? おいしいの?

Python Package Indexの略らしいです。
Pythonパッケージを管理するためのサービスで、誰でもパッケージを登録できます。
ここに登録されたパッケージは pip installでインストール出来る様になります。
ちなみにパイピーアイって読むらしいです。

パッケージの準備

まずは登録するパッケージを準備します。
今回は例として「pypipkg」というパッケージを作成した事にします。
ファイル構成はこんな感じです。
pypipkgディレクトリ直下にsetup.py等、PyPIの登録に必要な情報を用意し、pypipkgのソースのディレクトリも置きます。

pypipkg $ tree
├── MANIFEST.in
├── README.rst
├── pypipkg
│   ├── __init__.py
│   ├── dependency.py
│   ├── scripts
│   │   ├── __init__.py
│   │   └── command.py
│   └── verify.py
├── requirements.txt
└── setup.py

初回で用意する構成は上記のような感じですが。
後ほど、登録作業を行う段階でpipに必要なディレクトリが追加されます。

  • dist : パッケージのgzipファイルが格納される
  • pypipkg.egg-info : setup.pyの情報を元に作成される登録に必要な情報
pypipkg $ tree
├── MANIFEST.in
├── README.rst
├── dist
│   ├── pypipkg-1.0.0.tar.gz
│   ├── pypipkg-1.0.1.tar.gz
│   ├── pypipkg-1.0.2.tar.gz
│   ├── pypipkg-1.0.3.tar.gz
│   └── pypipkg-1.0.4.tar.gz
├── pypipkg
├── pypipkg.egg-info
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── entry_points.txt
│   ├── requires.txt
│   └── top_level.txt
├── requirements.txt
└── setup.py

setup.pyの作成

PyPi登録に重要なのがsetup.pyです。
このsetup.pyの情報を元にパッケージとして認識させ、登録する事ができます。
たぶん、PyPI登録でsetup.pyの作成が一番面倒くさいです。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
import os

from setuptools import setup, find_packages

try:
    with open('README.rst') as f:
        readme = f.read()
except IOError:
    readme = ''

def _requires_from_file(filename):
    return open(filename).read().splitlines()

# version
here = os.path.dirname(os.path.abspath(__file__))
version = next((line.split('=')[1].strip().replace("'", '')
                for line in open(os.path.join(here,
                                              'pypipkg',
                                              '__init__.py'))
                if line.startswith('__version__ = ')),
               '0.0.dev0')

setup(
    name="pypipkg",
    version=version,
    url='https://github.com/user/pypipkg',
    author='kinpira',
    author_email='[email protected]',
    maintainer='kinpira',
    maintainer_email='[email protected]',
    description='Package Dependency: Validates package requirements',
    long_description=readme,
    packages=find_packages(),
    install_requires=_requires_from_file('requirements.txt'),
    license="MIT",
    classifiers=[
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',
        'Programming Language :: Python :: 3.4',
        'License :: OSI Approved :: MIT License',
    ],
    entry_points="""
      # -*- Entry points: -*-
      [console_scripts]
      pkgdep = pypipkg.scripts.command:main
    """,
)

ぱっと見、いろいろ難しい事をやっている様に感じますが、重要なのはsetup()の中です。
ここに、各設定項目書いてあげればOKです。
上のsetup.pyの例で指定している項目が以下になります。

  • name : パッケージ名
  • version : リリースのバージョン指定 ( __ init__.pyに指定している)
  • url: パッケージのホームページ
  • author: パッケージの作者
  • author_email: 作者のemail
  • maintainer: メンテナンス担当者
  • maintainer_email: メンテナンス担当者のemail
  • description: パッケージについての簡潔な説明概要
  • long_description: パッケージについての詳細な説明概要 (READMEを読み込ませている)
  • packages: パッケージとなるディレクトリを指定する
    • (find_packagesで __ init__.pyが存在するディレクトリを検索して自動でパッケージ指定する)
    • パッケージから外す内容を指定もできます find_packages(exclude=["*.pyc"])
  • install_requires: 依存パッケージを指定(requirements.txtで指定)
    • ↓requirements.txtじゃなくても、直接指定もできます
  install_requires=[
        "hoge",
  ],
  • license: パッケージのライセンス
    • 一覧を参照したらライセンスがいっぱいあるけど、とりあえずMITはすごい緩いオープンソースのライセンスらしい (ライセンス一覧)

【wiki: MIT】

要約すると、MIT Licenseとは次のようなライセンスである。
1. このソフトウェアを誰でも無償で無制限に扱って良い。ただし、著作権表示および本許諾表示をソフトウェアのすべての複製または重要な部分に記載しなければならない。
2. 作者または著作権者は、ソフトウェアに関してなんら責任を負わない。

  • classifiers : 関連するカテゴリ

  • entry_points : パッケージの機能を提供するコマンドを作成する

    • 書き方: コマンド名 = スクリプトのpath : 実行する関数

これらの情報はpythonのドキュメントでも説明されています。

MANIFEST.in作成

setup.pyを作成したら、今回はrequirements.txtを指定する方式をとっているので、「MANIFEST.in」ファイルを作成します。
MANIFEST.in はパッケージに対象のpythonディレクトリ内に含まれないファイルを意図的に含ませたい場合に指定する事で、指定したファイルをパッケージに含める事が出来ます。

ちなみに、今回のようにrequirements.txtなどを指定している場合は、MANIFEST.inが無いとinstall時にrequirements.txtが無いよってエラーが出ます。

パッケージのテスト

パッケージにする準備ができたら、まずはローカルでパッケージにしてテストしてみましょう。
ローカルでテストしたい場合は、python setup.py developコマンドでパッケージ化してsite-packages内にinstallすることが出来ます。

$ cd ~/pypipkg
$ python setup.py develop

これによって、pythonプロジェクト内でimportで呼び出せる様になり、
setup.pyのentry_pointsで作成したコマンドもlocalで使用出来る様になるので問題無くパッケージとして動作するか確認ができます。

TestPyPIに登録する

本番のPyPIに登録する前にTestPyPIに登録することで、PyPIページの表示の確認やinstallなど一連の動作が本番同様に行えます。

まずは本番同様にアカウント登録が必要なので、アカウントを作成します。

↓TestPyPIのページはこんな感じでTESTING SITEと書かれています。

pypirc

TestPyPiを使用する場合は、下記の様にHOMEディレクトリに.pypircを作成する必要があるそうです。(参考)


$ vim ~/.pypirc

[distutils]
index-servers =
  pypi
  pypitest

[pypi]
repository=https://pypi.python.org/pypi
username=your_username
password=your_password

[pypitest]
repository=https://testpypi.python.org/pypi
username=your_username
password=your_password

TestPyPI register

pypircができたら、setup.pyがあるパッケージの直下に移動して、registerコマンドでTestPyPIにパッケージ情報を登録します

python setup.py register -r https://testpypi.python.org/pypi

TestPyPI search

registerで情報を登録したらsearchコマンドで確認できるらしいです。
(僕の場合はなぜか終止うまくいかなかった)

pip search --index https://testpypi.python.org/pypi pypipkg

TestPyPI upload

registerコマンドは、パッケージ情報を登録しただけでパッケージのgzip(ソースコード)そのものはまだ上がっていないので、uploadコマンドで実体を上げて初めて登録が完了します。

python setup.py sdist upload -r https://testpypi.python.org/pypi

TestPyPI install

uploadまで終わったらpip installでinstallできるようになります。

pip install --index-url https://testpypi.python.org/simple/ pypipkg

これで無事にinstallできたと思います。
ここまで確認できたら、後は本番のPyPIに公開するだけです。

本番のPyPIに登録する

では、本番のPyPIに公開してみましょう。

ここでもアカウント登録が必要なので、アカウントを作成します。

アカウントが出来たら登録作業をおこないます。
手順はTestPyPIの時と同じす。

PyPI register

まずは、registerコマンドで登録をします。

python setup.py register

PyPI upload

次にuploadコマンドで実体を上げます。

python setup.py sdist upload

PyPIサイト確認

はい!これで登録が完了したのでPyPIサイトで確認してみましょう。
こんな感じ

バッチリ公開されているので、これでpip installでinstallできるようになりました!

まとめ

初めはsetup.pyが面倒だなって思ったんですが、そこさえ書いちゃえばあとの登録作業はすごく簡単です。
それに、テストできる環境もちゃんと用意されているので、思ってたより抵抗無くPyPIデビューできました。