よちよちpython

独習 python/Qpython/Pydroid3/termux

【fire】楽チン!コマンドライン引数の自動設定ライブラリのテスト

コマンドライン引数を簡単に設定してくれるというPython用ライブラリfireを試します。

$ pip install fire

など環境に合わせて先にインストールしておきます。



【実行環境】



コマンドライン引数をプログラムに渡したいとき、通常はsys.argvargparse()を使いますが、fireを使うともっと簡単にできるらしい。本当かしら?



Pythonスクリプトを準備

引数を受けると、引数・引数の型・引数の要素数を返すプログラムを準備しました。コマンドライン引数については何の考慮もなしです。

testfire.py

# ライブラリのインポート
import fire

# 関数の定義
def test(x):
    return x,type(x),len(x)

# ファイヤー!
fire.Fire(test)

電流爆破を起こすプログラムです(ウソ
定義した関数やクラスを、Fire()に渡すたけでコマンドライン引数が自動的に使えるようになるのだと。

  • コマンドライン引数を関数に渡すような文は一行も書いてません。
  • インポートしたfireのFireクラスにそのまま関数名を渡しただけ

実行したら「引数・引数の型・引数の要素数」が表示される筈。
こんなので本当に動くのかいな?



実行

してみます。

$ python firetest.py wwwwww
('wwwwww', <class 'str'>, 6)

動くねぇ。



今度は引数を2つ渡してみよう

$ python firetest.py hello world 666
ERROR: Unable to index into component with argument: world
Usage: firetest.py hellow <command|index>
  available commands:    count | index
  available indexes:     0, 1, 2

For detailed information on this command, run:
  firetest.py hellow --help

エラーと表示された。詳細はヘルプでと。



ヘルプのオプション引数を見てみる

自動でヘルプのオプションを用意してくれている。親切。
通常ヘルプは「--help」か「-h」で出る。

$ python firetest.py --help
NAME
    firetest.py

SYNOPSIS
    firetest.py X

POSITIONAL ARGUMENTS
    X

NOTES
    You can also use flags syntax for POSITIONAL ARGUMENTS

スクリプトに「x」と書いていたので1つしか受けないみたい。



可変長の引数に書き換え

てみようか。

firetest.py

# ライブラリのインポート
import fire

# 関数の定義
def test(*x):  #←「*」追加で可変長に
    return x, type(x), len(x)

# ファイヤー!
fire.Fire(test)

実行します。

$ python firetest.py hello world 666
(('hellow', 'world', 666), <class 'tuple'>, 3)

行けたね。タプル型。ファイル自身は含まず。



ヘルプを見てみると、

$ python firetest.py --help

NAME
    firetest.py

SYNOPSIS
    firetest.py [X]...

POSITIONAL ARGUMENTS
    X

自動的にヘルプも作られる。
関数の引数を「*」で可変長にしたのでSYNOPSISの部分がXから[X]に変わった。器がでかくなった。



CLIツールにして実行を確かめる

自作Pythonスクリプトをコマンド1発で動かせるCLIツールにして、動くかどうか確認してみる。
まずはCLIツール用にスクリプトを書き替えます。実行部分を関数化します。

firetest.py

import fire

def test(*x):
    return x,type(x),len(x)

# 実行部分を関数化した
def main():
    fire.Fire(test)


if __name__=='__main__':
    main()

CLIツール化の時に作るsetup.pyで呼び出す関数名を指定する必要があるので、main()で関数化しました。


そして、setup.pyを用意します。

from setuptools import setup

setup(
    name="fire_test",  #パッケージ名
    version="0.0.1", #パッケージバージョン
    install_requires=["fire"], #必要なライブラリ
    entry_points={
        "console_scripts": [
            "firetest = firetest:main" #コマンド名=呼び出すファイル名:関数名
        ]
    }
)

フォルダを作って、上の2つのファイルをそこに閉じ込めます。

$ mkdir TEST  ← フォルダ作成
$ mv firetest.py setup.py TEST/ ←ファイルを移動
$ cd TEST  ←カレントディレクトリを移動
$ ls ←ディレクトリ内容を確認
firetest.py setup.py
$ tree ←ディレクトリ構成表示
.
├── firetest.py
└── setup.py

0 directories, 2 files

準備ができたのでCLIツール化します。

$ python setup.py develop
または
$ pip install -e .

Obtaining file:///なんとか/firetest
Requirement already satisfied: fire in /なんとか/usr/lib/python3.9/site-packages (from fire-test==0.0.1) (0.4.0)
Requirement already satisfied: termcolor in /なんとか/usr/lib/python3.9/site-packages (from fire->fire-test==0.0.1) (1.1.0)
Requirement already satisfied: six in /なんとか/usr/lib/python3.9/site-packages (from fire->fire-test==0.0.1) (1.15.0)
Installing collected packages: fire-test
  Running setup.py develop for fire-test
Successfully installed fire-test

pip listコマンドで自作スクリプトがインストールされたか確認できます。また、カレントディレクトリにfire_test.egg-info/が自動作成されています。



CLIツールの実行確認

できたコマンドを実行します。setup.py"console_scripts":で指定したコマンド名を使えるようになっています。

コマンドだけ入力してみる。

$ firetest
((), <class 'tuple'>, 0)

ヘルプを表示。

$ firetest --help
NAME
    firetest

SYNOPSIS
    firetest [X]...

POSITIONAL ARGUMENTS
    X

コマンドライン引数を1つ与える。

$ firetest ファイヤー
(('ファイヤー',), <class 'tuple'>, 1)

次は2つ。

$ firetest なんでん かんでん
(('なんでん', 'かんでん'), <class 'tuple'>, 2)

ちゃんと動くね。🆗👌



CLIツールのアンインストール

  • 呼び出すファイル(firetest.py)だけを書き換える場合はアンインストールせずとも変更が反映されますが、
  • setup.py側のコマンド名や呼び出すファイル名、関数名を内容変更する場合は一旦アンインストールする必要がある。(アップデートで行けるかも。未確認)


setup.pyを置いたディレクトリ(この場合TEST)で以下のコマンド。

$ pip uninstall fire-test
または
$ python setup.py develop -u
なんとかかんとか
Successfully uninstalled fire-test

と出ればアンインストール完了。
カレントディレクトリに自動作成されたフォルダはアンインストール後は不要なので、削除するなら

$ rm -rf fire_test.egg-info __pychash__

これで中身のファイルごと削除される。
【注意】
実行してはいけないLinuxコマンド(3) Windows 10 WSLで『rm -rf /』を実行 | TECH+



改造

次のように改造して動くか確認する。

firetest.py

import fire

def test(*x):
    return x,type(x),len(x)

fire.Fire(test)

main()を削除した。

setup.py

from setuptools import setup

setup(
    name="fire_test",
    version="0.0.1",
    install_requires=["fire"],
    entry_points={
        "console_scripts": [
            "firetest = firetest:test" #←mainをtestに変更
        ]
    }
)

呼び出す関数をmain()からtest()に変更した。setup.pyを書き換えたので一旦アンインストールした。
先ほどのインストール手順で再インストールし直し実行確認してみる。

$ firetest ggg hhh
(('ggg', 'hhh'), <class 'tuple'>, 2)
((), <class 'tuple'>, 0)

二度実行されています。
firetest.pyfire.Fire(test)コメントアウトすると実行結果は((), <class 'tuple'>, 0)だけが表示される。

またアンインストールし、次は複数の関数でできるか確認します。



複数の関数で確認

ここからはCLIツールのコマンド化はしません。firetest.pyのみを使う。
次のように書き換える。

import fire

def test(*x):
    return x,type(x),len(x)

def test2_rev(*y):
    return [i[::-1] for i in y]

# 実行
fire.Fire(test)
fire.Fire(test2_rev)

関数を2つ作って、fire.Fire()で2つ実行させるようにしました。

$ python firetest.py 上から読んでも 下から読んでも やまもとや

(('上から読んでも', '下から読んでも', 'やまもとやま'), <class 'tuple'>, 3)
もでん読らか上
もでん読らか下
まやともまや

ヘルプを表示

$ python firetest.py --help
NAME
    firetest.py

SYNOPSIS
    firetest.py [X]...

POSITIONAL ARGUMENTS
    X

1つ目の関数しか出ていない。



まるごと読み込む

fire.Fire()に何も渡さなければ丸ごと読み込まれるらしい。大泥棒か

firetest.py

import fire

def test(*x):
    return x,type(x),len(x)

def test2_rev(*y):
    return [i[::-1] for i in y]

fire.Fire()  #←何も書かない

ヘルプを見てみる。

$ python firetest.py --help
NAME
    firetest.py

SYNOPSIS
    firetest.py GROUP | COMMAND

GROUPS
    GROUP is one of the following:

     fire
       The Python Fire module.

COMMANDS
    COMMAND is one of the following:

     test

     test2_rev

変数の表示とかがされなくなったな。どこ行った。



コマンドライン引数を与える実行してみる。

$ python firetest.py hello
ERROR: Cannot find key: hello
Usage: firetest.py <group|command>
  available groups:      fire
  available commands:    test | test2_rev

For detailed information on this command, run:
  firetest.py --help

おっと、普通に実行出来なくなった。上のヘルプ表示の「Usage」に使い方が、「available commands:」に2つ関数名が載っている。
使い方のように引数で渡すと実行できるようだ。

$ python firetest.py test2_rev hello
olleh

オレッ!

他のでも

$ python firetest.py test2_rev 吾輩は猫である トンネルを抜けるとそこは雪国だった ここが何処だかとんと見当が付かぬ

るあで猫は輩吾
たっだ国雪はこそとるけ抜をルネント
ぬか付が当見とんとかだ処何がここ

ぬか漬けがどうのこうの。イケるねぇ(by 中尾彬



参考リンク


こちらにはclassを使う場合など例文がいくつか載っている。

おわりに

ファイルの最後の実行部分に「fire.Fire()」を付けるだけなので相当楽チンかも。



以上です。