よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

自作Pythonプログラムを超簡単にCLIツールにする方法

自作のPythonプログラムを簡単にCLIツールにしてみます。これは便利。



目次




CLIツールってなに?


CLIとはコマンド・ライン・インターフェースの略です。短いコマンドを入力することでプログラムを呼び出して実行できるようにしてあるものを指してCLIツールと呼ぶようです。

Python関係のコマンドならpython ファイル名pip listpip install ライブラリ名Python初心者が最初に覚えるコマンドです。
OSのシステムコマンドならdirlsmkdirなど。
CLIツールはカレントディレクトリに関係なく、いつでも何処からでもショートカットで実行できます。



今回のでできること


難しいことは一切しません(能力的にできない)。面倒な設定もしません。ネット上にファイルをアップしたりもしません。

  • 自作PythonプログラムをCLIツールにします。
  • 動作等の確認。
  • 自作CLIツールのアンインストール。



今回用意するファイルは2つ


  • 自作Pythonプログラムファイル(test.py)
  • CLIツールにする為のファイル(setup.py)



ディレクトリ構成 (ファイルの保存場所)


2つのファイルを作りますが、下記のような構成にします。


$ tree

myapp
.
├── test.py (自作プログラム)
└── setup.py (セットアップ用)

0 directories, 2 files

myappというフォルダを作って、その中に2つのファイルを作ります。



作成


フォルダの作成

作業用のフォルダを作ります。
フォルダの名前は何でも構いませんが、myappにしておきます。
フォルダは何処に作っても構いません。右クリックででもコマンドででも何でも好きな方法で。

$ mkdir myapp  # フォルダ作成
$ cd myapp     # フォルダへ移動



ファイル作成 (1/2 test.py)


Pythonプログラムファイルを作ります。コマンドラインツールなので、せっかくなのでコマンドライン引数を使うものを作ります。

import sys

def ggg():
    # コマンドライン引数(2つ目以降を取得
    x=sys.argv[1:]
    print("値",x)
    print("型",type(x))
    
if __name__=='__main__':
    ggg()

コマンドライン引数を出力するだけのプログラム。

一応動作を確認します。

$ python test.py hello world !
値 ['hello', 'world', '!']
型 <class 'list'>

コマンドライン引数はスペース区切りで要素になったリストを返します。



ファイル作成 (2/2 setup.py)


上記のプログラムをCLIツールにする為のファイルを作ります。



setup.pyの書き方は、本来はもっといろいろと書くべきのようですが、今回は動作確認のみで最小限で行きます。

from setuptools import setup

setup(
        install_requires=[],#'sys' 
        entry_points={
            "console_scripts":[
                "myapp = test:ggg"
            ]
        }
)
  • install_requires

    • importしている依存ライブラリをリストで羅列する
    • "sys"を書くとエラーになるので外した。必要ないみたい
  • "console_scripts"

    • 「myapp」 : コマンド名
    • 「test:ggg」 : test.pyのggg()を実行する

これをセットアップすると、test.pyのggg()関数が実行されるCLIツール「myapp」ができます。
コマンド名を作業フォルダ名と同じにしていますが、書き換えれば好きなように変更できます。



ファイル確認

$ ls myapp/

setup.py test.py

2つのファイルが揃いました。



自作プログラムをインストールする


この段階で早くも自作プログラムがインストールできる。あっけなくCLIツールができてしまいます。
二通りの方法を書いておきます。

インストール方法1

「setup.py」を保存しているディレクトリに移動する。
ずっとmyappで作業しているのでこれはいいですね。

カレントディレクトリ確認コマンド

$ pwd

なんとか/myappに居ればOK。



次のコマンドを打つとインストール。

$ python setup.py develop


running develop
running egg_info
creating UNKNOWN.egg-info
writing UNKNOWN.egg-info/PKG-INFO

なんちゃらかんちゃら

Processing dependencies for UNKNOWN==0.0.0
Finished processing dependencies for UNKNOWN==0.0.0

UNKNOWN==0.0.0という自作ライブラリが、どうやらインストールできたっぽい。



カレントディレクトリに追加されたもの


上記の方法で自作プログラムをインストールすると、カレントディレクトリに「UNKNOWN.egg-info」なるフォルダが追加されている。

$ tree

