「PyWebIO」があればPython 100%でWebアプリ作れるってマジ！？

# TL; NR

[PyWebIO](https://pywebio.readthedocs.io/en/latest/)っていう、Pythonユーザ向けでけっこうイケてる(死語)Webアプリケーションフレームワークを発見した。(正確にはスタックオーバーフローの[コメント](https://ja.stackoverflow.com/questions/77996/python-%e3%81%a7-%e3%81%82%e3%82%8bweb%e3%82%a2%e3%83%97%e3%83%aa%e3%82%92%e6%97%a9%e3%81%8f%e4%bd%9c%e3%82%8b%e5%bf%85%e8%a6%81%e3%81%8c%e3%81%82%e3%82%8b%e6%99%82%e3%81%ae-%e3%81%8a%e5%8b%a7%e3%82%81%e3%81%ae%e3%83%a9%e3%82%a4%e3%83%96%e3%83%a9%e3%83%aa%e3%81%ae%e7%b5%84%e3%81%bf%e5%90%88%e3%82%8f%e3%81%9b%e3%81%af%e3%81%82%e3%82%8b%e3%81%a7%e3%81%97%e3%82%87%e3%81%86%e3%81%8b#comment88283_77996)で知った)
なのに日本語の記事が全然見つからないからサンプルコード組んでみた。

結論から言うとタイトルはマジ。
Python大好きだけどHTMLやJavascriptを見ると血圧が上がったりバイタルサインが著しく低下する人もこれなら楽しく遊べそう。

個人的な印象としては込み入った複雑なレイアウトを作るのは大変そうだけど、[Bottle](https://bottlepy.org/docs/dev/)よりもスタートアップが楽。
[PySimpleGUI](https://pysimplegui.readthedocs.io/en/latest/)と同レベルかそれ以上の簡単さで作れるWebアプリは貴重なので頑張って進化してもらいたいと思いました。(CSSアレルギーおじさん並みの感想)

# インストール

Python 3.9 をインストール済みの Windows 10 とかで下記のとても複雑なコマンドを入力しないとインストールできない。
難しいけどここを乗り越えれば簡単にWebアプリを作ることができるから頑張って挑戦してみてね！

```
pip install pywebio
```

# コーディング

ほとんど全部が本家の[ユーザーズガイド](https://pywebio.readthedocs.io/en/latest/guide.html)からのオマージュだけどそれで要件は足りる。
1時間かけてコーディングして2時間かけて記事を書いた程度だから細かいことは何一つ分からない。
この記事はあくまでも**ファッションコーディング**だ。(今作った造語)
雰囲気だけつかんだら後は原典を読んでね。

## Hello world

限りなく頭の悪いHello worldを書くと2行で書ける。
BMIを計算して絶望したい人は公式サイトの[Hello world](https://pywebio.readthedocs.io/en/latest/index.html#hello-world)を参照。


```Python
from pywebio.output import put_text
put_text("こんにちは PyWebIO!")
```

ちなみに`Python 3.9.0`のノートパソコンではPowershellでもうまく行ったけど、おうちに帰って`3.6`で動かしたら`asyncio`の警告が出たり`3.9.6`にしてもPowershellコンソールからHello worldするとWeb画面にテキストが表示されなかったりした。
どちらもWindows 10でChromeを使用してるけど相性問題があるのかもしれない。

ここから下のスクリーンショットは`Python 3.9.6`で`PyWebIO.py`ってPythonファイルを作ったうえで動かしてChromeに出てきた画面で統一してる。

![2021-07-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/64276d09-d01d-7399-aa42-b4eb8023e7bc.png)

## Input

`input`など入力コントロールを配置すると**コントロールごとに**入力画面が生成される。
お手軽！

`put_text`を複数記述すると複数行まとめて出力できる。

```Python
from pywebio.input import input, PASSWORD, FLOAT
from pywebio.output import put_text, put_table

# 数値入力
number = input("1.2 + 0.5 =", type=FLOAT, placeholder='計算結果を入力', required=True)
# パスワード入力
password = input("パスワード入れてね", type=PASSWORD, help_text='助言は役に立たない')
# 出力
put_text(f"1.2 + 0.5 = {number}")
put_text(f"パスワードは{password}")
```

+ 数値入力と必須エラー

![2021-07-06 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/b990af9b-b740-03ca-5c0f-76d4fe64ec14.png)

+ パスワード入力とヘルプテキスト表示

![2021-07-06 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/df509971-9aa6-7826-8c23-526703e0d3db.png)

+ 出力

![2021-07-06 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/b763a7bc-c76b-85a2-26e3-3f67b6c4c928.png)


## Input GroupとかCombimed Outputとか

`input_group`や`put_table`を使うことで複数行列のコントロール配置が可能になる。
`file_upload`でファイル名やバイナリが取れる。
[`put_image`](https://pywebio.readthedocs.io/en/latest/output.html?highlight=put_image#pywebio.output.put_image)はURLやバイナリなどかなり柔軟にデータが取れそうでちょっと感動した。
詳しくは公式サイトの[ユーザーズガイド](https://pywebio.readthedocs.io/en/latest/guide.html)で。

ちなみにサーバを起動しない[スクリプトモード](https://pywebio.readthedocs.io/en/latest/guide.html#server-and-script-mode)だと`pywebio.session.hold`しておかないとスクリプトを最後まで読んだ時点でセッションが終了する。
そのため`hold()`しておかないとボタンクリックなどが実行できないため注意すること。

```Python
from pywebio.input import select, checkbox, radio, textarea, file_upload, input_group
from pywebio.output import put_markdown, put_table, put_buttons, put_image
from pywebio.session import hold

result = input_group("入力グループ", [
             select('どっちが好き', ['きのこ', 'たけのこ'], name="war"),
             checkbox("チェックボックス", options=['私は今Qiitaを読んでいます'], name="agree"),
             radio("1 + 1 =", options=['2', '11', '田'], name="answer"),
             textarea('Text Area', rows=3, placeholder='Some text', name="text"),
             file_upload("Select a image:", accept="image/*", name="img")
            ])

## 結果表示
put_table([
           ["1行目は", "タイトル"],
           ["好きなもの", result["war"]],
           ["あなたは", "正直者" if result["agree"] else "嘘つき"],
           ["1 + 1 =", result["answer"]],
           ["Text Area", result["text"]],
           ["画像データ", result["img"]],
           ["Image", put_image(result["img"]["content"])],
           ["コントロール", put_buttons(["置ける"], onclick=lambda _:put_markdown("残念。**はずれ**です！"))]
          ])

hold()  # これを記述しないとボタンイベント読込前にセッションが終了してしまう
```

+ Input Group

![2021-07-06 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/12aa82b7-e50f-67d4-42ab-004a0cf092ce.png)

+ Combimed Output

![2021-07-06 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/bfc4ba17-8d67-80a8-d466-afe24269b0e3.png)

## Server mode

サーバを立ち上げるには`start_server`する。
画面遷移は`go_app`または`put_link`で記述できる。

微ハマりした点は`start_server`の第一引数の配列に遷移用のメソッドを記述しないと遷移してくれなかったこと

```Python
from pywebio.output import put_text, put_buttons, put_link
from pywebio.session import hold, go_app
from pywebio.platform.tornado import start_server

def task_1():
    put_text('乳酸菌摂ってるぅ？')
    put_link('摂ってる(Endingへ行け)', app='ending')
    put_text('')  # put_link で inline=False 的に改行する方法が分からなかったので…
    put_link('摂ってない(14へ行け)', app='task_14')

def ending():
    put_text('おめでとう！\nあなたは健康になった！')
    put_buttons(['スタートに戻る'], [lambda: go_app('index', new_window=False)])
    hold()

def task_14():
    put_text('ざんねん！\nあなたのぼうけんはここでおわってしまった！')
    put_buttons(['スタートに戻る'], [lambda: go_app('index', new_window=False)])
    hold()

def index():
    put_text('まきますか？まきませんか？')
    put_link('まきます(1へ行け)', app='task_1')
    put_text('')  # put_link で inline=False 的に改行する方法が分からなかったので…
    put_link('まきません(14へ行け)', app='task_14')

# 第一引数の配列に遷移用のメソッドを記述しないと遷移してくれないので注意
start_server([index, task_1, ending, task_14], port=8080)
```

+ スタート画面(http://localhost:8080)

![2021-07-06 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/f641596f-3dad-8736-9803-92dba4f09930.png)

+ まきません

![2021-07-06 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81851/a2dda1ad-3d3f-7077-e790-90877939b14a.png)


# 総括

冒頭に書いた通り**python以外は1行も書かない縛り**でかなり楽にリッチなWebアプリケーションを作ることができるフレームワークだ。
すごく簡単なWebアプリを作りたいけど絶対にHTML書きたくないマンには良質な選択肢だと思う。
ブートストラップとかDBバインディングには[Django](https://www.djangoproject.com/)とかの方が便利かもしれないけどそれはそれ。

PyWebIOをお試しするとサクサク書けて**楽しいからぜひどうぞ**。

P.S. 素でQiita投稿は初めてです。優しくしてくれると嬉しいです。
PS2. たくさんのLGTMありがとうございます。 とても嬉しいです。