nikkie-ftnextの日記

イベントレポートや読書メモを発信

Phoenixアプリをドキュメントの「Deploying with Releases」に沿って動かす

はじめに

24!...不死...フェニックス!、nikkieです(引用はラ!サ!!より)。

WEB+DB PRESS vol.127の特集で知ったPhoenixmix releaseして開発マシンで動かすのを試しました。
ドキュメントを参照しつつもハマりながらとなったので、備忘録として記事を残します。

ElixirやPhoenixは完全理解よりも手前のレベルです(入門すらこれから)。
誤りやよりよいやり方にお気付きの場合はTwitter @ftnextまで教えていただけると大変助かります。

目次

WEB+DB PRESS Vol.127のPhoenix特集

2022年2月発売の号には、ElixirとPhoenixでWebアプリケーションを作る特集があります(特集2)。

ソースコードはこちら:

詳細は WEB+DB PRESS Vol.127の「作って学ぶPhoenix」で手を動かすために、Elixirの環境を構築する(macOS) #wdpress - nikkie-ftnextの日記 をご覧ください。

この記事ではmix releaseコマンドは登場しないようなのですが、どう動かすのが気になったのでドキュメントに当たりながら取り組みました。

環境

先ほども引いたこちらの記事で作ったElixirの環境で進めます。

$ docker --version
Docker version 20.10.13, build a224086

$ mix --version
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Mix 1.13.4 (compiled with Erlang/OTP 22)

$ mix phx.new --version
Phoenix installer v1.6.7

DB起動(docker利用)

WEB+DB PRESS Vol.127を参考に、Phoenixのアプリが接続するDB(PostgreSQL)をDockerを使って用意しました。

このイメージはrunするときに環境変数を指定してDBを初期設定できます(「Environment Variables」参照)。

  • POSTGRES_PASSWORD(必須)
  • POSTGRES_USER
  • POSTGRES_DB
docker run --rm --name phoenix-postgres -p 5432:5432 \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=hello_dev \
  postgres:13

(DB接続のデバッグでログが見たかったので-dを指定していません)

なお、後述のmix phx.new--no-ectoを渡してDB接続を不要にする方法もあると思います1

Phoenixのインストール

WEB+DB PRESS Vol.127で案内されています。
また、Installation — Phoenix v1.6.7も参照しました。

# Hexのインストール(インストール済みの場合は最新のバージョンにアップグレード)
mix local.hex
# Phoenix(のアプリケーションジェネレータ)のインストール
mix archive.install hex phx_new

開発用サーバで動かす🚀

WEB+DB PRESSからは離れ、Up and Running — Phoenix v1.6.7を進めます。

以下のコマンドでスキャフォールドされます(必要なファイルが作られ、ディレクトリに配置されます)。

mix phx.new hello

開発用のサーバを起動します。

cd hello
mix phx.server

DBへの接続情報はconfig/dev.exsに書かれています(mix phx.newでできたファイルです)。

# Configure your database
config :hello, Hello.Repo,
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  database: "hello_dev",
  # 省略

docker runするときの設定は、このファイルに合わせていたわけです!

http://localhost:4000 にアクセスすると、「Welcome to Phoenix!」が表示されます2

サーバを止めるにはCtrl+C2度押しです。

本番用サーバで動かす🚀🚀

本番用のサーバでも動かしてみようと、Deploying with Releases — Phoenix v1.6.7を参照しました。

環境変数の設定

export SECRET_KEY_BASE=$(mix phx.gen.secret)
export DATABASE_URL=ecto://postgres:postgres@127.0.0.1/hello_dev

DATABASE_URLはdocker runの環境変数に渡した値と合わせて作っています。
これらはconfig/runtime.exsで読み込まれるようです (設定されていないとエラー送出)。

依存関係のインストール(など)3

mix deps.get --only prod
MIX_ENV=prod mix phx.digest

以上の準備をしたあとで起動します。

MIX_ENV=prod PORT=4001 mix phx.server

http://localhost:4001 にアクセスすると、「Welcome to Phoenix!」が見えます!

リリースをビルドして動かす🚀🚀🚀

コンパイル

MIX_ENV=prod mix compile
mix phx.gen.release

MIX_ENV=prod mix release

ビルドしたファイルからサーバを動かします

PHX_SERVER=true PORT=4001 _build/prod/rel/hello/bin/hello start

# PORT=4001 _build/prod/rel/hello/bin/server  # こちらでも動かせました

http://localhost:4001 にアクセスすると、「Welcome to Phoenix!」が見えます!

環境変数PHX_SERVER指定がないと、サーバが起動せず、何も表示されない状態になりました(config/runtime.exsで参照するようです)。
DATABASE_URLunsetするとエラーを吐くので、すべての処理は正常に行われるのですが、サーバが起動せずに待機した状態みたいです。

終わりに

ドキュメントに沿って、小さく躓きながらもやりたいことは達成できました!

Elixirのドキュメントは最小限という感じですが、

  • コマンド実行で出力されるメッセージ
  • スキャフォールドされたファイルの中

にコマンドや説明コメントが書かれています。
こういった情報を繋いで目的が達成できたときは、リアル脱出ゲームをクリアしたときのような達成感がありました。

「Deploying with Releases」に沿ってmix releaseして動かす方法は分かりました。
満足してしまった感もありますが、WEB+DB PRESS Vol.127の特集の残りもやってみたいですね。

参考文献

本文中で出したURL以外にも以下を参考にしました。

config以下の説明は以下が興味深かったです(ファイルの中のコメントにも詳しいです)。

  • config.exsがエントリポイント
  • config.exsの中でdev.exsprod.exsを読み込む
  • runtime.exsは秘密情報や動的な設定を読み込む

  1. mix phx.new — Phoenix v1.6.7

  2. PythonDjangoで言うロケットのページというわけですね! 参考:プロジェクトを作成しよう! · HonKit

  3. MIX_ENV=prod mix phx.digestと手元のコマンドメモにありました。このコマンドで再現したのですが、ドキュメントに当たるとMIX_ENV=prod mix assets.deployかもしれません

WEB+DB PRESS Vol.127の「作って学ぶPhoenix」で手を動かすために、Elixirの環境を構築する(macOS) #wdpress

はじめに

毎年少なくとも言語を1つ学習する。(『達人プログラマー 第2版』第1章 6 より)

Python大好き、nikkieです。

達人プログラマーのこの一節はよく引かれますよね。
私は「とにかくPythonのことをどこまでも知りたい!」という感じなのですが、このたび訳あってElixirの環境構築をしました。
もう一度やるときに参照して楽できるよう、自分用のメモとしてアウトプットします。

目次

WEB+DB PRESS Vol.127

2022年2月発売の号です(執筆時点の最新はVol.128)。

ここで取り上げるPhoenixの特集の他、

  • 実践リファクタリング 凝集度と結合度を学び,保守性と生産性を高める
  • 入社した会社にすばやく適応する 事業構造,カルチャー,コードの把握

といった特集があります。
また、連載「現場のPython」は komo_fr さんによる「データサイエンスのためのテスト入門」1でした2

特集2 Elixirによる高速なWeb開発! 作って学ぶPhoenix

本特集では,ElixirとPhoenixでWebアプリケーションを開発する方法を解説します。

ちょうどPhoenixというWebアプリケーションフレームワーク気になっていたタイミングで、直近のWEB+DB PRESSで取り上げられているのに気づき、読んでみることにしました。

特集ではrealworld3を題材に、PhoenixでWebアプリを作ります!

ソースコードはこちら:

環境構築!

Elixirのインストールからスタートです。
※ちなみに、Elixirの文法もよく分かっていません。

特集によると

asdfのようなパッケージマネージャを用いてインストールすることをお勧めします。(p.136)

とのことなので、オススメにならって環境構築しました。
初めてのasdf、ワクワクです!

手順

  1. asdfのインストール
  2. asdfのpluginのインストール(erlang, elixir)
  3. asdferlang, elixirをインストール

環境構築コマンド覚書

開発環境情報

  • macOS 10.14.6 (古いOSとなっています)
  • Homebrew 3.4.6

1. asdfのインストール

Getting Started | asdf (☆)に沿って進めます。

macOSではHomebrewを使うと

brew install asdf

でインストールできます(リンク先の1,2の部分)。

リンク先3の部分にある、シェル起動時に読み込ませる設定も実施します。
Bash & Homebrew (macOS)」に沿って、~/.bash_profileを編集しました。

これでasdfコマンドが使えるようになりました!

$ asdf --version
v0.10.0

2. asdfのpluginのインストール

(☆)の4に該当します。

elixirだけでなくerlangプラグインインストールします。

asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git

asdf plugin listでインストールされたことを確認できました。

3. asdferlang, elixirをインストール

(☆)の5, 6に相当します。

環境構築時(2022/04時点)の最新バージョンを指定しました。

asdf install erlang 24.3.3
asdf install elixir 1.13.4

asdf list elixir allのようにして、インストール可能なバージョンを確認できます。

最後に、使うelixirのバージョンを指定します。
localで作業ディレクトリごとに違うバージョンも指定できますが、やりたいことは特集を体験するだけなのでglobalで十分そうと判断しました。

asdf global elixir 1.13.4

Elixirがインストールされています!🙌

$ elixir --version
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Elixir 1.13.4 (compiled with Erlang/OTP 22)

終わりに

asdfを使って、Elixirのインストールができました。
これでPhoenixの特集をバリバリ進められます!

asdfは初めて触りましたが、なかなか好感触です。
「Manage multiple runtime versions with a single CLI tool, extendable via plugins」を謳うだけあり、「pyenvよりもasdfを使ってみたいな」と思いました。
pyenvだとPythonの管理しかできないですが、asdfだとPythonだけでなくElixirも他の言語も管理できると思っていて、それが魅力的です。

この環境構築の伸びしろポイントとしては、Pythonでいうvenv的なものを知りたいですね。
Elixirを使った開発が全然分かっていないのですが、いまのままだと、Elixir 1.13.4で複数のPhoenixのバージョンを使い分けられないんじゃないかと思っています。

ここで共有した手順で開発環境は構築できました。
近いうちにmix releaseの成果物を動かすまでの手順4を共有予定です。


  1. PyCon JP 2020の「NumPy/pandas使いのためのテスト自動化入門」のアップデート版という印象です。

  2. Medium.com のクローンアプリをバックエンド・フロントエンドの多様な組合せで作るための作り方のリポジトリのようです。

BERTの事前訓練をColabで動かしてみました(『Transformerによる自然言語処理』3章写経)

はじめに

「彼と出会った瞬間、私の人生が変わったの。(略) 世界が輝きだしたの」 (『四月は君の嘘』より)

えぬえるぴーや1のnikkieです。
いやー、BERTは自然言語処理の世界を変えてしまいましたねー!

「そんなBERTをもっと知りたい!」と、この週末『Transformerによる自然言語処理』の写経に取り組みました2

目次

『Transformerによる自然言語処理

この4月に朝倉書店さんから出版された翻訳書です。

自然言語処理の世界に革命をもたらし,BERTやGPTなどさまざまな言語処理モデルに用いられている深層学習モデル・Transformer。Transformerの仕組みや理論の解説のほか,テキスト生成や要約,ニュース分析など自然言語処理のさまざまなタスクへの利用法を,Pythonのコード付きで解説。実践的な1冊。(「編集部から」)

ソースコードはこちら:

「Transformerの訓練にはGPUが必要なのです!」ということで、Google Colabを徹底活用しています。

3章 RoBERTaモデルのゼロからの事前訓練

この章ではRoBERTa 3(改良されたBERT)を事前訓練(pre-train)します。
といっても、何日もかけて訓練するわけではなく、1エポックだけ の訓練です。

公開されているTransformerモデルをそのまま利用4したり、手元のタスクに合わせてfine-tuningしたりという経験はあるのですが、そもそも事前訓練ってどうやっているのかよく分かっていませんでした。
目次を見て「え!RoBERTa事前訓練するの!? 仕組みを知りたい、写経したい!」🤩とこの章に食指が動きました。

イマニュエル・カントの著作のテキストデータ(原著者が用意)を訓練に使います。

RoBERTa事前訓練を写経

コードはこちら(ColabからGitHubに保存):

動作環境

  • Colab (Python 3.7系)
  • transformers 4.18.0
  • tokenizers 0.12.1

RoBERTa事前訓練の流れ

  1. トークナイザの訓練・保存(tokenizersを使用)
  2. RoBERTaの事前訓練(transformersを使用)

2のRoBERTaの事前訓練、登場人物はこちら!

fill-maskタスクで事前訓練の確認

事前訓練(1エポックだけ)が終わったら、transformersのpipelineを使ってfill-maskタスクを解かせます。

Human thinking involves<mask>.

訓練は1エポックだけですが、reasonのように、カントの著作っぽい埋め方をしており、さらなる訓練の可能性を感じさせます!

このモデルはエクスポートもできました。

Googleドライブをマウントして、Colabのノートブックからドライブに保存。
それをダウンロードして、別の環境でもfill-maskパイプラインで同様の結果に!

以上で、Colabを使った事前訓練のやり方は体験できたことになります(長時間どう動かすかといった工夫はTODOです)。

「考えながら写経」5のメモ

  • datasetは、🤗的にはdatasetsを使ってロードする方法に置き換えたいようです
    • LineByLineTextDatasetはdeprecatedっぽい雰囲気なので、datasetsでの読み込みの仕方を調べたい
  • configのmax_position_embeddings=514、Transformerでよく見る数字は512だと思うのですが、+2しているのはどういう意味なんでしょう?
  • vocab_size=52_000ですが、tokenizerを確認すると19296。20000くらいまで小さくしても結果は変わらない?
  • tokenizersは今回初めて知ったライブラリ。ByteLevelBPETokenizerTokenizer(models.BPE())はどこまで同じか確認してみたい

終わりに

事前訓練はブラックボックスでしたが、写経して体験して全体感がつかめました
中でもdata-collatorは今回初めて知りました。
訓練データのマスクを担当していて、なるほどーという感想です。
青空文庫からテキストを取得して、事前訓練を素振りしてみてもよさそうですね。

『Transformerによる自然言語処理』は他にも興味深いトピックで満ちています!
引き続き読み進め、必要に応じて写経していきます。

補足: この記事を書いた時点のnikkieの認識

※正確性には自信がありません

  • 転移学習の枠組み
    • 事前訓練(pre-train)
    • fine-tuning
  • 事前訓練済みのTransformerモデルは(Hugging Face Hubなどで)公開されている
  • BERTのTはtransformerのT(Bidirectional Encoder Representations from Transformers
    • 事前訓練済みのBERTやその進化系は公開されている(誰でも利用できる)
  • BERTの事前訓練は2つ
    • 文中のマスクされた語が何か予測
    • 与えられた2文が、次の文かどうかを予測
  • RoBERTaは「次の文かどうかの予測」をやめ(簡単だから)、マスクされた語の割合を増やした訓練をするとして提案された

  1. RoBERTaは「ロベルタ」と読まれるようです(NLP2022の発表でいくつか聞きました)。私の中では「ローダンセ(Rhodanthe*)」みたく「ローベルタ」と読みたい気持ち(👈たぶん通じません)

  2. イベントレポート | Pythonで自然言語処理ハンズオン #はんなりPython - nikkie-ftnextの日記

  3. 先日のみんなのPython勉強会でも共有しましたが、「書き写しながら(略)考えることが大事です」 from『エンジニアの知的生産術』

直近のPythonイベント紹介(二〇二二 卯月) ※Python以外もあります

はじめに

「今夜、私が(話を聴かせて)いただくのは」、nikkieです。

先月、みんなのPython勉強会の「直近のPythonイベント紹介」向けにまとめた勉強会コレクション記事を書きました。

同種の記事の2022/04時点版をお送りします。

目次

前提

前回の記事の「なぜこの記事を書いたのか」と重なります(勉強会のリストを見たい方はどうぞ飛ばしてください)。

  • nikkieが気になっている勉強会の情報(nikkie's choice)です(参加予定表ではありません)
  • 読んだ方が、新しい勉強会を知ったり、参加して学びがあったり、人と繋がったりしたらいいなという願いを込めて記事にしています
    • nikkieの手元には、勉強会の情報が溢れかえっています
    • 「この状態は他の方にとっては当然ではないかも。どんな勉強会があるかよくわからない方もいるのでは」という気付きがこのシリーズのモチベーションです
  • 網羅するより推し!というスタンスです
    • あなたのオススメ勉強会があれば、Twitter @ftnextまでお知らせください。

今回の試みとして、カンファレンス情報も共有します。

それでは早速行ってみましょう!

4/14 みんなのPython勉強会#80 🎤

「新年度からはじめるPython」をテーマに、直近のPython本著者2名が話されます。

私は著者ではないですが、「Pythonを始めるガイド」で登壇する1🙋‍♂️ので、みんな来て!(宣伝)

4/15 Art of Agile Development Book Club: Refactoring (with Martin Fowler)

最近は『Art of Agile Development』という本(2nd Edition)の読書会に参加しています。
読書会を機に、この本のオンラインイベント(Book Club・無料)が開催されていることを知りました。

リファクタリング』やThoughtworks(などなど)で知られているMartin Fowler!!
直接話聞けるのヤバいですね!

Fridays from 8:00 – 8:45am Pacificで開催、JSTでは金曜日の24時(土曜日の0時)開始です。

4/19 第18回 MLOps 勉強会(Online)

3月に引き続き、機械学習系の勉強会はウォッチしていきます。
MLOps Practicesや継続的なモデルモニタリング、興味深いトピックだなーと思いました!

4/26 『良いコード/悪いコードで学ぶ設計入門』著者トーク

nikkieとは『アイの歌声を聴かせて』好きという共通点があるミノ駆動さん2

良いコード/悪いコードで学ぶ設計入門』は4/30発売。
3月に発表され、観測範囲ではめちゃめちゃ期待が高まっています
私もすごく楽しみです!

ミノ駆動さん本の読書会も開かれるんじゃないかなー(言い出しちゃった!)

4/26 pandasコードリーディング会#2

pandasのコードリーディング、おもしろそう!!
この日は勉強会、ヒトツダケナンテエラベナイヨー(悩🤯)

4/27 BPStudy#176〜BERTで自然言語処理を使ったサービスを開発してみよう

BERTを使って日本語を訂正するプログラムを書こう
BERTをWebサーバーで動かしてみよう

今年に入って自然言語処理の勉強会が多く開かれている印象3なのですが、ついにBERTをWebサービスで利用する方法が題材に!
「初心者歓迎!」ということなので、NLPer4の私は対象外な気もしますが、これは楽しみですねー。

4/27〜5/3 PyCon US 2022

Salt Lake Cityで現地開催みたいです。
日本からのスピーカーもいるようですよ。
PyVideoを見るのが楽しみです!

4/29 Art of Agile Development Book Club: Evolutionary Design with Kent Beck

エクストリームプログラミング』(などなど)で知られるKent Beckの話が聞ける!!
これも行くしかない!

4/29 Python駿河 勉強会 #36

5/2(月)、6(金)をつなげる方もつなげない方も、連休初日にオンラインもくもく会あります!

5/12 みんなのPython勉強会#81 📝

7周年記念回!
登壇者募集中です!!

5/25 Python Tips LT会 - vol.3 🎤

ラクスさん開催のLT会、テーマはPython Tips。
LT登壇する🙋‍♂️ので、みんな来て!(宣伝)

カンファレンス情報!

PyCon APAC 2022のCfPは4/15(金) AoE

9/3,4 オンライン開催、ホストはPyCon Taiwanです!

どんな言語でも登壇OKらしく、海外登壇の一歩目にいかがでしょうか?
事前録画形式なので、「字幕が付くのかな」と想像しています。

"準備"を始めた国内カンファレンスたち

DjangoCongress JP 2022 始動!

PyCon JP 2022は10/14(金)〜16(日) 有明で開催予定

今回はオンサイト(現地)での開催となります。

14日: カンファレンス
15日: カンファレンス、パーティ(仮)
16日: スプリント、その他未定

終わりに

2022年4月〜5月の気になっている勉強会リストとカンファレンスの状況を共有しました。
これを読んで、「この勉強会興味持った!」というのが1つでもあったら嬉しいです。
「私もこれ、気になる!」という勉強会があれば、ぜひご一緒しましょう!


  1. 一部プレビューです:

  2. キャリア的にはまだまだな身なのに調子乗りました。ごめんなさい🙇‍♂️

  3. 一例

  4. 自然言語処理を業務でやっている、えぬえるぴーやです

Webで無料で読める!Python入門教材リスト(2022/04 #stapy Python始めるガイドトークプレビュー)

はじめに

聞いて聞いて! 4/14(木) 19時からのみんなのPython勉強会で登壇します! nikkieです。

トークPythonを始めるガイドとして

  • Pythonの入門教材をいくつか紹介
  • プログラミングを始める上でオススメの考え方を共有

する予定です。

前者のPythonの入門教材について、このブログでプレビューしちゃいます!

目次

TL;DR(この記事のまとめ)

  • この記事は、みんなのPython勉強会のトークで紹介予定のPython入門教材リストです
  • この記事を読んでいる方(特にPython歴が長い方)、ここにないオススメ教材あれば@ftnextまで教えてください🙏

Python入門教材リストの前提

以下を満たす教材を紹介しています。

  • Webに公開されている
    • 書籍についてはカバーしません(無料で読めるものにフォーカス)
  • 日本語で読める
    • 英語も対象にすると、もっともっと広がります

プログラミング自体が初めてな方向け

まずはプログラミングの経験がなく、プログラミングにもPythonにも入門したいというユースケース向けです。

python.jp ゼロからのPython入門講座

この講座では、プログラミング未経験者を対象に、Pythonプログラミングに必要な最低限な操作方法と、基礎知識を覚えてもらうことを目標にしています。この講座でかんたんにプログラミングの概要を学び、それから一般的なPythonの入門書に取り組むと、学習がスムーズに進むのではないかと思います。

Google ColabでPythonプログラミングを体験します。
「スイカ割りゲーム」が作れるようになります。

Python ゼロからはじめるプログラミング』サポートページの「Python学習用教材」

筑波大の三谷先生による、Python ゼロからはじめるプログラミング』の内容を解説するための副教材

300ページを超える大ボリューム! かつ、スライドが見やすいです。

東京大学 理学部の教材「Pythonプログラミング入門」

授業のサイトと思われるのがこちら:https://sites.google.com/view/ut-python/

Colab版やガイダンススライドも公開されています。

京都大学の教材「プログラミング演習 Python 2021」

本書は京都大学の全学共通科目として実施されるプログラミング演習(Python)の教科書として作成されたものです.

プログラミング入門済みの方向け

以下は、プログラミングは入門済みで、Pythonに入門したいというユースケースに向くかなと思っています。

Python入門者の集い(PyNyumon) ハンズオンテキスト

数時間で行うハンズオンのテキスト。
実は私のPython入門もこちらでした。

Python言語入門 + スクレイピング という内容です。
入門時に仮想環境について知られたのが大きかったです。

Python Boot Camp テキスト

半日行うPython Boot Camp(※ハンズオン)のテキスト。
扱う範囲はPyNyumonと重なりますが、PyNyumonより少しだけ情報量が多いと感じます。
Pythonの紹介から始め、スクレイピングやWeb APIの呼び出しまで扱います。

Pythonチュートリアル

公式のチュートリアル
(関数の引数やクラスなど)ところどころ詳しすぎる内容もありますが、公式なので安心感がありますね。
わからないところは飛ばして取り組むのがオススメです(時をおいて何周もしましょう)。

終わりに

ここ数年のPythonの人気からか、入門教材だけ見てもものすごい情報量でした。
よさそうな教材が見つかったという方が1人でもいたら嬉しいです。

私1人の知っている範囲には限界がありますので、「この教材もよかった!」という声があればお気軽に@ftnextまでお寄せください。

4/14の勉強会でトークするのを楽しみにしています!

sphinx-revealjsで作ったスライドをGitHub Pagesで公開する

はじめに

聞いて聞いて! nikkieです。

先日以下のように書きました。

sphinx-revealjsいいと思うので、皆さんに使ってほしく、筆を進めねば・・

https://nikkie-ftnext.hatenablog.com/entry/yapc-japan-online-2022-awesome-talks#fn:5

こちらを実現させていきます。
まずは一番単純なトピックから。
sphinx-revealjsで作ったスライドをGitHub Pagesで公開する方法を共有します!

ちなみに私の登壇資料は、2021年からsphinx-revealjs × GitHub Pagesという組合せです!1

目次

TL;DR(sphinx-revealjsで作ったスライドをGitHub Pagesで公開する方法)

  • sphinx-revealjs作者のattakeiさんが実はすでにまとめているんです!(こちらを見てください
  • このブログで付加できる価値は、より簡単に公開できる ように自作したアクション ftnext/action-push-ghpages の紹介です
  • GitHub Actions設定例

前提:Sphinxとは

Python製のライブラリで、ドキュメンテーションツールです。
reStructuredText(reST。拡張子は.rst)形式で記述すると、あれよあれよという間にドキュメントができあがります(まるで魔法!)

過去のみんなのPython勉強会2でも特集しました。3
詳しく知りたい方はアーカイブをどうぞ!

このSphinxでなんとプレゼンテーションに使うスライドも作れちゃうんです!!

attakeiさんによる『Sphinxでもプレゼンテーション』

sphinx-revealjsの紹介やプレゼンテーションの作り方、より使いこなすためのtipsやGitHub Pagesでの公開方法はattakeiさんのまとめに譲ります。
TL;DRで紹介したリンク先をぜひ読んでみてください!(本当にオススメなので、同じリンクを再掲しておきます)

PythonドキュメンテーションビルダーSphinxを用いて、プレゼンテーションをしてみませんか?
この本は、Sphinxの拡張を使ってreStructuredTextからReveal.jsのプレゼンテーションを生成するハンドブックです。

私はSphinxが手に馴染んでいるので、「Sphinxでスライド作れるの、最高じゃん!」って感じですね。

sphinx-revealjsでスライドが作れる仕組み(概要)

スライドが作れる仕組みには、Reveal.jsというJavaScriptのライブラリも一役買っています。

  • スライドの内容をreSTで書く
  • ➡️ sphinx-revealjsがreSTをHTMLに変換(Reveal.jsに沿った形式)
  • ➡️ 変換されたHTMLをブラウザで開くと、Reveal.jsによってスライドとして表示されます!

つまり、スライドはHTMLなんですね。
そして、GitHub PagesはHTMLなどの静的ファイルをホストできるので、sphinx-revealjsで作ったスライド(HTML)を公開できます!

ftnext/action-push-ghpages を使って、より簡単に公開できます!

attakeiさんのまとめによると、GitHub Pagesとしての公開には maxheld83/ghpages を使います。

      - name: Deploy to GitHub Pages
        uses: maxheld83/ghpages@v0.2.1
        env:
          BUILD_DIR: build/revealjs
          GH_PAT: ${{ secrets.GH_PAT }}

${{ secrets.GH_PAT }}は、PATと呼ばれるトークンを作ってリポジトリに設定する必要があります。

これまでの素振り(後述)から、「このトークンって作る必要ないんじゃ?」と思い至りました。
maxheld83/ghpages@v0.2.1 を参考に、PATを作らずにGitHub Pagesとして公開できる ftnext/action-push-ghpages を実装しました。

ftnext/action-push-ghpages を使うと、以下のように書き換えられます。

      - name: Deploy to GitHub Pages
        uses: ftnext/action-push-ghpages@v1.0.0
        env:
          build_dir: build/revealjs
          github_token: ${{ secrets.GITHUB_TOKEN }}

${{ secrets.GITHUB_TOKEN }} は、GitHub Actionsを有効にするとリポジトリにインストールされるGitHub Appのアクセストークンです4
これは設定不要で使えます。

アクションを自作して、PATを作る一手間を解消しました。
いいなと思ったら ftnext/action-push-ghpages を使ってみてください!

裏話:PATがいらないと気付いたきっかけ

git remote set-urlは要らない? に関係して調べたところ、${{ secrets.GITHUB_TOKEN }}でもコミットをpushできそうだと分かりました。
この仮説を元に実装してみたのが ftnext/action-push-ghpages です。

未検証ですが、maxheld83/ghpages でもPATの代わりに${{ secrets.GITHUB_TOKEN }}を使えるかもしれません。

終わりに

sphinx-revealjsで作ったスライド(HTMLファイル)をGitHub Pagesで公開する方法を紹介しました。

基本はattakeiさんのまとめに沿っていただき、GitHub Pagesに公開するActionだけ ftnext/action-push-ghpages を使ってみてください!
私の登壇資料リポジトリの例も最後においておきます(TL;DRと同じリンク先です)

発表資料はプレーンテキストで書いて省力化すると、アウトプットが捗りますよー📣5


この記事は、以下のツイートを記事に書き上げたものになります。

argparseのadd_argumentのtype引数には、FileTypeよりもユーザ定義関数を渡すのをオススメしたいです!(#Python実践レシピ を勝手に補足)

はじめに

#みんなでアイうた、最高の時間になりました!ありがとうございました🙌 nikkieです。

この1月に出た書籍『Pythonエンジニア育成推進協会監修 Python実践レシピ』(以下、『Python実践レシピ』)を読んでいます。
先日、Python標準ライブラリのargparseについて、「位置引数もある!」と書籍での説明を補足しましたが、今回は別の点の補足です。

Python実践レシピ』でargparse.FileTypeを知りました!
「もっと詳しく知りたい!」とドキュメントを調べたところ、「書籍の書き方だけでは情報が十分に伝わっていないかも」という懸念を抱きました。
そこで、「この記事が補完関係になったらいいな」と、いつものおせっかいで勝手に補足しちゃいます!

目次

この記事の要点

  • Python実践レシピ』ではadd_argumenttype引数にargparse.FileTypeを渡して、エラーメッセージを分かりやすくするtipsを紹介
  • argparse.FileTypeのドキュメントを当たったところ、引数で処理が失敗した場合、ファイルを閉じないということが分かった
  • ファイルを閉じないのを好まない立場なので、type引数にユーザ定義関数を渡してエラーメッセージを分かりやすくする方法を共有します

動作環境

$ python -VV
Python 3.10.2 (v3.10.2:a58ebcc701, Jan 13 2022, 14:50:16) [Clang 13.0.0 (clang-1300.0.29.30)]

Python実践レシピ』よりargparse.FileTypeの紹介

10.4.4「argparse:よくあるエラーと対処法」でargparse.FileTypeが紹介されます。

「ユーザーが何をすべきかわかりにくくなって」いる例

read_file.py

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("input")
args = parser.parse_args()

with open(args.input, encoding="utf8") as f:
    print(f.read().rstrip())

実装について書籍から以下のように変えています:

  • コマンドラインから渡す引数が1つだけなので、位置引数で実装しました。詳しくは
  • open()関数にencoding引数を指定しました(補足を後述します)
  • ファイルオブジェクトの内容(read()の返り値)の末尾の改行文字を削除するためにrstrip()を追加しました

読み取るファイルを作ります。

$ echo "アイの歌声を聴かせて" > some.txt

読み取らせてみましょう。

$ python read_file.py some.txt
アイの歌声を聴かせて

いいですね!

Python実践レシピ』には、存在しないファイルを指定したとき、ユーザが何をすべきか分かりにくいと書かれています。
エラーメッセージを確認しましょう。

$ python read_file.py spam.txt
Traceback (most recent call last):
  File "/.../read_file.py", line 7, in <module>
    with open(args.input, encoding="utf8") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'spam.txt'

第1引数に渡したspam.txtについて「No such file or directory」とFileNotFoundErrorが送出されました。

このスクリプトを開発した人なら、Tracebackを見て「存在しないファイルをopenしようとしたのか」と気付き、修正できると思います。
このスクリプトが配布されていて、中身を知らずに使おうとした人にとって、何をすべきか分かりにくいということなのかなと理解しました(Tracebackを目にすることになりますからね)。

では、この解決の仕方を見ていきましょう。

argparse.FileTypeにより、ユーザーが何をすべきか分かりやすくできる

argparse.FileTypeを使って以下のように書き換えます。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("input", type=argparse.FileType("r", encoding="utf8"))  # 変更1
args = parser.parse_args()

print(args.input.read().rstrip())  # 変更2

変更点は2箇所です:

  • add_argumentメソッドでtype引数にFileTypeオブジェクトを渡しました
    • 後で示すドキュメントから、FileTypeの引数の指定はopen()関数と同様と理解しています
  • コマンドライン引数で指定したパスのファイルが開かれ、args.inputはファイルオブジェクトなので、そのままread()しています

存在しないファイルを指定したときのエラーメッセージを確認しましょう。

$ python read_file.py spam.txt
usage: read_file.py [-h] input
read_file.py: error: argument input: can't open 'spam.txt': [Errno 2] No such file or directory: 'spam.txt'

たしかに、スクリプトの中身を知らずに使いたい人にとっては分かりやすいと言えると思います!

  • Tracebackを目にしなくて済む
  • 使い方(usage)が表示されている
  • inputに指定したファイルが「No such file or directory」で開けなかったと分かる

argparse.FileTypeのドキュメントより

FileTypeは『Python実践レシピ』で初めて知ったので、ドキュメントも確認しました(これは私の習慣によるものです)。

標準入力も扱える!

https://docs.python.org/ja/3/library/argparse.html#filetype-objects に興味深い記載がありました。

FileType オブジェクトは擬似引数 '-' を識別し、読み込み用の FileType であれば sys.stdin を、(略)変換します:

試してみましょう!

$ python read_file.py -
みんなでアイうた  # この行を入力して改行した後に、Ctrl+D
みんなでアイうた

Ctrl+Dをするまで標準入力から読み取り続けます(1行入力して改行した後、Ctrl+Dしました)

標準入力から複数行入力した場合

$ python read_file.py -
$ python read_file.py -
サトミ
シオン  # この行を入力して改行した後に、Ctrl+D
サトミ
シオン

制限がある:開かれたファイルは自動では閉じない!?

ドキュメントを読み進めていくと「ムム😕」という記載を見つけました。

https://docs.python.org/ja/3/library/argparse.html#type

また、type キーワードに FileType を指定した場合には制限があります。ある引数に FileType を指定してファイルが開かれ、その後ろのどこかの引数で処理が失敗した場合、エラーが表示されますが、開かれたファイルは自動では close されません。

「開かれたファイルが自動でcloseされない」なんて!

上の引用は次のように続きます。

これを好まない場合は、parser による引数の処理が終わるまで待ち、その後に with 文などでファイルを開くのがよいでしょう。

これは好みの問題だと思いますが、add_argumentメソッドのtype引数にFileTypeオブジェクトを指定し、引数のパースエラーとなった時、開かれたファイルが自動で閉じない1のは好ましくないな(私だったら他の人に使用をオススメしないかな)と思いました。

脱線:開いたファイルが閉じられないと何が問題なの?

Python入門時からopenしたファイルはcloseすべし(closeを都度書くのが億劫ならwith文を使うべし)の教えを守ってきたので、「closeしないと落ち着かない」という感覚なのですが、この機に少し調べてみました。

openが返すファイルオブジェクト2は、__del__の呼び出しでclose()メソッドが呼ばれる3そうです。
プログラマが明示的にcloseを呼び出さなくても、プログラムを実行するインタプリタが終了するときに、__del__が呼ばれているのかな」と思ったのですが、ドキュメント4によると

インタプリタが終了したときに、残存しているオブジェクトの __del__() メソッドが呼び出される保証はありません。

とのこと。
つまり、プログラマが明示的にclose呼び出す必要があるんだなと理解しました。

closeしないと何が問題なの?」と誰かが聞いているだろうと調べたところ、以下を見つけました。

回答を読むと(※意訳です)、

  • CPythonは参照カウントというガベージコレクションの仕組みにより、closeメソッドを呼び出さなくても閉じられる5
  • CPython以外のPythonの実装では、参照カウントを使っておらず、closeメソッドを呼び出さなければファイルを閉じない6
  • CPythonの実装の詳細に依存しており、(Cpython以外の処理系への)可搬性が損なわれている7

IMO:別のやり方として、type引数に関数を渡す

私の中では(好みとして)FileTypeは使わないと考えていますが、このままではFileTypeを使って解決したかった「ユーザーにとって、エラーメッセージが何をすべきか分かりにくい」という問題が残っています。

過去の私のアウトプット8から、type引数に独自定義した関数を渡した解決法を紹介します(スライド28・29)。

import argparse
from pathlib import Path


def existing_path(path_str: str) -> Path:
    """文字列が指すファイルが存在すれば、そのファイルを指すPathオブジェクトを返す
    
    存在しなければ、ArgumentTypeErrorを送出する
    """
    path = Path(path_str)
    if not path.exists():
        message = f"{path_str}: No such file or directory"
        raise argparse.ArgumentTypeError(message)
    return path


parser = argparse.ArgumentParser()
parser.add_argument("input", type=existing_path)
args = parser.parse_args()

with args.input.open(encoding="utf8") as f:  # Path.open()
    print(f.read().rstrip())

存在しないファイルのパスをコマンドライン引数として渡してみましょう。

$ python read_file.py spam.txt
usage: read_file.py [-h] input
read_file.py: error: argument input: spam.txt: No such file or directory

FileTypeを使ったときと同様のエラーメッセージが表示できていますね!

  • Tracebackを目にしなくて済む
  • 使い方(usage)が表示されている
  • inputに指定したファイルが「No such file or directory」となったと分かる(文言は調整できると思います)
  • ただし、-で標準入力は受け取れなくなっています😢

type引数のドキュメントの以下を参考に実装しています。
https://docs.python.org/ja/3/library/argparse.html#type

type キーワードの引数として、単一の文字列を受け取るような任意の呼び出しオブジェクト (callable) が使用できます。もし呼び出しが ArgumentTypeError, TypeError, または ValueError 型の例外を送出した場合は、parser がそれをキャッチして適切なエラーメッセージが表示されます。それ以外の型の例外は処理されません。

ユーザが定義した関数も使用できます

ドキュメントには以下のように続いています。

一般論として、type キーワードに指定するものは、せいぜい上記の3種類の例外を発生するくらいの、お手軽な変換に限るべきです。より複雑な (interesting) エラー処理、またはリソース管理を伴うものは、引数を解析したあとに別個の処理として行うべきです。

終わりに

Python実践レシピ』で紹介されたargparse.FileTypeについて、

  • 引数で処理が失敗した場合、ファイルを閉じない挙動
  • 私の好みとしてファイルが閉じないのは落ち着かないので、type引数にユーザ定義関数を渡してエラーメッセージをカスタマイズしたい

の2点を共有しました。

限られた紙面の中で、豊富なライブラリを紹介するというスタンスの『Python実践レシピ』👏
認定試験の教科書でもあるため、多くの方が読むと期待されるこの本を、引き続き勝手に補足していきます。

補足:open関数のencoding引数指定

Python3.10で追加されたEncodingWarning(オプショナル)を知ってから、私は指定するようにしています。

https://docs.python.org/ja/3/whatsnew/3.10.html#optional-encodingwarning-and-encoding-locale-option

(意訳)ほとんどのUnixプラットフォームではUTF-8が使われますが、UTF-8のファイルを開くときにencoding引数を省略するのは、非常によくあるバグです9

What's New内の記載は簡潔ですが、これを提案したPEP10を読むと「指定したほうがいいな」と思いました(提案者はInadaさんです)。
これだけでも一ネタなので、機会があれば記事としてアウトプットします。


  1. ファイルを閉じるについては、私の性格(ちゃんとやりたい)として、Python入門時から徹底しています。 ref: https://pycamp.pycon.jp/textbook/5_module.html

  2. 用語集 https://docs.python.org/ja/3/glossary.html#term-file-object

  3. https://docs.python.org/ja/3/library/io.html#io.IOBase.__del__

  4. https://docs.python.org/ja/3/reference/datamodel.html#object.__del__

  5. (原文) In current versions of CPython the file will be closed at the end of the for loop because CPython uses reference counting as its primary garbage collection mechanism

  6. (原文) For example IronPython, PyPy, and Jython don’t use reference counting and therefore won’t close the file at the end of the loop.

  7. (原文) It’s bad practice to rely on CPython’s garbage collection implementation because it makes your code less portable.

  8. 近況報告:2020夏、登壇の夏、予定していた全公演を駆け抜けました!🎤 - nikkie-ftnextの日記

  9. (原文) Since UTF-8 is used on most Unix platforms, omitting encoding option when opening UTF-8 files (e.g. JSON, YAML, TOML, Markdown) is a very common bug.

  10. https://peps.python.org/pep-0597/ encoding引数の指定が省略されているコードを、Windowsユーザはうまく動かせないと指摘しています(読み込むファイルにASCII外の文字が入っている場合です)