jqfpyでyamlを実験的にサポートしてみた
jqfpyでyamlを実験的にサポートしてみた。実験的という言葉がついている理由は完全にサポートしているというわけじゃないということ。 具体的には、連続したjsonに対応した入力をサポートしていない(後で詳しく)。
yaml対応版のインストール
yaml対応版のインストールのインストールは以下の様にする。
$ pip install 'jqfpy[yaml]'
動作例
PyYAMLがインストールしていれば普通に動く。ファイルの拡張子を見て良い感じに扱ってくれる。特にフォーマットを指定していない場合にはjsonで出力される。
00data.yaml
$ jqfpy 00data.yaml { "person": { "name": "foo", "age": 20, "skills": [ "x", "y", "z" ] } } $ jqfpy -r '"{p[name]}({p[age]})".format(p=get("person"))' 00data.yaml foo(20)
入っていない場合には以下の様なエラーが出る。
$ jqfpy 00data.yaml yaml module is not found. please install via pip install 'jqfpy[yaml]'
フォーマットの指定
-o
, --output-format
でyamlを指定すると出力もyamlになる。
$ jqfpy -o yaml 00data.yaml person: name: foo age: 20 skills: - x - y - z $ jqfpy -c -o yaml 00data.yaml {person: {name: foo, age: 20, skills: [x, y, z]}}
catからパイプで繋げられたときなど、ファイルのフォーマットがファイル名から取得できない場合もある。そのような場合には、-i
, --input-format
を使う。
$ cat 00data.yaml | jqfpy -r -i yaml 'get("person/name")' foo
連続したデータ
残念ながら完全なサポートではなく連続したデータなどに対応していない。 例えば、jsonで言う以下の様な出力を例に取る。
01data.json
{ "person": { "name": "foo", "age": 20, "skills": [ "x", "y", "z" ] } } { "person": { "name": "bar", "age": 10, "skills": [] } }
これをそのままyamlに直すと以下の様になる。
01data.yaml
person: name: foo age: 20 skills: - x - y - z person: name: bar age: 10 skills: []
このyamlが2つのデータになれば良いはずなのだけれど。yamlのパーサーの問題でちょっと対応方法が思いつかなかった。現在の所は1つだけのデータと認識されてしまう。
$ jqfpy 01data.yaml { "person": { "name": "bar", "age": 10, "skills": [] }` }
ちょっとだけあがいてみていて、yamlの仕様的に---
がドキュメントの区切りとして定義されているので出力のときにはこれを利用するようにしている。こちらは2つのデータとして認識される。
$ jqfpy -o yaml 01data.json person: age: 20 name: foo skills: - x - y - z --- person: age: 10 name: bar skills: [] $ jqfpy -o yaml 01data.json | jqfpy -i yaml -c --force-stdin {"person": {"age": 20, "name": "foo", "skills": ["x", "y", "z"]}} {"person": {"age": 10, "name": "bar", "skills": []}}
ちょっとだけ困ったこと
ちょっとだけ困ったことが実は存在していて。標準入力から入力がなければヘルプを表示と言うようにしているのだけれど。パイプで繋いでいった状態でちょっと処理が重たいときなどには誤動作してしまうことがある。ヘルプを表示してしまう。
これに対して標準入力を見ることを強制するために --force-stdin
というオプションを設けている。これがちょっと微妙。
ちなみに標準入力の有無はselectでみている。このあたりの待機時間を調整すれば良いのかもという話ではあるのだけれど。それもそれで微妙な感じ。
def is_fd_alive(fd): if os.name == 'nt': return not os.isatty(fd.fileno()) import select return bool(select.select([fd], [], [], 0.07)[0])
追記:
以下が動かないのはちょっとありえないので。ヘルプメッセージを表示する機能消した(0.3.2)。
(sleep 1; cat 01data.json ) | jqfpy
ヘルプメッセージが見たい場合には明示的に jqfpy -h
と入力する。