自作のPythonパッケージをPyPIに登録してpip install可能にする

# はじめに

自作のPythonパッケージをPyPIに登録して`pip install`可能にしたので、その方法をまとめました。

ちなみに参考までに自作のPythonパッケージは以下になります。
PyPIのサイト上ではどのように各種情報が表示されるのか、等の参考にしてください。

- https://pypi.org/project/gokulang/

ソースコードは以下になります。

- https://github.com/shonansurvivors/goku-lang

# パッケージ登録の手順

パッケージ登録の流れは以下になります。

 1. テスト環境・本番環境のPyPIのアカウント登録
 2. wheel, twineのインストール 
 3. setup.pyの作成
 4. python setup.py bdist_wheelの実行
 5. (任意).gitignoreの編集
 6. (任意)テスト環境のPyPIへのパッケージ登録とpip install
 7. 本番環境のPyPIへのパッケージ登録とpip install

# パッケージのディレクトリ構成

以下の構成のパッケージを例に説明します。

```
.
├── .gitignore
├── README.md # GitHub用のパッケージ説明文
├── gokulang # パッケージ(プロジェクト)の名前
│   ├── __init__.py
│   ├── gokulang.py # メインモジュール
│   ├── romakana.py # サブモジュール
│   └── test_gokulang.py # メインモジュールのテスト
└── setup.py # PyPIへの登録に必要
```

# 手順解説

## 1. テスト環境・本番環境のPyPIのアカウント登録

テスト環境・本番環境のページから`Resister`を選択して、アカウント登録を行ってください。

- テスト環境: https://test.pypi.org
- 本番環境: https://pypi.org

アカウント登録後、それぞれメールが届きますので、メール本文の`click this link to verify your email address`をクリックしてください。

**このメール認証を行わなくても各環境のPyPIのサイトにログインはできますが、パッケージを登録しようとするとエラーになってしまいますので、忘れずにメール認証しておいてください。**

## 2. wheel, twineのインストール

- PyPI登録用パッケージの作成ツールである`wheel`
- PyPIへのパッケージ登録実行ツールである`twine`

をインストールします。

```
(venv) $ pip install wheel twine 
```

## 3. setup.pyの作成

```python
from setuptools import setup
from codecs import open
from os import path

here = path.abspath(path.dirname(__file__))

# long_description(後述)に、GitHub用のREADME.mdを指定
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='gokulang', # パッケージ名(プロジェクト名)
    packages=['gokulang'], # パッケージ内(プロジェクト内)のパッケージ名をリスト形式で指定

    version='1.0.0', # バージョン

    license='MIT', # ライセンス

    install_requires=['janome', 'pykakasi', 'semidbm', 'six'], # pip installする際に同時にインストールされるパッケージ名をリスト形式で指定

    author='shonansurvivors', # パッケージ作者の名前
    author_email='shonansurvivors@gmail.com', # パッケージ作者の連絡先メールアドレス

    url='https://github.com/shonansurvivors/yourpackage', # パッケージに関連するサイトのURL(GitHubなど)

    description='To translate Japanese sentences into Son Goku accent.', # パッケージの簡単な説明
    long_description=long_description, # PyPIに'Project description'として表示されるパッケージの説明文
    long_description_content_type='text/markdown' # long_descriptionの形式を'text/plain', 'text/x-rst', 'text/markdown'のいずれかから指定
    keywords='gokulang goku-lang', # PyPIでの検索用キーワードをスペース区切りで指定

    classifiers=[
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.6',
    ], # パッケージ(プロジェクト)の分類。https://pypi.org/classifiers/に掲載されているものを指定可能。
)
```

# 4. python setup.py bdist_wheelの実行

以下コマンドを実行し、PyPI登録用のパッケージを作成します。

```
(venv) $ python setup.py bdist_wheel
```

コマンドを実行すると、以下`# NEW`と記載したディレクトリ、ファイルが作成されます。

```
.
├── README.md
├── build # New
│   ├── bdist.macosx-10.9-x86_64 # New
│   └── lib # New
│       └── あなたのパッケージ名 # New（自作パッケージ名)
│           ├── __init__.py # New
│           └── あなたのパッケージ内のモジュール名.py # New
├── dist # New
│   └── あなたのパッケージ名-1.0.0-py3-none-any.whl # New
├── あなたのパッケージ名
│   ├── __init__.py
│   └── あなたのパッケージ内のモジュール名.py
├── あなたのパッケージ名.egg-info # New
│   ├── PKG-INFO # New
│   ├── SOURCES.txt # New
│   ├── dependency_links.txt # New
│   ├── requires.txt # New
│   └── top_level.txt # New
└── setup.py
```

なお、パッケージを修正して（バージョンアップして）、PyPI登録用パッケージを再び作り直す際は、あらかじめ上記の`# NEW`のディレクトリ、ファイルは削除しておきましょう。

## 5. (任意).gitignoreの編集

gitでこのパッケージをソース管理している場合`.gitignore`に以下を追記することで、`python setup.py bdist_wheel`で作成されるディレクトリ、ファイルをgit管理対象外にできます。

```
build/
dist/
あなたのパッケージ名.egg-info/
```

##  6. （任意）テスト環境のPyPIへのパッケージ登録とpip install

