LoginSignup
14
9

More than 1 year has passed since last update.

Pythonで対話式CLIツールを作る

Last updated at Posted at 2022-01-19

PythonでこんなCLIツールが実装できる
questionary.gif

上記のスクリプトはこちら
(questionary==1.10.0を使用)

import questionary

name = questionary.text('Name?').ask()
age = int(questionary.text('Age?').ask())
sex = questionary.select(
    'Sex?',
    choices=["Male", "Female"]
).ask()
if sex == "Male":
    print(f"Hello {name}! {age} years old gentleman!")
else:
    print(f"Hello {name}! {age} years old lady!")

使用例

テキスト入力

import questionary
name = questionary.text('Name?').ask()

デフォルト値を設定する

import questionary
name = questionary.text('Name?', default='My Default Name').ask()
print(name)

text-default.gif

clickのようにtype引数は使えない。
入力値を数値にしたい場合はint()float()でキャストする。
入力値のバリデーションを別途行う必要がある(後述)。

対話式に選択(単一)

import questionary
sex = questionary.select(
    'Sex?',
    choices=["Male", "Female"],
).ask()
print(sex)

select.gif

選択肢に表示する名前と実際の変数値を使い分ける

import questionary
from questionary import Choice

sex = questionary.select(
    'Sex?',
    choices=[
        Choice(title="Male", value=0),
        Choice(title="Female", value=1),
    ],
).ask()
print(sex)

select-use-choice.gif

デフォルト値を設定する

指定した値が選択された状態の対話モードになる

import questionary
sex = questionary.select(
    'Sex?',
    choices=["Male", "Female"],
    default="Female",
).ask()
print(sex)

select-default.gif

選択肢に連番を振る

use_shortcuts引数。

import questionary
sex = questionary.select(
    'Sex?',
    choices=["Male", "Female"],
    use_shortcuts=True
).ask()
print(sex)

例の場合、1キーまたは2キーを入力することで選択肢を移動することができる。
select-shortcut.gif

区切り線を設ける

import questionary
from questionary import Separator

sex = questionary.select(
    'Sex?',
    choices=[
        "Male",
        Separator("---"),
        "Female",
    ],
).ask()
print(sex)

select-delimiter.gif

無効な選択肢

import questionary
from questionary import Choice

sex = questionary.select(
    'Sex?',
    choices=[
        "Male",
        "Female",
        Choice(title="Disabled", disabled="Cannot use!")
    ],
).ask()
print(sex)

※動画は全て「↓キー」を押してます
select-disabled.gif

対話式に選択(複数)

import questionary
choiced_items = questionary.checkbox(
    "Select items.",
    choices=[
        'item1',
        'item2',
        'item3',
    ]
).ask()
print(choiced_items)

スペースキーで選択/解除
checkbox.gif

選択肢に表示する名前と実際の変数値を使い分ける

questionary.selectの場合と同様にquestionary.Choiceを使用

import questionary
from questionary import Choice

choiced_items = questionary.checkbox(
    "Select items.",
    choices=[
        Choice('item1', value=1),
        Choice('item2', value=2),
        Choice('item3', value=3),
    ]
).ask()
print(choiced_items)

checkbox-choice.gif

デフォルトで選択済みにする

item2を選択済みにする

import questionary
from questionary import Choice

choiced_items = questionary.checkbox(
    "Select items.",
    choices=[
        "item1",
        Choice("item2", checked=True),
        "item3",
    ]
).ask()
print(choiced_items)

checkbox-checked.gif

ファイルパス

import questionary

path = questionary.path(
    "What's the path to the projects version file?"
).ask()
print(path)

スラッシュキーで候補が表示される(すごい)。
タブキーで自動補完入力される(すごい)。
path.gif

Yes|No (真偽値)

import questionary

is_engineer = questionary.confirm('Are you engineer?').ask()
print(is_engineer)

confirm.gif

「No」を選ぶ場合「n」キーを押すだけで次へ進む。
confirm-no.gif

デフォルトをFalseにする

import questionary

is_engineer = questionary.confirm(
    'Are you engineer?',
    default=False
).ask()
print(is_engineer)

confirm-default-false.gif

その他

オートコンプリートなSelect

ローマ字表記の都道府県を入力するケースを考える。

都道府県一覧
prefectures.py
PREFECTURES = [
    "hokkaido",
    "aomori",
    "iwate",
    "miyagi",
    "akita",
    "yamagata",
    "fukushima",
    "ibaraki",
    "tochigi",
    "gunma",
    "saitama",
    "chiba",
    "tokyo",
    "kanagawa",
    "niigata",
    "toyama",
    "ishikawa",
    "fukui",
    "yamanashi",
    "nagano",
    "gifu",
    "shizuoka",
    "aichi",
    "mie",
    "shiga",
    "kyoto",
    "osaka",
    "hyogo",
    "nara",
    "wakayama",
    "tottori",
    "shimane",
    "okayama",
    "hiroshima",
    "yamaguchi",
    "tokushima",
    "kagawa",
    "ehime",
    "kochi",
    "fukuoka",
    "saga",
    "nagasaki",
    "kumamoto",
    "oita",
    "miyazaki",
    "kagoshima",
    "okinawa",
]

import questionary
from prefectures import PREFECTURES

prefecture = questionary.autocomplete(
    "お住まいの都道府県は?",
    choices=PREFECTURES
).ask()
print(prefecture)

(エディタのカラーテーマとの相性で見づらい・・・)
autocomplete.gif

入力値バリデーション

入力値が整数であることを検証する例。

import questionary
from questionary import Validator, ValidationError

class IntegerValidator(Validator):
    def validate(self, document):
        try:
            int(document.text)
        except:
            raise ValidationError(
                message=f"{document.text} is not valid integer.",
                cursor_position=len(document.text)
            )

age = questionary.text("Age?", validate=IntegerValidator).ask()
print(age)

integer-validator.gif

プロンプトを動的に分岐

import questionary

sex = questionary.select(
    "Sex?",
    choices=["Male", "Female"]
).ask()
is_male = sex == "Male"

questionary.text(
    "女性の方にお聞きします。愛用する化粧品を教えてください:"
).skip_if(is_male).ask()

skip-if.gif

14
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
9