Apple Numbers to Excel 変換スクリプトの品質・用途適性評価

このコードは誰向けか

  • CLIツールとして変換作業を自動化・バッチ処理したい利用者向け

  • データ移行や定常的なファイル変換パイプラインを構築・修正する開発者向け

  • 型ヒントや構造化された関数分割を参考にしたい教育用途(Python中級者向け)

  • 単独のスクリプトとして保守・カスタマイズを考える開発者向け(外部の公開ライブラリとしてインポートされることは想定されていない構造です)

用途に対する適性評価

CLIツール・バッチ処理用途

単独のCLIツールまたはバッチ処理のスクリプトとして非常に適した構造となっています。argparse による引数解析の明確な定義、同名ファイルの回避や --overwrite の実装、さらに atomic_save によるファイル破損対策が組み込まれており、安定した自動化処理に寄与します。

公開ライブラリ・再利用用途

処理ごとに関数が細かく分割されモジュール化が進んでいますが、現状のまま他のPythonプロジェクトからインポートして再利用するには制限があります。main 関数内で直接 sys.stderr に出力する設計や、ConversionStats に依存した副作用を伴う設計となっているため、APIとして利用するにはインターフェースの改修が必要となる可能性があります。

コードの長所

  • 異常系対策と堅牢性 atomic_save 関数において、一時ファイル (tempfile.mkstemp) に書き込んだ後、load_workbook で一度読み込みテストを行ってから対象ファイルを置換する構造となっており、処理中のクラッシュなどによる出力ファイルの破損を防ぐ配慮がなされています。

  • 極限条件への配慮(数値処理) normalize_value 関数内で、math.isnan(value) や math.isinf(value) を用いた条件分岐が実装されています。Excelで表現できない非数や無限大を "NaN", "Infinity", "-Infinity" といった文字列にフォールバックしており、数値変換時の予期せぬエラーを防いでいます。

  • モジュール化と可読性 スタイルの変換処理 (make_font, make_fill, make_alignment など) や、出力パスの解決 (resolve_output) など、機能ごとに小規模な関数に分離されており、__future__ annotations や typing による型アノテーションが徹底されているため、コードの意図が読み取りやすい構成です。

  • ログ出力とユーザーフィードバック ConversionStats.warn メソッドにおいて警告件数の上限(デフォルト50件)を設け、巨大なシートの変換時などにコンソール出力が膨大になるのを抑制する工夫が確認できます。

問題点と制限事項

  • broad exceptとSilent Failureの可能性 apply_source_style や add_hyperlink 関数において except Exception: が使用されています。一部の書式エラーが全体の変換処理を止めないための意図は推察できますが、Typoやメモリ不足など想定外のバグも握りつぶしてしまう(Silent Failure)制限があります。

  • Any型への依存と動的属性の多用 外部ライブラリ (numbers-parser) に由来する引数(source_cell, style, source_border など)が Any 型で定義され、内部で getattr(..., default) が多用されています。ライブラリ側の仕様変更が発生した際、型チェッカーで検知できず実行時にデフォルト値へフォールバックされるため、将来的な保守の際に原因特定が難しくなる可能性があります。

  • 関数責務の集中(巨大関数の兆候) convert_table 関数が、セル値の解決、スタイルの適用、行高・列幅の計算、結合セルの処理をすべて一手に担っています。ネストが深く行数も多いため、将来的に機能拡張を行う際にコードが複雑化する余地を残しています。

  • 数値処理の精度落ちの懸念 normalize_value 内に isinstance(value, Decimal) の場合 float(value) へキャストする処理があります。極端に精度が高い値や極小値を含むデータの場合、このキャストによってアンダーフローや丸め誤差(精度落ち)が発生する可能性があります。

  • メモリ消費の懸念 table.rows(values_only=False) や list(sheet.tables) のように、変換元データを一括でリスト化して処理する記述が見受けられます。極端に巨大なスプレッドシートを入力とした場合、メモリ消費が増大する可能性があります(ただし、依存ライブラリ内部の遅延評価の有無まではコード断片からは判断できません)。

優先順位が高い改善提案

  1. 例外捕捉範囲の限定 add_hyperlink、apply_source_style、および convert_table 内の行高・列幅調整などの except Exception: を、AttributeError や ValueError、TypeError など、実際に発生しうる具体的な例外クラスに限定する。

  2. convert_table の内部処理の分割 ネストされたループ内で行われている各セルに対する処理を別関数として切り出す。 例: セルの書き込みと装飾を担う process_single_cell(xl_cell, source_cell, stats, ...) といった関数を新たに定義する。

  3. Any 型から具体的な型またはプロトコルへの移行 numbers-parser の提供するオブジェクトに対して、必要な属性を定義した typing.Protocol を作成するか、ライブラリが提供する具体的なクラスをインポートして型アノテーションを付与し、getattr への依存を減らす。

  4. ライブラリとしての再利用性(APIとCLIの分離) main 関数内のエラー出力を print(..., file=sys.stderr) から logging モジュールを用いたログ出力に置き換える。または、変換処理全体を束ねるクラス(例えば NumbersToExcelConverter など)を定義し、CLIの引数解析と実際の変換ロジックをより明確に分離する。

  5. Decimal型の取り扱い検証 Decimal を強制的に float に変換する処理について、高い数値精度が要求されるケースを想定し、Excel(openpyxl)側へ文字列ベースなどで精度を維持したまま数値を書き込む手段がないか検証・検討する。