Open Files Using with

ID

python.open_files_with

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Python

Tags

reliability, resource-leak

Description

Reports calls to open(…​) that are not used as the resource expression of a with statement. Any open file that is not bound through with open(…​) as f: relies on the caller to remember to close it, which is fragile under exceptions and easy to forget when a function returns early or chains a call on the result.

f = open(path)                  # FLAW — never closed on exception
data = open(path).read()        # FLAW — file descriptor leaks

with open(path) as f:           # OK
    data = f.read()

Rationale

A bare f = open(path) puts the burden on the programmer to track the file descriptor lifetime through every code path. Any exception raised between the open call and the eventual f.close() leaves the descriptor open until the garbage collector finalizes it, which on CPython usually happens promptly but on PyPy or under reference cycles can be delayed indefinitely.

The chained form open(path).read() is even worse: the file object becomes unreachable as soon as the call returns, so the descriptor closes on garbage collection rather than at a deterministic point. That is enough to exhaust the per-process descriptor limit on long-running services.

The with statement attaches the file’s exit handler to the surrounding block, so the file always closes — including when the block raises.

Remediation

Wrap the open call in a with block:

with open(path) as f:
    data = f.read()

For multiple resources, chain them in a single with:

with open(src) as fin, open(dst, "w") as fout:
    fout.write(fin.read())