読者です 読者をやめる 読者になる 読者になる

カイワレの大冒険 Third

技術的なことや他愛もないことをたまに書いてます

pypiにパッケージを登録して、setup.pyの「scripts」と「console_scripts」の違いを比較してみた

プログラミング プログラミング-Python

みなさま、Pythonのパッケージ化はしたことありますでしょうか?最近以下のような記事を書きましたが、ツールを作ったものの、それを配布しようとなると、Pythonのパッケージ化に関して分からないことがあり、pypiにパッケージを登録して試してみました。

これらの記事を書いたときの自分の考えは以下のとおりです。

  • pip install -e .してコマンドにパス通すの、微妙すぎる
  • setup.pyで、scriptsなりconsole_scriptsを使えば、コマンドが/usr/bin配下にインストールされパスを通すことができるので、どちらかでやったほうがいい
  • 前者であればmain関数を用意せずとも、ファイル名を書くだけなので、そのほうが楽だと思える

コマンドにパスを通すという観点で、このような内容を書きました。

しかしながら、その後コメントにあるように、パッケージ化することを考えるなら、console_scriptsのほうがよいのではというご意見を頂き、実際どうなのだろうと思ったのです。

ということで、pypiに登録してみました。レポジトリは以下。

2つの差異はsetup.pyの記述だけです。 前者はこんな感じ。

      entry_points={
          'console_scripts': ['justHello = bin.justHello:main']
      },

bin配下をモジュール化して、main関数(名前はなんでもいい)として登録する必要があります。

後者はこんな感じ。

      scripts=['bin/justHello2'],

ファイル名をそのまま書くだけですね。

ちなみにbin以下のファイルはこんな感じのスクリプトになってます。

def main():
    print('Hello World')


if __name__ == '__main__':
    main()

シェバンも書かず、main関数があるのみです。 では、パッケージインストール後の変化を見てみましょう。

console_scripts

console_scriptsを使ったものをpipで入れるとこんな感じになります。

# pip install justHello
Downloading/unpacking justHello
  Downloading justHello-0.0.19.tar.gz
  Running setup.py egg_info for package justHello
Installing collected packages: justHello
  Running setup.py install for justHello
    Installing justHello script to /usr/bin
Successfully installed justHello
Cleaning up...

/usr/bin以下にちゃんと入りますね。 次に、インストールされたコマンドを見ましょう。

#!/usr/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'justHello==0.0.19','console_scripts','justHello'
__requires__ = 'justHello==0.0.19'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('justHello==0.0.19', 'console_scripts', 'justHello')()
    )

見事にシェバンが追加されて、load_entry_point関数で、いい感じで読み込んでくれています。

scripts

まずインストールのログ。

# pip install justHello2
Downloading/unpacking justHello2
  Downloading justHello2-0.0.2.tar.gz
  Running setup.py egg_info for package justHello2
Installing collected packages: justHello2
  Running setup.py install for justHello2
    changing mode of build/scripts-2.6/justHello2 from 644 to 755
    changing mode of /usr/bin/justHello2 to 755
Successfully installed justHello2
Cleaning up...

/usr/bin以下にインストールだけではなくて、パーミッションも変わってますね。 となると、console_scriptsでは、パーミッション変えてくれないのでしょうか。

$ ll /usr/bin/justHello*
-rwxr-xr-x 1 root root 314  1月 29 22:12 2015 /usr/bin/justHello
-rwxr-xr-x 1 root root  77  1月 29 22:12 2015 /usr/bin/justHello2

そういうわけではないようです。となると、そこまで大きな変化はないかもしれません。

次にbin以下のファイルを見てみましょう。

def main():
    print('Hello World')


if __name__ == '__main__':
    main()

まんまですね。シェバンもなく、そのままのコードが置かれてます。 importとかあった場合に、モジュールのパスがどこを基準に書かれているか初めて見た人は混乱するかと。 また、そのままということはシェバンを書いたままパッケージ化してしまうと、そのシェバンに従ってインタープリタが固定されてしまいます。 自分の環境では/usr/bin/python3を指定して動かしていたから、そのままパッケージ化してしまったとすると、利用者の環境では動かない可能性も出てくるわけです。

「ロジックが入る」という表現をコメントでされたのですが、要はこのように処理がそのまま書かれているという状態なのですね。

終わりに

ここまで書いたとおりではありますが、console_scriptのほうが綺麗ではありますね。ただ、main関数のように一つにまとめて、それをsetup.pyで指定しなければいけないなど、ほんのほんのちょっとだけ気を遣う必要があります。まぁ、最初からそう書いておけば問題無いですし、移行するにしても、そこまでの労力ではないでしょう。

と、実際にレポジトリに登録して、試してみました。コメントでご助言頂いたこうへいさんほんとにありがとうございました!!