テクノロジー · 実用ガイド

NamedTemporaryFile は POSIX で動くのに Windows で失敗?再オープンと削除契約を選ぶ

一時パスには作成者、二次オープン、cleanup の三者がいます。名前を渡す前に、どの handle を開いたままにするか決めます。

Original diagram showing creator, consumer, and cleanup as three owners of a named temporary file.
オリジナルイラスト:作成者、consumer、cleanup の責任を先に結ぶ。 Watch at Ease

NamedTemporaryFile は可視パスを返しますが、すべての二次 handle が再オープン、rename、delete できる保証ではありません。POSIX と Windows では open handle の共有規則が異なります。

作成前に lifetime contract を選び、delete と delete_on_close を結び付け、不互換 handle を context 終了前に閉じ、consumer 成功と最終削除を検証します。

次の所有者を先に決める

Write down whether the next user is the same Python handle, a second Python open, a library that accepts a path, or an external process. Also state whether that consumer needs only read/write access or may rename, replace, or keep the file mapped.

If the consumer accepts a file object, prefer passing the existing object and avoid a second pathname open. If it requires a path, the handle and cleanup contract must be explicit.

三つの lifetime contract から選ぶ

For same-context reopen on Python 3.12+, delete=True with delete_on_close=False keeps automatic context-exit cleanup while allowing an ordinary second open on Windows. Close that second handle before leaving the context.

For an external process or API that cannot share delete access, flush and close the producer, use delete=False, pass the path, wait for the consumer, then remove the file in finally. For a specialized second Python open that shares delete access, use the documented O_TEMPORARY route only when every participant follows the same contract.

flush、close、process 完了を分ける

flush makes Python buffers visible but does not release the Windows handle or its share-mode record. close releases that handle. Waiting for the subprocess proves only that process exit occurred; it does not prove another library or mapped view released the file.

Keep the producer, consumer, and cleanup timestamps in a small ledger. A cleanup PermissionError is evidence of an outstanding handle or missing delete right, not a reason to silently leak the path.

rename と delete を別アクセスとして扱う

Microsoft documents that delete access includes rename. A file can be readable and writable yet still reject os.replace, fileinput in-place editing, or cleanup because a prior handle did not share delete access.

Do not diagnose every WinError 32 as another process. Record the exact operation, every handle you own, whether each is closed, and whether the consumer might retain a mapping.

両 platform で検証する

Create a fixture that writes bytes, reopens or hands off the path exactly as production does, confirms the consumer read the expected hash, closes every handle, exits the context, and asserts whether the path should exist. Run it on Windows and POSIX.

For delete=False, assert deletion in finally and fail loudly if removal fails. For delete_on_close=False, assert the second handle closes before context exit. Also test the exception path so cleanup is not dependent on a successful consumer.

Original diagram comparing incompatible and compatible Windows file sharing contracts.
オリジナルイラスト:Windows は全 open handle の share mode を検証する。 Watch at Ease