Search code examples
pythontemporary-files

seek(0) versus flush() on tempfile.NamedTemporaryFile before calling subprocess.run on a generated script


Below is a example script to generate a Bash script into a temporary file, execute it, allow stdout and stderr to be emitted to the stdout of the calling script, and automatically delete the file.

When I set use_fix = True as stated below, and set use_seek to either True or False, the script works: I see output. But if I set use_fix = False, it does not work.

My question is this: Under the case of use_fix = True, which setting of use_seek is correct? More interestingly, why would I prefer one value over the other? My gut tells me that f.flush() is correct, because that is what I think is required: The buffered I/O needs to be flushed to disk before the subsequent child process can open that script and execute it. Could it be that the seek is also forcing a flush, as a side-effect?

import tempfile

use_fix = True
use_seek = False
# use_seek = True
# Create a temporary file with a bash script
with tempfile.NamedTemporaryFile(prefix="/tmp/xxx.out.", suffix=".sh", mode='w+t', delete=True) as f:
    f.write("#!/bin/bash\necho 'This is a temporary bash script'\necho 'error message' >&2")

    if use_fix:
        # Allow subprocess.run to "see" the temporary file contents on disk:
        if use_seek:
            f.seek(0)
        else:
            # Allow subprocess.run to "see" the output.
            f.flush()

    # Execute the bash script and capture its standard output and standard error
    result = subprocess.run(["bash", f.name], stdout=sys.stdout, stderr=subprocess.STDOUT)

Solution

  • You should just use f.flush() if you only need to flush output. You would use f.seek() if you want to overwrite what you just wrote; the fact that it flushes is just an extra side effect. But it's not documented as far as I can tell, so you shouldn't rely on it.

    According to Does Python automatically flush its buffer when calling seek and/or read operations following a write? CPython only flushes the buffer when you use SEEK_END, I'm not sure why you're seeing the flush when you use SEEK_SET.