On Mar 15, 2009, at 3:25 PM, Greg Ewing wrote:

 with renaming_file("blarg.txt", "w") as f:
   ...


By chance during the weekend I actually wrote something like that:

from __future__ import with_statement

import os
import codecs
import shutil
import tempfile

from contextlib import contextmanager

TDIR = tempfile.mktemp(dir='/tmp/')

@contextmanager
def topen(filepath, mode='wb', bufsize=-1, encoding=None,
          inplace=False, tmpd=TDIR, sync=False):
    """
    C{topen} is a transactional version of the Python builtin C{open}
    function for file IO. It manages transactionality by using a
    temporary file and then moving it to the final position once its
    content has been written to disk.
    If the mode used to open the file doesn't modify the file, this
    function is equivalent to the built-in C{open} with automatic
    file closing behavior.

    @param filepath: The path of the file that you want to open
    @type filepath: C{str}

    @param mode: POSIX mode in which you want to open the file.
    @type mode: C{str} see documentation for the format.

    @param bufsize: Buffer size for file IO
    @type bufsize: C{int} see documentation for the meaning

    @param encoding: Encoding that should be used to read the file
    @type encoding: C{str}

    @param inplace: Indicates if the temporary file should reside
                    in the same directory of the final file.
    @type inplace: C{bool}

    @param tmpd: The temporary directory in which file IO is
                 performed. Then files are moved from here to
                 their original destination.
    @type tmpd: C{str}

    @param sync: Force topen to fsync the file before closing it
    @type sync: C{bool}
    """
    if 'r' in mode or 'a' in mode:
        fp = filepath
    else:
        if inplace:
            source_dir, _ = os.path.split(filepath)
            tmpd = source_dir

        if not os.path.exists(tmpd):
            os.makedirs(tmpd)
        _f, fp = tempfile.mkstemp(dir=tmpd)

    if encoding is not None:
        f = codecs.open(fp, mode, encoding=encoding)
    else:
        f = open(fp, mode, bufsize)

    try:
        yield f
    finally:
        if 'r' in mode:
            if "+" in mode:
                f.flush()
                if sync:
                    os.fsync(f.fileno())
            f.close()
            return

        f.flush()
        if sync:
            os.fsync(f.fileno())
        f.close()
        if 'w' in mode:
            shutil.move(fp, filepath)

if __name__ == "__main__":
    with topen("a_test") as f:
        f.write("hello")
    assert file("a_test", "rb").read() == 'hello'
    assert os.path.exists(TDIR)
    os.rmdir(TDIR)

    with topen("a_test", mode="rb") as f:
        assert f.read() == "hello"
    assert not os.path.exists(TDIR)
    os.remove("a_test")


--
Valentino Volonghi aka Dialtone
Now running MacOS X 10.5
Home Page: http://www.twisted.it
http://www.adroll.com

Attachment: PGP.sig
Description: This is a digitally signed message part

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to