インストール可能な Python パッケージを作るには、セットアップスクリプト (setup.py) と呼ばれるファイルを用意する。
セットアップスクリプトは以下のように用いる。 <command> にはパッケージのインストールに使う install やソースコード配布物を生成する sdist などがある。
$ python setup.py <command>
今回はそのセットアップスクリプトに自作のコマンドを追加する方法について書いてみる。 尚、環境には setuptools というパッケージが入っていることを前提にする。 これはサードパーティ製のパッケージだけど、Python のパッケージング用ライブラリとしてはデファクトスタンダードになっているもの。
自作パッケージにコマンドを追加する
まずは自作パッケージに対してコマンドを追加する方法について書いていく。
mysetupcmd という名前でパッケージを作ってみる。 中身は空っぽだけど __init__.py があるため、これでも立派な Python パッケージになる。
$ mkdir mysetupcmd $ touch mysetupcmd/__init__.py
上記のパッケージに対してセットアップスクリプトを書く。 ポイントは setuptools.set() に対して cmdclass というパラメータを渡しているところ。 ここに setuptools.Command を継承したクラスを渡すことでコマンドが追加できる。
$ cat << EOF > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup from setuptools import Command class GreetCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): print('Hello, World!') def main(): setup( name='mysetupcmd', version='0.0.1', zip_safe=False, packages=['mysetupcmd'], cmdclass={'greet': GreetCommand}, ) if __name__ == '__main__': main() EOF
これでセットアップスクリプトに greet というコマンドが追加できた。 早速実行してみよう。
$ python setup.py greet running greet Hello, World!
上手いこと greet コマンドで GreetCommand#run() の内容が実行された。
追加したコマンドで引数を受け取る
今度は上記のコマンドに引数を取れるようにしてみよう。 user_options に取れるようにしたい引数を設定しておくと、自動的に同名のメンバとしてアクセスできるようになる。 また、initialize_options/finalize_options() メソッドでは引数のデフォルト値などが設定できる。
$ cat << EOF > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup from setuptools import Command class GreetCommand(Command): user_options = [ ('message=', None, 'output message'), ] def initialize_options(self): self.message = 'Hello, World!' def finalize_options(self): pass def run(self): print(self.message) def main(): setup( name='mysetupcmd', version='0.0.1', zip_safe=False, packages=['mysetupcmd'], cmdclass={'greet': GreetCommand}, ) if __name__ == '__main__': main() EOF
オプションを追加すると --help オプションに詳細が表示されるようになる。 今気づいたけど、ここの表示はクラス名がそのまま出るんだね…。 クラス名はコマンド名と揃えたほうが良さそうかな。
$ python setup.py greet --help Common commands: (see '--help-commands' for more) setup.py build will build the package underneath 'build/' setup.py install will install the package Global options: --verbose (-v) run verbosely (default) --quiet (-q) run quietly (turns verbosity off) --dry-run (-n) don't actually do anything --help (-h) show detailed help message --no-user-cfg ignore pydistutils.cfg in your home directory Options for 'GreetCommand' command: --message output message usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help
これで greet コマンドが --message オプションを受け取れるようになる。
$ python setup.py greet --message='I am a pen!'
running greet
I am a pen!
オプションの指定がない場合は initialize_options() メソッドで指定したデフォルト値のまま。
$ python setup.py greet running greet Hello, World!
コマンドをインストールする
さて、これまでのやり方ではパッケージ内でしかコマンドが有効ではなかった。 次は自作のコマンドを Python 実行環境にインストールすることで、どのパッケージのセットアップスクリプトでも使えるようにしてみる。
まずは mysetupcmd パッケージに先ほど作成した GreetCommand クラスを移動する。
$ cat << EOF > mysetupcmd/cmd.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import Command class GreetCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): print('Hello, World!') EOF
そしてセットアップスクリプトでは entry_points オプションの distutils.commands にコマンド名と上記のクラスを指定する。
$ cat << EOF > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup def main(): setup( name='mysetupcmd', version='0.0.1', zip_safe=False, packages=['mysetupcmd'], entry_points={ 'distutils.commands': [ 'greet = mysetupcmd.cmd:GreetCommand', ], } ) if __name__ == '__main__': main() EOF
この状態では cmdclass に指定がないため、自身のパッケージでも自作のコマンドは使えない。
$ python setup.py greet usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help error: invalid command 'greet'
では次に、セットアップスクリプトを使って Python 実行環境に mysetupcmd パッケージをインストールしよう。
$ python setup.py install ...(省略)... Finished processing dependencies for mysetupcmd==0.0.1
これで mysetupcmd パッケージが入った。
$ pip list | grep ^mysetupcmd mysetupcmd (0.0.1)
すると greet コマンドがセットアップスクリプトで使えるようになる。 もちろん、これはインストールされた mysetupcmd パッケージの効果なので、別のプロジェクトのセットアップスクリプトでも有効になる。
$ python setup.py greet running greet Hello, World!
めでたしめでたし。
まとめ
今回はセットアップスクリプトに自作のコマンドを追加する方法について書いた。 紹介した内容はほんのさわりだけど、応用例としてはセットアップスクリプト経由でパッケージのソースコードに対してツールを実行できるようにするといったことが考えられる。
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る