### 6.1. テスト環境のPyPIへのパッケージ登録

以下コマンドで、テスト環境のPyPIへのパッケージ登録が開始されます。

```
(venv) $ twine upload --repository testpypi dist/*
```

ユーザー名とパスワードを聞かれるのでそれぞれ入力してください。

```
Enter your username: (あなたのusername)
Enter your password: 
```

問題無ければ、以下のようにパッケージが登録されます。

```
Uploading distributions to https://test.pypi.org/legacy/
Uploading あなたのパッケージ名-1.0.0-py3-none-any.whl
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 11.4k/11.4k [00:02<00:00, 5.13kB/s]
```

`https://test.pypi.org/project/あなたのパッケージ名/`にブラウザでアクセスしてください。

登録したパッケージが表示されているはずです。

### 6.2. テスト環境のPyPIからのpip install

テスト環境のPyPIから、あなたの自作パッケージを`pip install`してみましょう。

```
(venv) $ pip install --index-url https://test.pypi.org/simple/ あなたのパッケージ名
```

**なお、これまで自作モジュールを開発していたのとは別のディレクトリ、別の仮想環境にて実施することをおすすめします。**

#### 6.2.1. 【トラブルその1】 テスト環境のPyPIのサイトにはパッケージが掲載されているのに、インストールができない

テスト環境のPyPIのサイトにはパッケージが掲載されているのに、インストールできない場合があります。

```
  Could not find a version that satisfies the requirement あなたのパッケージ名 (from versions: 1.0.5)
No matching distribution found for あなたのパッケージ名
```

反映に時間がかかっている可能性があります。少し待ってから、改めてインストールしてみてください。私の場合、10分〜15分程度待ったら解消した場合がありました。

#### 6.2.2. 【トラブルその2】 テスト環境のPyPIから依存関係にあるパッケージをインストールできない

今回のサンプルパッケージでは、依存関係にあるいくつかの別パッケージを`setup.py`の`install_requires`に指定していますが、これらパッケージがテスト環境のPyPIに存在するとは限りません。

以下は、`setup.py`の`install_requires`に指定していた`semidbm`が、テスト環境のPyPIから見つからず、自作パッケージ自体の`pip install`が失敗に終わっています。

```
Collecting semidbm (from あなたのパッケージ名)
  Could not find a version that satisfies the requirement semidbm (from あなたのパッケージ名) (from versions: )
No matching distribution found for semidbm (from あなたのパッケージ名)
````

こういった場合は、その依存パッケージだけ個別に本番環境のPyPIからインストールしましょう（要は普通に`pip install`しましょう）。

```
(venv) $ pip install semidbm
```

#### 6.2.3. 【トラブルその3】 テスト環境のPyPIからpip installした自作パッケージが正常に動作しない

以下の理由が考えられます。

- `setup.py`の`install_requires`に指定した依存パッケージ群のバージョンが、本番環境のPyPIと比較して最新でない為、不整合が生じている

テスト環境のPyPIが不完全であることから問題が生じているので、こうした場合は諦めて本番環境のPyPIへのパッケージ登録に進んでしまって良いと思います。

##  ７. 本番環境のPyPIへのパッケージ登録とpip install

### 7.1. 本番環境のPyPIへのパッケージ登録

以下コマンドで、本番環境のPyPIへのパッケージ登録が開始されます。

```
(venv) $ twine upload --repository pypi dist/*
```

ユーザー名とパスワードを聞かれるのでそれぞれ入力してください。

```
Enter your username: (あなたのusername)
Enter your password: 
```

問題無ければ、以下のようにパッケージが登録されます。

```
Uploading distributions to https://pypi.org/legacy/
Uploading あなたのパッケージ名-1.0.0-py3-none-any.whl
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 11.4k/11.4k [00:02<00:00, 5.13kB/s]
```

`https://pypi.org/project/あなたのパッケージ名/`にブラウザでアクセスしてください。登録したパッケージが表示されているはずです。

### 7.2. 本番環境のPyPIからのpip install

改めて説明するまでもありませんが、本番環境のPyPIからの`pip install`は以下の通りです。

```
(venv) $ pip install あなたのパッケージ名
```


# よくあるエラーとその対処方法

- [PyPIエラー対応　File already exists - Qiita](https://qiita.com/shonansurvivors/items/4032cea13c03ae10da22)

- [PyPIエラー対応　User (username) has no verified email addresses - Qiita](https://qiita.com/shonansurvivors/items/8a6386e7768c8a548cb8)

- [PyPIエラー対応　Invalid or non-existent authentication information - Qiita](https://qiita.com/shonansurvivors/items/f4649b620f404eddb4e9)

# 参考

- [Packaging and distributing projects - Python Packaging User Guide](https://packaging.python.org/guides/distributing-packages-using-setuptools/)

- [Building and Distributing Packages with Setuptools - setuptools 40.8.0 documentation](https://setuptools.readthedocs.io/en/latest/setuptools.html)

- [PyPIパッケージ公開手順 - Qiita](https://qiita.com/shinichi-takii/items/e90dcf7550ef13b047b5)

- [PyPI登録手順〜pip installするまで〜 - Qiita](https://qiita.com/takezyou/items/9b34c601a5dba0ee837b)