📄

python の yaml.dump 面白すぎだろww

に公開

※ 情報量の少ないタイトルは釣りです。

何が起きたのか?

以前 FastAPI の openapi.json を yaml に変換する記事を書きました

https://zenn.dev/oroshi/articles/fastapi_document_customize

が、面白いバグが発生しました。

日本の都道府県に都道府県コードと呼ばれる2桁のコードが割り振られています。

https://www.asahi-net.or.jp/~ax2s-kmtn/ref/jisx0401.html

これをAPIでやり取りする際に、以下のような enum を定義して openapi.yaml を出力しました。

class PrefCode(str, CustomSchemaEnum):
    HOKKAIDO = "01"
    AOMORI = "02"
    IWATE = "03"
    MIYAGI = "04"
    AKITA = "05"
    YAMAGATA = "06"
    FUKUSHIMA = "07"
    IBARAKI = "08"
    TOCHIGI = "09"
    GUNMA = "10"
    SAITAMA = "11"
    # ...以下省略...

すると openapi.yaml では以下のような出力になりました。

PrefCode:
    enum:
    - '01'
    - '02'
    - '03'
    - '04'
    - '05'
    - '06'
    - '07'
    - 08
    - 09
    - '10'
    - '11'
    # ...以下省略...

08 と 09 だけクォーテーションがないんですよね。この openapi.yaml でクライアントのコードを生成すると 08 と 09 が数値扱いになりました。

なぜ起きたのか

以下のコメントによると

https://github.com/yaml/pyyaml/issues/794#issuecomment-2100844662

0 から始まることは 8 進数であることを意味し、'06' や '07' はクォーテーションをつけないと 8 進数の数値なのか文字列なのか区別できないので '' をつける必要があるが、08 や 09 は無くても区別できるので、YAML 1.1 の仕様では '' をつけない。

ということらしいです。しかし YAML 1.2 では 08 や 09 にも '' を付けられるようになったようです。

解決方法

yamlcore というモジュールが公開されています。これを使えば解決します。

https://pypi.org/project/yamlcore/

import yaml
from yamlcore import CoreDumper

openapi_yaml = yaml.dump(openapi_json, Dumper=CoreDumper)
PrefCode:
    enum:
    - '01'
    - '02'
    - '03'
    - '04'
    - '05'
    - '06'
    - '07'
    - '08'
    - '09'
    - '10'
    - '11'
    # ...以下省略...
GitHubで編集を提案

Discussion