excel-tableとは
excel-tableは、Excelを構造化されたI/Oとして扱うためのPythonライブラリです。
ExcelのフォーマットをPydanticモデルとして定義し、
そのモデルに対して読み書きを行うことで、
- フォーマット変更に強く
- I/Oと処理ロジックを分離できる
ようにすることを目的としています。
問題定義
Excelをデータの入出力インターフェースとして使うケースは多いように思います。
一方で、Excelをプログラムから扱う場合、多くは openpyxl などを用いてセル座標ベースで処理を書くことになるかと思います。
この方法は柔軟ではありますが、フォーマット変更に弱く、コードの保守性を下げる要因になることがあります。
例えば、
- 列や行が1つずれる
- テーブルの配置が変わる
といった変更が入るだけで、
処理ロジック全体を書き直す必要がある
という状態になりがちな気がします(自分だけかもしれませんが、、、)。
特に問題になるのは、
フォーマット定義と処理ロジックがコードの中で混在してしまうこと
だと考えています。
本来、これらはI/Oの問題であるにも関わらず、
処理ロジック側まで巻き込んで変更が必要になるのは、
両者が分離されていないためだと考えられます。
解決方針
Excelの構造をPydanticモデルとして定義し、そのモデルに対して読み書きを行う形にすれば上記問題を解決できるのではないかと思います。
これにより、フォーマット変更はモデル変更に閉じ、
I/Oと処理ロジックを分離できます。
最小例
# 書き込み
from excel_table.models import Table2D, FormattedTable2D
from excel_table.writer import SheetWriteSchema, write_sheet_bytes
table = FormattedTable2D(
table=Table2D(
title="Example",
column_label="X",
row_label="Y",
column=[1, 2, 3],
row=[1, 2],
values=[[1, 2, 3], [4, 5, 6]],
)
)
schema = SheetWriteSchema(rows=[[table]])
xlsx_bytes = write_sheet_bytes("Sheet1", schema)
# 読み込み
from excel_table.reader import SheetReadSchema, read_sheet_bytes
from excel_table.models import Table2DFloat
from excel_table.models.table_format import FormattedTable2DSchema
schema = SheetReadSchema(
columns=[
FormattedTable2DSchema(title="Example", table_type=Table2DFloat),
]
)
result = read_sheet_bytes(xlsx_bytes, "Sheet1", schema)
table = result[0][0]
print(table.title, table.values)
このように、Excelの構造をそのままモデルとして表現し、
writeだけでなく、titleベースでテーブルを特定して読み取ることもできます。
セル座標ではなく、構造を直接扱う形になる点が特徴です。
設計について
なぜこの設計にしたか
いくつかの設計判断について補足します。
- バリデーションはPydanticに任せる
- 識別はtitleベースにする
- Excelの可読性・編集性を壊さない
特に重要だと考えているのは、
Excelをブラックボックス化しないこと
です。
Excelを使う理由は、セルやレイアウトを通じて構造を人間が理解できる点にあると思います。
そのため、
- セル構造に従って読み書きする
- Excelを見れば挙動が分かる
という性質を維持するように設計しています。
概念
このライブラリは、大きく
- 書き込み側(Write)
- 読み取り側(Read)
の2つの面を持っています。
全体構造は以下の通りです。
想定ユースケース
- 入力だけ人手で揺れる
- 処理ロジックは共通
- フォーマット統一が難しい
例えば、
同じ測定であっても、装置や分析会社によって記載フォーマットが全く異なるということもあるかと思います
このような状況で、
- 入力(Excel)と処理(コード)を分離する
ためのI/O層として使えると考えています。
Excelレポートの生成
読み取ったデータは、そのままExcelとして再出力することができます。
例えば、以下のようにテーブルからグラフを生成できます。
from excel_table.models import Table2D, FormattedTable2D
from excel_table.models import ChartConfig, LineSeriesConfig
table = FormattedTable2D(
table=Table2D(
title="Example",
column_label="Vgs",
row_label="Vds",
column=[0.0, 0.5, 1.0],
row=[0.0, 0.5, 1.0],
values=[
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
],
)
)
chart = ChartConfig(
chart_type="line",
x_label="Vds",
y_label="Id",
series=[
LineSeriesConfig(
label="IV",
source_block="Example",
x_axis="row",
color_axis="column",
)
],
)
Excel上では、テーブルとそれに対応するグラフが配置されます。
他にも、
- グラフ
- ヒートマップ
などの最低限の出力機能を提供します。
一方で、最終的なフォーマット調整は利用者に委ねています。
このライブラリの位置づけ
excel-tableは、Excelを扱うための汎用的な解法の一つだと考えています。
- 専用システムを作るほどではない
- しかしI/Oはある程度整理したい
といったケースで有効だと思います。
一方で、
- 大規模な業務システム
- 厳密なデータ管理が必要な場合
には、専用設計の方が適していると考えられます。
用途に応じて、
- そのまま使う
- 拡張する
- 別実装に置き換える
といった使い分けが前提になるライブラリです。
デモ