myapp
.
├── UNKNOWN.egg-info
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── entry_points.txt
│   └── top_level.txt
├── setup.py
└── test.py

1 directory, 7 files



pip list で確認する


$ pip list

インストール済みのライブラリに紛れて、

UNKNOWN 0.0.0 /なんちゃら/myapp

が追加されている。 これが今さっき作った自作プログラムらしい。



すぐにでもCLIツールを動かしたいなら、↓の方のできたCLIツールの動作確認まで読み飛ばしてください。



インストール方法2


次の方法でも同じようにあっけなくCLIツールができてしまいます。
作業フォルダ「myapp」に移動して、下記のコマンドを実行します。

$ pip install -e .


オプションの「e」は「editable」の略、最後の「.」は「カレントディレクトリ」を指す。

ローカルな環境で開発を行う際に使い、インストール後もファイル編集可能な状態になるetc。
install_requiresで指定した依存ライブラリを作業中のカレントディレクトリに引っ張ってくるのだとか。

【参考】
python - Pipenvのオプション`--editable`の意味を教えてください。 - スタック・オーバーフロー



PythonでサクッとCLIツールを作る - Qiita

Obtaining file:///なんとか/myapp                      Installing collected packages: UNKNOWN
  Running setup.py develop for UNKNOWN        Successfully installed UNKNOWN

同じようにインストールされる。



アンインストール方法


インストールしてCLIツールを作ったばかりだが、先にアンインストールの方法を書いておく。



「setup.py」のあるカレントディレクトリ「myapp」で、
インストールした時のコマンドに「-u」のオプションを付けるとアンインストールされる。

$ python setup.py develop -u


running develop
Removing /なんとか/usr/lib/python3.9/site-packages/UNKNOWN.egg-link (link to .)
Removing UNKNOWN 0.0.0 from easy-install.pth file



または、次の方法でもできる。
別のディレクトリからでも構わないが

pip uninstall UNKNOWN

追加された自作ライブラリを通常の方法でアンインストールする形。次のようなものが出てくる

Found existing installation: UNKNOWN 0.0.0
Uninstalling UNKNOWN-0.0.0:
  Would remove:
   
  なんとか/usr/lib/python3.9/site-packages/UNKNOWN.egg-link
Proceed (y/n)?

yを入力すると

Successfully uninstalled UNKNOWN-0.0.0

でアンインストールされた。



pip listコマンドを打つと、インストール済みライブラリのリストからUNKNOWN==0.0.0が消えていることが確認できる。



できたCLIツールの動作確認


「myapp」フォルダに「setup.py」を作りましたが、その中に
"console_scripts":["myapp = test:ggg"]
と書きましたので、コマンド名はmyappです。

また、「test.py」の「ggg()」はコマンドライン引数を表示する関数でした。


$ myapp コマンドライン引数 

という使い方。


$ myapp 5 6 7
値 ['5', '6', '7']
型 <class 'list'>

何処のディレクトリからでも同じように実行できます。



プログラムを改造する


インストールされたままの状態で、コマンド「myapp」が呼び出している「test.py」の「ggg()」関数を書き換えてみます。現在時刻を表示するプログラム。

from datetime import datetime

def ggg():
    print(datetime.now())

if __name__=='__main__':
    ggg()

書き換えたら、そのまま実行

$ myapp
2021-01-xx xx:xx:xx.534180

コマンドが呼び出しているファイルを書き換えても普通に動く。
インポートしたdatetimeライブラリについても設定等はノータッチ。



コマンド名や呼び出す関数を変更する

インストールした時に自動で「myapp」フォルダの中に「UNKNOWN.egg-info」というフォルダが追加されていました。その中に幾つかファイルが自動作成されています。


たとえばコマンド名を変更したいなら、 「entry_points.txt」の

[console_scripts]
myapp = test:ggg

の「myapp」を別の単語に変更すると、myappコマンドは直ちに無効となり、変更後のコマンド名が有効になる。

同様に、「test:ggg」のファイル名や関数名を書き換えれば別のものに置き換えられる。



参考


単刀直入に方法が書いてあります。

PythonでサクッとCLIツールを作る - Qiita]



Python 自作モジュールのパッケージ化 · GitHub



おわりに


かなり簡単にCLIツールを作ることができるのが今回わかった。
次はパッケージ名の「UNKNOWN」だとかの設定方法等を調べますかな。
以上です。



続き