Skip to content

Instantly share code, notes, and snippets.

@Cartman0
Last active April 8, 2016 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cartman0/4b95fdbe00b52f4d0c90a1654a4b15c7 to your computer and use it in GitHub Desktop.
Save Cartman0/4b95fdbe00b52f4d0c90a1654a4b15c7 to your computer and use it in GitHub Desktop.
Dive Into Python3 16章メモ(Pythonライブラリをパッケージ化する)
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"metadata": {
"toc": "true"
},
"cell_type": "markdown",
"source": "# Table of Contents\n <p><div class=\"lev1\"><a href=\"#16章-Pythonライブラリをパッケージ化する-1\"><span class=\"toc-item-num\">1&nbsp;&nbsp;</span>16章 Pythonライブラリをパッケージ化する</a></div><div class=\"lev2\"><a href=\"#飛び込む-1.1\"><span class=\"toc-item-num\">1.1&nbsp;&nbsp;</span>飛び込む</a></div><div class=\"lev2\"><a href=\"#Distutilsがやってくれないこと-1.2\"><span class=\"toc-item-num\">1.2&nbsp;&nbsp;</span>Distutilsがやってくれないこと</a></div><div class=\"lev2\"><a href=\"#ディレクトリ構造-1.3\"><span class=\"toc-item-num\">1.3&nbsp;&nbsp;</span>ディレクトリ構造</a></div><div class=\"lev2\"><a href=\"#セットアップスクリプトを書く-1.4\"><span class=\"toc-item-num\">1.4&nbsp;&nbsp;</span>セットアップスクリプトを書く</a></div><div class=\"lev2\"><a href=\"#パッケージを分類する-1.5\"><span class=\"toc-item-num\">1.5&nbsp;&nbsp;</span>パッケージを分類する</a></div><div class=\"lev3\"><a href=\"#良いパッケージ分類タグの例-1.5.1\"><span class=\"toc-item-num\">1.5.1&nbsp;&nbsp;</span>良いパッケージ分類タグの例</a></div><div class=\"lev2\"><a href=\"#マニフェストを使って追加ファイルを指定する-1.6\"><span class=\"toc-item-num\">1.6&nbsp;&nbsp;</span>マニフェストを使って追加ファイルを指定する</a></div><div class=\"lev2\"><a href=\"#セットアップスクリプトにエラーがないかを確認する-1.7\"><span class=\"toc-item-num\">1.7&nbsp;&nbsp;</span>セットアップスクリプトにエラーがないかを確認する</a></div><div class=\"lev2\"><a href=\"#ソースディストリビューションを作る-1.8\"><span class=\"toc-item-num\">1.8&nbsp;&nbsp;</span>ソースディストリビューションを作る</a></div><div class=\"lev2\"><a href=\"#グラフィカルインストーラを作る-1.9\"><span class=\"toc-item-num\">1.9&nbsp;&nbsp;</span>グラフィカルインストーラを作る</a></div><div class=\"lev3\"><a href=\"#他のオペレーティングシステムのためのパッケージを構築する-1.9.1\"><span class=\"toc-item-num\">1.9.1&nbsp;&nbsp;</span>他のオペレーティングシステムのためのパッケージを構築する</a></div><div class=\"lev2\"><a href=\"#ソフトウェアをPython-Package-Indexに追加する-1.10\"><span class=\"toc-item-num\">1.10&nbsp;&nbsp;</span>ソフトウェアをPython Package Indexに追加する</a></div><div class=\"lev2\"><a href=\"#参考リンク-1.11\"><span class=\"toc-item-num\">1.11&nbsp;&nbsp;</span>参考リンク</a></div>"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "- [Dive Into Python3 1章メモ](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/d54093a99b9254c81bf1123adacbc48a/raw/eedc90bbbfc14e259854f2e739fffeec4cb4d8f7/DiveIntoPython3_01.ipynb)\n- [Dive Into Python3 2章メモ(ネイティブデータ型)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/988b51d8482ad9ade835bb07efdffb38/raw/784cf276b7cebe254e59f09dcea6f09eea760d38/DiveIntoPython3_02.ipynb)\n- [Dive Into Python3 3章メモ(内包表記)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/183ec6f6c835f621106f7c27d215290a/raw/bd7677946d6400bbe6acd257df7fb9c5976c3320/DiveIntoPython3_03.ipynb)\n- [Dive Into Python3 4章メモ(文字列)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/bb974f82e8a3fc74ac82c3c2a5b1a4f9/raw/63a80011c9391b451108c1a4dc804ec5ff125f34/DiveIntoPython3_04.ipynb)\n- [Dive Into Python3 5章メモ(正規表現)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/b834807a0dabb1c458b87be2f333a5ca/raw/37d6f25f67e017a569e1f0b60a9fcbe49d50515f/DiveIntoPython3_05.ipynb)\n- [Dive Into Python3 6章メモ(クロージャとジェネレータ)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/a8998f8f88c5578271495ada56cc4809/raw/4e9b8ef3543016a710f905215693694acd703549/DiveIntoPython3_06.ipynb?flush_cache=true)\n- [Dive Into Python3 7章メモ(クラスとイテレータ)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/8eb511c3b2aa6cadad6f6d49666c9db2/raw/60863d1ce1c1e9e4cb336ad79a0e252807beb87c/DiveIntoPython3_07.ipynb?flush_cache=true)\n- [Dive Into Python3 8章メモ(高度なイテレータ)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/9ed3037cbdac59af53c20c125aed806e/raw/46ee3c71d72ab7ee665cf0c10f8717734632b462/DiveIntoPython3_08.ipynb)\n- [Dive Into Python3 9章メモ(ユニットテスト)](http://nbviewer.jupyter.org/urls/gist.githubusercontent.com/Cartman0/1833320ab55ae5ea660ce0c635483d26/raw/46034833206366c8011594cbea2efce90168d54b/DiveIntoPython3_09.ipynb)\n- [Dive Into Python3 10章メモ(リファクタリング)](http://nbviewer.jupyter.org/gist/Cartman0/0c0af20eb95236da4da9547258fe2bb3)\n- [Dive Into Python3 11章メモ(ファイル)](http://nbviewer.jupyter.org/gist/Cartman0/152eacd23b793ecd3dbf5f706ae33e92)\n- [Dive Into Python3 12章メモ(XML)](http://nbviewer.jupyter.org/gist/Cartman0/87d2d00c5d64c66778f20d1d056e76c7)\n- [Dive Into Python3 13章メモ(Pythonオブジェクトをシリアライズ)](http://nbviewer.jupyter.org/gist/Cartman0/33cd21bbc84ae3c07ea84884f8354ab3)\n- [Dive Into Python3 14章メモ(HTTPウェブサービス)](http://nbviewer.jupyter.org/1c885ad8ce22c021b0350f53ee3a1126/DiveIntoPython3_14.ipynb)"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "# 16章 Pythonライブラリをパッケージ化する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 飛び込む"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "世界はより多くのPythonコードを求めている。\nPython 3 には `Distutils` と呼ばれるパッケージング用のフレームワークが付属している。\nこの `Distutils` はたくさんのものがつまったライブラリ \n- (あなたのための)ビルドツール、\n- (ユーザのための)インストールツール\n- (検索エンジンのための)パッケージのメタデータの形式、\n\nなどなど。\n\nさらに、`Distutils` は、オープンソースのPythonライブラリのための中央リポジトリである Python Package Index (“PyPI”) に統合されている。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "このような `Distutils` の様々な面の中核にあるのが\n「セットアップスクリプト」(このスクリプトは伝統的にsetup.pyと呼ばれている)。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "> chardetのsetup.py\n\n```\nfrom distutils.core import setup\nsetup(\n name = \"chardet\",\n packages = [\"chardet\"],\n version = \"1.0.2\",\n description = \"Universal encoding detector\",\n author = \"Mark Pilgrim\",\n author_email = \"mark@diveintomark.org\",\n url = \"http://chardet.feedparser.org/\",\n download_url = \"http://chardet.feedparser.org/download/python3-chardet-1.0.1.tgz\",\n keywords = [\"encoding\", \"i18n\", \"xml\"],\n classifiers = [\n \"Programming Language :: Python\",\n \"Programming Language :: Python :: 3\",\n \"Development Status :: 4 - Beta\",\n \"Environment :: Other Environment\",\n \"Intended Audience :: Developers\",\n \"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)\",\n \"Operating System :: OS Independent\",\n \"Topic :: Software Development :: Libraries :: Python Modules\",\n \"Topic :: Text Processing :: Linguistic\",\n ],\n long_description = \"\"\"\\\nUniversal character encoding detector\n-------------------------------------\n```\n\n```\nDetects\n - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants)\n - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese)\n - EUC-JP, SHIFT_JIS, ISO-2022-JP (Japanese)\n - EUC-KR, ISO-2022-KR (Korean)\n - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic)\n - ISO-8859-2, windows-1250 (Hungarian)\n - ISO-8859-5, windows-1251 (Bulgarian)\n - windows-1252 (English)\n - ISO-8859-7, windows-1253 (Greek)\n - ISO-8859-8, windows-1255 (Visual and Logical Hebrew)\n - TIS-620 (Thai)\n\nThis version requires Python 3 or later; a Python 2 version is available separately.\n\"\"\"\n)\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "`chardet` と `httplib2` はオープンソースだが、\nPythonライブラリを何か特定のライセンスでリリースしなければならないという制約は存在しない。\nこの章で説明する手順は、ライセンスに関係なく、どんなPythonのソフトウェアにも使える。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## Distutilsがやってくれないこと"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "初めてのPythonパッケージをリリースする作業は手ごわいもの。\nDistutils はできる限りの自動化を試みてくれるが、自分自身でやらなければいけないこともいくつか存在する。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "- **ライセンスの選択**\nこれは、政治と危険に満ちた複雑な話題だ。自分のソフトウェアをオープンソースとしてリリースしたいのであれば、私はつつましく5つのアドバイスをしておく:\n\n 1. 独自のライセンスを書いてはならない。\n 2. 独自のライセンスを書いてはならない。\n 3. 独自のライセンスを書いてはならない。\n 4. ライセンスがgplである必要はないが、gpl互換である必要がある。\n 5. 独自のライセンスを書いてはならない。\n\n\n- **ソフトウェアの分類**\nこの分類にはPyPIの分類システムを使うが、その詳細についてはこの章のもう少し後で説明する。\n\n- **“read me”ファイルの作成** \nこれをいい加減に済ませてはならない。最低でも、ソフトウェアが何をするのかについての概要と、インストールの方法ぐらいは書くようにしよう。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## ディレクトリ構造"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Pythonソフトウェアのパッケージ化を始めるには、ファイルとディレクトリを整理する必要がある。\n`httplib2`ディレクトリは以下のようになる:"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nhttplib2/ 1\n|\n+--README.txt 2\n|\n+--setup.py 3\n|\n+--httplib2/ 4\n |\n +--__init__.py\n |\n +--iri2uri.py\n```\n\n1. すべてのディレクトリとファイルを入れるルートディレクトリを作ろう。\nこれにはPythonモジュールと同じ名前を付けておく。\n\n2. Windowsユーザのために、“read me” ファイルには.txtという拡張子を付け、さらにWindowsスタイルの改行文字を使っておこう。自分はコマンドラインから起動する独自のマクロ言語を備えたクールなテキストエディタを使っているからといって、ユーザーの人生を難しくする必要はない(ユーザは「メモ帳」を使っている。悲しいけれどこれは事実)。\nあなたがLinuxやMac OS Xを使っているとしても、そのクールなテキストエディタには、まず間違いなくファイルをWindowsスタイルの改行文字で保存するオプションがある。\n\n3. 何かもっともな理由がない限り、Distutilsのセットアップスクリプトには\nsetup.pyという名前を付けておくべき。\n\n4. Pythonソフトウェアが単一の.pyファイルで構成されているのであれば、\nそのファイルは“read me”ファイルやセットアップスクリプトと一緒にルートディレクトリに置いておけばいい。\nしかし、httplib2は単一の.pyファイルではない。httplib2はマルチファイルモジュールなのだ。しかしそれでも問題はない! \nルートディレクトリの中にhttplib2ディレクトリを置こう。\nつまり、httplib2/というルートディレクトリの中にあるhttplib2/ディレクトリの中に `__init__.py`ファイルがあることになる。これで問題ない。実は、これによってパッケージ化の処理が単純化される。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "chardetディレクトリの方はこれとは微妙に異なっている。\nhttplib2と同じくchardetはマルチファイルモジュールなので、\nchardet/というルートディレクトリの中にchardet/ディレクトリが存在する。\nしかし、chardetの場合は、\nREADME.txtファイルに加えてhtml形式のドキュメントがdocs/ディレクトリの中に用意されているのだ。このdocs/ディレクトリには、.htmlファイルや.cssファイルがいくつか入っており、さらにimages/というサブディレクトリの中には複数の.pngファイルや.gifファイルも入っている(これは後で重要になる)。\n\nまた、(l)gplでライセンスされたソフトウェアの慣例として、lgplの全文を収めたCOPYING.txtというファイルも入っている。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nchardet/\n|\n+--COPYING.txt\n|\n+--setup.py\n|\n+--README.txt\n|\n+--docs/\n| |\n| +--index.html\n| |\n| +--usage.html\n| |\n| +--images/ ...\n|\n+--chardet/\n |\n +--__init__.py\n |\n +--big5freq.py\n |\n +--...\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## セットアップスクリプトを書く"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "DistutilsのセットアップスクリプトはPythonスクリプトになる。\nこのスクリプトは理論的にはPythonができることなら何でもできる。\nしかし実際には、このスクリプトでは最小限の処理を可能な限り標準的な方法で行うべき。\n\nインストール処理をエキゾチックなものにすれば、\nエキゾチックなバグレポートが返ってくることになる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "どんなDistutilsセットアップスクリプトだろうと、1行目は常に同じものになる:\n\n```\nfrom distutils.core import setup\n```\n\nこれは `setup()`関数をインポートしている。\nこの関数がDistutilsのメインのエントリポイント。\nすべてのDistutilsセットアップスクリプトのうちの95%はsetup()の呼び出しだけで構成されており、他には何も含んでいない(この統計は単なるでっち上げだが、Distutilsのセットアップスクリプトが、Distutilsのsetup()関数を呼び出す以上のことをするのであれば、何かそれ相応の理由を持っているべき."
},
{
"metadata": {},
"cell_type": "markdown",
"source": "setup()関数は何十ものパラメータを受け取ることができる。これに関わるすべての人を正気に保つために、すべてのパラメータには名前付き引数を使わなければならない。これは単なる慣例ではなく、コード上要求されている条件だ。従って、名前付き引数を使わずにsetup()関数を呼び出そうとすると、セットアップスクリプトはクラッシュする。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "次の名前付き引数は必須:\n\n- name: パッケージ名\n- version: パッケージのバージョン番号\n- author: フルネーム\n- author_email: 電子メールアドレス\n- url: プロジェクトのホームページ。\nプロジェクト用のウェブサイトを別個に持っていないのであれば、自分のPyPIパッケージのページでもいい。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "必須ではないが、以下もセットアップスクリプトに含めておくことを推奨:\n\n- description: プロジェクトの一行要約\n- long_description: reStructuredText形式で書かれた複数行の文字列。PyPIはこれをhtmlに変換し、あなたのパッケージのページに表示する。\n- classifiers: 次節で説明する特別な形式の文字列のリスト"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "セットアップスクリプトのメタデータは [pep 314](https://www.python.org/dev/peps/pep-0314/) で定義されている。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "では、chardetのセットアップスクリプトを見てみよう。\nここでは先ほど説明した必須/推奨のパラメーター全部に加えて、\nさらにもう一つ、`packages`というパラメータを使っている。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nfrom distutils.core import setup\nsetup(\n name = 'chardet',\n packages = ['chardet'],\n version = '1.0.2',\n description = 'Universal encoding detector',\n author='Mark Pilgrim',\n ...\n)\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "packagesパラメータは、配布プロセスにおける用語の不幸な重複を浮き彫りにする。\n私たちは、いま構築しているものを「パッケージ」と呼んできた(そして、これがPythonの「パッケージ」インデックスに登録される)。\n\nしかし、このpackagesパラメータが指しているものはそれとは違う。これは、chardetモジュールがマルチファイルモジュール(これは時に……「パッケージ」と呼ばれる)であるという事実を指している。\nこのpackagesパラメータは、\nchardet/ディレクトリ、`__init__.py`ファイル、\nそしてchardetモジュールを構成するすべての.pyファイルをビルドに加えるように\n`Distutils` に伝える。\nこれは重要。\nもし実際のソースコードを入れ忘れてしまったら、\nドキュメントやメタデータの話はすべて無意味なものになってしまう。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## パッケージを分類する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Python Package Index (“PyPI”) には何千ものPythonライブラリが存在している。\n適切な分類用メタデータを用意しておけば、他の人々があなたのライブラリを簡単に見つけられるようになる。\n\nPyPIは、分類タグをもとにパッケージを探せるようになっていて、\n分類タグをいくつか選んで絞り込みをかけることもできる。\n分類タグは無視できるような見えないメタデータではない。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "ソフトウェアを分類するには、\n`classifiers`パラメータを `Distutils` の `setup()`関数に渡せばよい。\n\n`classifiers` は、文字列のリストだが、この文字列は自由形式ではない。\nすべての分類タグはPyPIのこのリストにあるものを使う必要がある。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "分類タグはオプションなので、Distutilsのセットアップスクリプトを書く時には全て省略することもできる。\nしかしそれをやってはいけない。少なくとも次の分類タグは必ず入れておくべき。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "- **Programming Language**(プログラミング言語): \n具体的には、\n - \"Programming Language :: Python\"と\n - \"Programming Language :: Python :: 3\"\n\nの両方を入れておくべき。\nこの2つのタグを抜かすと、パッケージはpypi.python.orgの全ページのサイドバーからリンクされているこの Python 3 互換ライブラリのリストに表示されなくなってしまう。\n\n- **License**(ライセンス): \nこれは、サードパーティのライブラリを評価するときにに探される。\n複数のライセンスの下で配布しているライブラリだとはっきり示しているのでなければ、複数のライセンスタグを入れてはいけない(そして、強制されている場合でなければ、ソフトウェアを複数のライセンスで公開しないべき。\nまた、他の人に複数ライセンスを強制するのもやめるべき。)\n\n- **Operating System**(オペレーティングシステム): \nもしソフトウェアがWindows(あるいはMac OS XやLinux)上でのみ動くものなら、後になってそれを知るよりも早めに知っておきたい。\nソフトウェアがプラットフォーム依存のコードを使わずにどこでも動作するのであれば、\"Operating System :: OS Independent\"という分類タグを使う。\n複数のOparating System分類タグを書かなければならないのは、\nソフトウェアが個々のプラットフォームについて特別なサポートを必要とするときだけ(これは一般的ではない)。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "以下の分類タグも含めておくことを奨める:"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "- **Development Status**(開発状況): ソフトウェアはベータ版の品質だろうか? それともアルファ版の品質? プリアルファ? 一つだけ選ぼう。それも正直に。\n\n- **Intended Audience**(対象とする利用者): どんな人がソフトウェアをダウンロードするだろうか? 最も一般的な選択肢としては\n - Developers、\n - End Users/Desktop、\n - Science/Research、\n - System Administrators\n\nがある。\n\n- Framework(フレームワーク): もしソフトウェアが、DjangoやZopeなどのもっと大きなフレームワークのためのプラグインである場合は、適当なFrameworkタグを付けておこう。そうでないのならこれは省略する。\n\n- Topic(トピック): たくさんの選択肢が存在する。該当するものをすべて選択しよう。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### 良いパッケージ分類タグの例"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "例を挙げるために、ここに **Django** の分類タグを示す。\n\n**Django** は、製品レベルの品質を持ち、クラスプラットフォームで、Webサーバ上で動作する、bsdライセンスのウェブアプリケーションフレームワークだ(DjangoはまだPython 3に対応していないので、Programming Language :: Python :: 3というタグは含まれていない)。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nProgramming Language :: Python\nLicense :: OSI Approved :: BSD License\nOperating System :: OS Independent\nDevelopment Status :: 5 - Production/Stable\nEnvironment :: Web Environment\nFramework :: Django\nIntended Audience :: Developers\nTopic :: Internet :: WWW/HTTP\nTopic :: Internet :: WWW/HTTP :: Dynamic Content\nTopic :: Internet :: WWW/HTTP :: WSGI\nTopic :: Software Development :: Libraries :: Python Modules\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "次は**chardetの分類タグ**。\n\nchardetは、\n文字コード自動判定用のライブラリだ。\nこれは\n- ベータ版の品質\n- クラスプラットフォームで、\n- Python 3互換で、\n- lgplでライセンスされていて、\n- 開発者が自身の製品に組み込んで使うこと\n\nを想定している。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nProgramming Language :: Python\nProgramming Language :: Python :: 3\nLicense :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)\nOperating System :: OS Independent\nDevelopment Status :: 4 - Beta\nEnvironment :: Other Environment\nIntended Audience :: Developers\nTopic :: Text Processing :: Linguistic\nTopic :: Software Development :: Libraries :: Python Modules\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "次は `httplib2` の分類タグ。\nこれは、httpウェブサービスで詳しく見たライブラリだ。\n\n`httplib2` は\n- ベータ版の品質で、\n- クロスプラットフォームで、\n- mitライセンスで、Python開発者を対象\n\nとしている。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nProgramming Language :: Python\nProgramming Language :: Python :: 3\nLicense :: OSI Approved :: MIT License\nOperating System :: OS Independent\nDevelopment Status :: 4 - Beta\nEnvironment :: Web Environment\nIntended Audience :: Developers\nTopic :: Internet :: WWW/HTTP\nTopic :: Software Development :: Libraries :: Python Modules\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## マニフェストを使って追加ファイルを指定する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "デフォルトでは、`Distutils` は次のファイルをリリースパッケージに入れる:\n\n- README.txt\n- setup.py\n- packagesパラメータにリストされたマルチファイルモジュールが必要とする.pyファイル。\n- py_modulesパラメータにリストされた個々の.pyファイル。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "これでhttplib2プロジェクトのファイルは網羅できている。\n\nしかし `chardet`プロジェクトでは、\nこれに加えて `COPYING.txt`ライセンスファイルと、\n画像やhtmlファイルを収めたdocs/ディレクトリもパッケージに入れておくつもりだった。\nこのファイルやディレクトリをchardetのリリースパッケージに追加してもらうには、\n**マニフェストファイル** が必要となる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "マニフェストファイルは `MANIFEST.in` という名のテキストファイル。\nこのファイルをREADME.txtやsetup.pyファイルと一緒にルートディレクトリに置く。\n\nマニフェストファイルは、Pythonスクリプトではなく、\n`Distutils` が定義する一連の「コマンド」を並べたテキストファイル。\nマニフェストコマンドを使うことで、特定のファイルやディレクトリをパッケージに含めたり除外したりできる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "chardetプロジェクト用のマニフェストファイル全体:\n\n```\ninclude COPYING.txt 1\nrecursive-include docs *.html *.css *.png *.gif 2\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "`recursive-include` はディレクトリ名と1つ以上のファイル名を受け取る。\nこのファイル名の部分ではファイルを個別に指定するだけではなく、ワイルドカードを使って指定することもできる。\n\nこの行は「ルートディレクトリの中にdocs/ディレクトリがあるだろう? \nその中から `.html・.css・.png・.gif`ファイルを(再帰的に)探してほしい。\nそれらをすべてリリースパッケージに入れたい」という意味になる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "すべてのマニフェストコマンドは、\nプロジェクトディレクトリのディレクトリ構造をそのまま維持する。\n\n`recursive-include`コマンドが、`.html` と `.png`ファイルをリリースパッケージのルートディレクトリに置くことはない。\nこのコマンドはdocs/ディレクトリの構造を保ちつつ、このディレクトリの中にあるファイルのうちワイルドカードにマッチしたものだけをパッケージに含める(今まで言っていなかったが、chardetのドキュメントは、\n実際にはxmlで書かれており、\n別のスクリプトによってhtmlに変換されている。\n私はこのxmlファイルをリリースパッケージに含めずに、htmlと画像だけを含めておきたい)。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "マニフェストファイルが必要になるのは、`Distutils` がデフォルトでは無視するファイルをパッケージに入れる場合だけ。\nマニフェストファイルが本当に必要なら、`Distutils` がデフォルトで見つけないファイルやディレクトリだけを書くようにする。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## セットアップスクリプトにエラーがないかを確認する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "把握しておかなければいけないことはたくさんある。\n\n`Distutils` には、必須なメタデータがセットアップスクリプト中にすべて存在しているかどうかをチェックするための組み込みの検証コマンドが付属している。\n\n例えば、`version`パラメータを入れ忘れたとしたら、`Distutils` がそれをエラーとして表示してくれる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "例:\n```\nc:\\python31\\python.exe setup.py check\nrunning check\nwarning: check: missing required meta-data: version\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "versionパラメータ(とその他の必要なメタデータ全て)を入れると、checkコマンドはこのようになる:\n\n```\nc:\\Users\\pilgrim\\chardet> c:\\python31\\python.exe setup.py check\nrunning check\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## ソースディストリビューションを作る"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "Distutilsは、複数の種類のリリースパッケージを構築できる。\n\n最低でも、ソースコードと、\n`Disturils` のセットアップスクリプトと、\n“read me”ファイルと、その他任意の追加ファイルを入れた「ソースディストリビューション」を構築すべき。\nソースディストリビューションを構築するには、`Distutils` のセットアップスクリプトに\n`sdist`コマンドを渡せばよい。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nc:\\Users\\pilgrim\\chardet> c:\\python31\\python.exe setup.py sdist\nrunning sdist\nrunning check\nreading manifest template 'MANIFEST.in'\nwriting manifest file 'MANIFEST'\ncreating chardet-1.0.2\ncreating chardet-1.0.2\\chardet\ncreating chardet-1.0.2\\docs\ncreating chardet-1.0.2\\docs\\images\ncopying files to chardet-1.0.2...\ncopying COPYING -> chardet-1.0.2\ncopying README.txt -> chardet-1.0.2\ncopying setup.py -> chardet-1.0.2\ncopying chardet\\__init__.py -> chardet-1.0.2\\chardet\ncopying chardet\\big5freq.py -> chardet-1.0.2\\chardet\n...\ncopying chardet\\universaldetector.py -> chardet-1.0.2\\chardet\ncopying chardet\\utf8prober.py -> chardet-1.0.2\\chardet\ncopying docs\\faq.html -> chardet-1.0.2\\docs\ncopying docs\\history.html -> chardet-1.0.2\\docs\ncopying docs\\how-it-works.html -> chardet-1.0.2\\docs\ncopying docs\\index.html -> chardet-1.0.2\\docs\ncopying docs\\license.html -> chardet-1.0.2\\docs\ncopying docs\\supported-encodings.html -> chardet-1.0.2\\docs\ncopying docs\\usage.html -> chardet-1.0.2\\docs\ncopying docs\\images\\caution.png -> chardet-1.0.2\\docs\\images\ncopying docs\\images\\important.png -> chardet-1.0.2\\docs\\images\ncopying docs\\images\\note.png -> chardet-1.0.2\\docs\\images\ncopying docs\\images\\permalink.gif -> chardet-1.0.2\\docs\\images\ncopying docs\\images\\tip.png -> chardet-1.0.2\\docs\\images\ncopying docs\\images\\warning.png -> chardet-1.0.2\\docs\\images\ncreating dist\ncreating 'dist\\chardet-1.0.2.zip' and adding 'chardet-1.0.2' to it\nadding 'chardet-1.0.2\\COPYING'\nadding 'chardet-1.0.2\\PKG-INFO'\nadding 'chardet-1.0.2\\README.txt'\nadding 'chardet-1.0.2\\setup.py'\nadding 'chardet-1.0.2\\chardet\\big5freq.py'\nadding 'chardet-1.0.2\\chardet\\big5prober.py'\n...\nadding 'chardet-1.0.2\\chardet\\universaldetector.py'\nadding 'chardet-1.0.2\\chardet\\utf8prober.py'\nadding 'chardet-1.0.2\\chardet\\__init__.py'\nadding 'chardet-1.0.2\\docs\\faq.html'\nadding 'chardet-1.0.2\\docs\\history.html'\nadding 'chardet-1.0.2\\docs\\how-it-works.html'\nadding 'chardet-1.0.2\\docs\\index.html'\nadding 'chardet-1.0.2\\docs\\license.html'\nadding 'chardet-1.0.2\\docs\\supported-encodings.html'\nadding 'chardet-1.0.2\\docs\\usage.html'\nadding 'chardet-1.0.2\\docs\\images\\caution.png'\nadding 'chardet-1.0.2\\docs\\images\\important.png'\nadding 'chardet-1.0.2\\docs\\images\\note.png'\nadding 'chardet-1.0.2\\docs\\images\\permalink.gif'\nadding 'chardet-1.0.2\\docs\\images\\tip.png'\nadding 'chardet-1.0.2\\docs\\images\\warning.png'\nremoving 'chardet-1.0.2' (and everything under it)\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "指摘しておきたいことがいくつかある:\n\n- Distutilsはマニフェストファイル (MANIFEST.in) に気づいている。\n- Distutilsは、マニフェストファイルのパースに成功し、指定した追加ファイル(COPYING.txtとdocs/ディレクトリにあるHTMLファイルと画像)を追加している。\n- プロジェクトディレクトリの中を覗くと、Distutils が `dist/`というディレクトリを作成したことが分かる。dist/ディレクトリの中には配布可能な `.zip`ファイルがある。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nc:\\Users\\pilgrim\\chardet> dir dist\n Volume in drive C has no label.\n Volume Serial Number is DED5-B4F8\n\n Directory of c:\\Users\\pilgrim\\chardet\\dist\n\n07/30/2009 06:29 PM <DIR> .\n07/30/2009 06:29 PM <DIR> ..\n07/30/2009 06:29 PM 206,440 chardet-1.0.2.zip\n 1 File(s) 206,440 bytes\n 2 Dir(s) 61,424,635,904 bytes free\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## グラフィカルインストーラを作る"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "どんなPythonライブラリにもWindowsユーザのためのグラフィカルインストーラを付ける価値がある。このインストーラは(Windowsを使ってない人でも)簡単に作ることができるし、\nWindowsユーザはこれをありがたく思う。\n\nDistutilsを使えば、グラフィカルなWindowsインストーラを作成できる。この機能を使うには`bdist_wininst` コマンドを `Distutils` のセットアップスクリプトに渡せばよい。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nc:\\Users\\pilgrim\\chardet> c:\\python31\\python.exe setup.py bdist_wininst\nrunning bdist_wininst\nrunning build\nrunning build_py\ncreating build\ncreating build\\lib\ncreating build\\lib\\chardet\ncopying chardet\\big5freq.py -> build\\lib\\chardet\ncopying chardet\\big5prober.py -> build\\lib\\chardet\n...\ncopying chardet\\universaldetector.py -> build\\lib\\chardet\ncopying chardet\\utf8prober.py -> build\\lib\\chardet\ncopying chardet\\__init__.py -> build\\lib\\chardet\ninstalling to build\\bdist.win32\\wininst\nrunning install_lib\ncreating build\\bdist.win32\ncreating build\\bdist.win32\\wininst\ncreating build\\bdist.win32\\wininst\\PURELIB\ncreating build\\bdist.win32\\wininst\\PURELIB\\chardet\ncopying build\\lib\\chardet\\big5freq.py -> build\\bdist.win32\\wininst\\PURELIB\\chardet\ncopying build\\lib\\chardet\\big5prober.py -> build\\bdist.win32\\wininst\\PURELIB\\chardet\n...\ncopying build\\lib\\chardet\\universaldetector.py -> build\\bdist.win32\\wininst\\PURELIB\\chardet\ncopying build\\lib\\chardet\\utf8prober.py -> build\\bdist.win32\\wininst\\PURELIB\\chardet\ncopying build\\lib\\chardet\\__init__.py -> build\\bdist.win32\\wininst\\PURELIB\\chardet\nrunning install_egg_info\nWriting build\\bdist.win32\\wininst\\PURELIB\\chardet-1.0.2-py3.1.egg-info\ncreating 'c:\\users\\pilgrim\\appdata\\local\\temp\\tmp2f4h7e.zip' and adding '.' to it\nadding 'PURELIB\\chardet-1.0.2-py3.1.egg-info'\nadding 'PURELIB\\chardet\\big5freq.py'\nadding 'PURELIB\\chardet\\big5prober.py'\n...\nadding 'PURELIB\\chardet\\universaldetector.py'\nadding 'PURELIB\\chardet\\utf8prober.py'\nadding 'PURELIB\\chardet\\__init__.py'\nremoving 'build\\bdist.win32\\wininst' (and everything under it)\nc:\\Users\\pilgrim\\chardet> dir dist\nc:\\Users\\pilgrim\\chardet>dir dist\n Volume in drive C has no label.\n Volume Serial Number is AADE-E29F\n```\n\n```\nDirectory of c:\\Users\\pilgrim\\chardet\\dist\n\n07/30/2009 10:14 PM <DIR> .\n07/30/2009 10:14 PM <DIR> ..\n07/30/2009 10:14 PM 371,236 chardet-1.0.2.win32.exe\n07/30/2009 06:29 PM 206,440 chardet-1.0.2.zip\n 2 File(s) 577,676 bytes\n 2 Dir(s) 61,424,070,656 bytes free\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "### 他のオペレーティングシステムのためのパッケージを構築する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "`Distutils` は、Linuxユーザ向けのインストールパッケージを構築する手助けをしてくれる。\nLinuxでソフトウェアを配布してもらいたいなら、\n主要なLinuxディストリビューションでソフトウェアのパッケージ化を専門としているコミュニティメンバと協力したほうがいい。\n\n例として、chardetライブラリはDebian GNU/Linux リポジトリの中にある(従って、これはUbuntu リポジトリの中にもある)。このパッケージはある日突然姿を現した。\nDebianコミュニティはPythonライブラリをパッケージングする独自のポリシーを持っており、Debianのpython-chardetライブラリはこれらの慣習に従うように作られている。\nこのパッケージはDebianのリポジトリの中に存続しているので、\nコンピュータの管理のために選択したシステムの設定にもよるがDebianのユーザはセキュリティアップデートや新しいバージョンを受け取ることになる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## ソフトウェアをPython Package Indexに追加する"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "ソフトウェアを`Python Package Index` にアップデートするプロセスには3つのステップがある。\n\n1. アカウントを作成する\n2. ソフトウェアを登録する\n3. `setup.py sdist` と `setup.py bdist_*`で作成したパッケージをアップロードする。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "アカウントを作成するためにPyPI [ユーザ登録ページ](https://pypi.python.org/pypi?:action=register_form) へ行く。\n希望のユーザ名、パスワード、有効な電子メールアドレスを入力し、\nRegisterボタンをクリックしよう(pgpキーやgpgキーを提供することもできる。これらを持っていなかったり、\nこれらの意味が分からなくても、心配は要らない)。\nPyPIから数分以内に、メールアドレスを検証するためのリンクが書かれている電子メールが届くはずなのでそれを確認。登録処理を完了させるためにそのリンクをクリック。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "今度は、ソフトウェアをPyPIに登録し、それをアップロードする必要がある。\nこれは1つのステップですべて実行できる。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "```\nc:\\Users\\pilgrim\\chardet> c:\\python31\\python.exe setup.py register sdist bdist_wininst upload 1\nrunning register\nWe need to know who you are, so please choose either:\n 1. use your existing login,\n 2. register as a new user,\n 3. have the server generate a new password for you (and email it to you), or\n 4. quit\nYour selection [default 1]: 1 2\nUsername: MarkPilgrim 3\nPassword:\nRegistering chardet to http://pypi.python.org/pypi 4\nServer response (200): OK\nrunning sdist 5\n... output trimmed for brevity ...\nrunning bdist_wininst 6\n... output trimmed for brevity ...\nrunning upload 7\nSubmitting dist\\chardet-1.0.2.zip to http://pypi.python.org/pypi\nServer response (200): OK\nSubmitting dist\\chardet-1.0.2.win32.exe to http://pypi.python.org/pypi\nServer response (200): OK\nI can store your PyPI login so future submissions will be faster.\n(the login will be stored in c:\\home\\.pypirc)\nSave your login (y/N)?n 8\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "1. プロジェクトを初めてリリースするときは、DistutilsがソフトウェアをPython Package Indexに追加し、それに専用のurlを与える。それ以降の場合は、プロジェクトのメタデータを、変更されたsetup.pyのパラメータへと更新するだけだ。次に、ソースディストリビューションの構築 (sdist) と、Windowsインストーラの構築 (bdist_wininst) を行って、それらをPyPIにアップロードする (upload)。\n\n2. “use your existing login.” を選択するために、1と入力してENTERキーを押そう。\n\n3. PyPIユーザ登録ページで入力したユーザ名とパスワードを入力しよう。Distuilsは入力したパスワードをエコーしないし、文字の代わりにアスタリスクをエコーすることもない。パスワードを入力してENTERを押そう。\n\n4. DistutilsはパッケージをPython Package Indexに登録し……\n\n5. ……ソースディストリビューションを構築し……\n\n6.\t……Windows用インストーラを構築し……\n\n7. ……そして、これら両方をPython Package Indexにアップロードする。\n\n8. もし新しいバージョンのリリース処理を自動化したいのであれば、PyPIの証明書をローカルファイルに保存しておく必要がある。これはまったくセキュアではないので、まったく任意だ。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "これで、Python Package Indexにパッケージのページを手に入れた.\nアドレスは http://pypi.python.org/pypi/NAME になる。\n(NAMEにはsetup.pyファイルのnameパラメータに渡した文字列が入る)。"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "新しいバージョンをリリースしたいときは、\n`setup.py` を単に新しいバージョン番号で更新して、\n同じアップロードコマンドを再び実行する:\n\n```\nc:\\Users\\pilgrim\\chardet> c:\\python31\\python.exe setup.py register sdist bdist_wininst upload\n```"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "## 参考リンク"
},
{
"metadata": {},
"cell_type": "markdown",
"source": "- [Dive Into Python3 16章 Pythonライブラリをパッケージ化する](http://diveintopython3-ja.rdy.jp/packaging.html)\n- [distutils — Python モジュールの構築とインストール python doc](http://docs.python.jp/3.5/library/distutils.html)"
}
],
"metadata": {
"toc": {
"toc_window_display": false,
"toc_cell": true,
"toc_number_sections": true,
"toc_threshold": "6"
},
"language_info": {
"name": "python",
"file_extension": ".py",
"mimetype": "text/x-python",
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"version": "3.5.1",
"codemirror_mode": {
"name": "ipython",
"version": 3
}
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3",
"language": "python"
},
"gist": {
"id": "",
"data": {
"description": "Dive Into Python3 16章メモ(Pythonライブラリをパッケージ化する)",
"public": true
}
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment