Unyablog.

のにれんのブログ

Poetry を使ってみた

この記事は KMC 2 Advent Calendar 2019 3日目の記事ということにしました。

Poetry

PythonDependency Manager は pipenv が有名で、自分もリリース当初から使っていた。ただ、最近はリリースが一年間されておらず、割と不安な状態*1

最近は pipenv への対抗馬として Poetry が開発されているらしい。こちらは活発でリリースも頻繁にされており良い感じ。

pipenv で決まりだと思っていたのに… と思いながらも Poetry を使ってみた。

pipenv は Pipfile で依存パッケージを記述するが、Poetry では pyproject.toml を用いる。その他細かい使い方は README 参照。

感想

良かったところ

  • ちゃんと使える
  • PyPI にアップロードするのがとても楽になる

    pyproject.toml に書いたら poetry build && poetry publish で終わり!

  • 依存解決が早い

  • グラフィカルなコンソール表示
  • 機能の取捨選択が良い

    pipenv はおもてなし機能が多すぎると思う。

  • ソースコードがきれい

    これは出たばかりだからかも。

poetry run の実装を見たところ、ちゃんと os.exec しているので安心した。

イマイチなところ

  • CLI のインターフェースは pipenv のほうが好き

    poetry addinstall コマンドにまとめて欲しい、とか。

    pyproject.toml が無いときに addinstall しても、良しなに init されて動いて欲しい、とか。

  • カスタマイズが弱い

    単純にフラグが少なくて、要求とマッチせず困ることがある。

    また、 pipenv ではフラグ類は基本的に環境変数で設定できるが、Poetry は一部のフラグしか設定できない

  • まだ絶賛開発中である

    時々バグっぽい挙動がある。作者が想定していそうなパッケージストラクチャを使っていれば動くが、そこから外れるとよく分からないエラーが出る。結局ソースコードを読むことになる。

  • (良い意味でも悪い意味でも)かっちりしている

    パッケージ追加時において、pipenv はデフォルトのバージョン指定は * (どのバージョンでも ok)である。それに対して、 Poetry は ^{current version} となる。個人の開発レベルでは * のほうが嬉しい(* にする手段はある)。

結論

まだ開発中ではあるものの、パッケージマネージャとして欲しい機能がちょうど良く揃っていて良いソフトウェアだと感じた。特に setup.py を生成してくれるのが魅力的で、PyPI にアップロードしようという気持ちにしてくれる。

もうすぐ 1.0 が出るらしいし、当面は Poetry で過ごそうと思う。

*1:master だけは進んでいる…

iTerm2 JISキーボード 文字 拡大 Karabiner-Elements

iTerm2 で文字を拡大するショートカットは ⌘ + である。

JISキーボードでは +Shift ; を入力することになるので、⌘ + は JIS では Shift ⌘ ; が入力される。

一方 iTerm2 では、Shift ⌘ ; が Open Command History に割り当てられている。このため、JISキーボードで文字を拡大しようとすると謎の機能が発火してしまう。

これの対策として、

  • iTerm2 を表示している
  • JISキーボードである

場合、Karabiner-ElementsShift ⌘ ;⌘ + に変換するようにする。

{
  "title": "Send Cmd+'+' on iTerm2",
  "rules": [
    {
      "description": "Send Cmd+'+' on iTerm2",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "semicolon",
            "modifiers": {
              "mandatory": [
                "command", "shift"
              ]
            }
          },
          "conditions": [
            {
              "type": "frontmost_application_if",
              "bundle_identifiers": [
                "com.googlecode.iterm2"
              ]
            },
            {
              "type": "keyboard_type_if",
              "keyboard_types": [
                "jis"
              ]
            }
          ],
          "to": [
            {
              "key_code": "keypad_plus",
              "modifiers": [
                "left_command"
              ]
            }
          ]
        }
      ]
    }
  ]
}

YAML から JSON に変換するツールを Nim で書き、GitHub Actions でリリースする

最近 config が YAML になっているアプリケーションが多い。ただ、自分は YAML の読み書きが苦手である。

設定を書くには機能が多すぎるのと、(config なので)ネストしやすいのにインデントが関わってくるのが苦手なのだと思う。

何度かハマった結果、これからは JSON に変換して読むことにした。JSON を読むのには慣れているし、jq など色付・抽出するツールも持っているので最高 *1

YAMLJSON に変換するツールは世の中に多くあるが、そんなに大変じゃないので自分で作ることにした*2

github.com

何で作るか

案1 Ruby で書く

Ruby は標準ライブラリに YAML パーサーが入っているので、適当な rubyスクリプトを書けば目的は達成される。

ただ、そのためだけに Ruby 入れるのも嫌だな…って思ってやめた。

案2 Go で書く

Go のようなコンパイラ言語であれば、標準ライブラリに入ってなくともコンパイルすれば良いので楽である。

また、Go は goreleaser や go get などインストールしやすい環境が整っており最高。

というわけで初めは Go で書いていたのだけど、YAMLJSON で型が微妙に違う(YAMLmap[int]interface{} のこともあるが、JSONmap[string]interface{})のが面倒でやめた。

案3 Nim で書く(採用)

Nim は先日 1.0.0 が出たイケイケの言語で、Python っぽく書けて便利という評判が自分の中である。Go が無理なら Nim チャンス!ということで Nim で書くことにした。

Nim の YAML ライブラリ は最高で、loadToJson 関数があるので一瞬で終わった。

バイナリを作る

リリース周りは CI でやりたい。今回は GitHub Actions を使ってみることにした。GitHub Actions では、Action を組み合わせたり、自分でコマンドを記述したりして CI の動作を記述する。

Action は 公式がいくつか配布している 他、サードパーティのもある。今回はサードパーティ Action は使わない方向でやってみた。

Nim with GitHub Actions

公式では Golang など様々な言語をインストールする Action があるが、残念ながら Nim はない。なので自分で環境構築を行った。

macOS

brew が入っているので、 brew install nim する。

Ubuntu

Ubuntu では Docker を使った(apt で Nim が配布されているものの、バージョンが古くて依存ライブラリがコンパイルできない)。

amd64 だと 公式 Nim Docker Image を使えばよかったが、クロスコンパイルはできなかったので、 arm 用には クロスコンパイルできる Image を Docker Hub に作った *3

ちなみに、GitHub Workflow には Docker 上で動かしたり Volume を作ってくれたりする機能があるが、それを使うにはパブリックイメージを使う必要がある。そうでない場合は自前で docker build して docker run ... することになると思う。

その他

良かった

悪かった

まだ出たばかりというのもあって、使いづらい点も多かった。

  • 公式の Actions が機能不足

    artifact は一つずつしか Upload できない等、「一応できるけど不便」みたいな例が多い。 特にリリース周りは不便で、本当はもっとうまくできるのにな…と言いながら長い Workflow になってしまった。

  • job 間で値の受け渡しがしずらい

    値を直接受け渡しすることはできず、 artifact 経由になってしまう。「一回リリースつくって、そこに並列で artifact を追加する」といったケースでは upload_url を渡すことができずに困った。

  • 情報が多くない

    ドキュメントはちゃんとしているが、ユースケースがまだ少ないため情報が探しにくい。

  • YAML エディタが使いにくい

    エラーや補完を出てくれるのは嬉しいが、改行時は普通に改行してほしいな…。

多くの問題は時が経てば解決するだろう。

感想

  • YAML から逃げるために作ったのに、 GitHub Actions で数十行の YAML を書いていたのは悲しかった
  • こんな面倒なことをしなくても、Go 言語を使えばクロスコンパイルもリリースも一瞬でできるので最高だと思った。でも Nim も悪くないよ。

*1:書くのに向いているとは言っていないが、YAML よりはハマらない…

*2:手段が目的になった面もある

*3:実は Docker Hub 初めてです

VSCode 上で ESLint を使った TypeScript のフォーマット

  1. https://github.com/microsoft/vscode-eslint を入れる
  2. VSCode のデフォルトフォーマッタを切る

グローバルか、ワークスペース上の .vscode/settings.json などに書くと良い

{
  "typescript.format.enable": false
}
  1. TypeScript で ESLint が働くようにする
    "eslint.validate": [
        "javascript",
        "javascriptreact",
        {
            "language": "typescript",
            "autoFix": true
        },
        {
            "language": "typescriptreact",
            "autoFix": true
        }
    ],