tests/test-atomictempfile.py
author Greg Ward <greg@gerg.ca>
Thu, 25 Aug 2011 20:21:04 -0400
changeset 15057 774da7121fc9
parent 14007 d764463b433e
child 18666 fb9d1c2805ff
permissions -rw-r--r--
atomictempfile: make close() consistent with other file-like objects. The usual contract is that close() makes your writes permanent, so atomictempfile's use of close() to *discard* writes (and rename() to keep them) is rather unexpected. Thus, change it so close() makes things permanent and add a new discard() method to throw them away. discard() is only used internally, in __del__(), to ensure that writes are discarded when an atomictempfile object goes out of scope. I audited mercurial.*, hgext.*, and ~80 third-party extensions, and found no one using the existing semantics of close() to discard writes, so this should be safe.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     1
import os
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     2
import glob
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     3
from mercurial.util import atomictempfile
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     4
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     5
# basic usage
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     6
def test1_simple():
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     7
    if os.path.exists('foo'):
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     8
        os.remove('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
     9
    file = atomictempfile('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    10
    (dir, basename) = os.path.split(file._tempname)
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    11
    assert not os.path.isfile('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    12
    assert basename in glob.glob('.foo-*')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    13
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    14
    file.write('argh\n')
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
    15
    file.close()
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    16
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    17
    assert os.path.isfile('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    18
    assert basename not in glob.glob('.foo-*')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    19
    print 'OK'
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    20
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
    21
# discard() removes the temp file without making the write permanent
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
    22
def test2_discard():
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    23
    if os.path.exists('foo'):
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    24
        os.remove('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    25
    file = atomictempfile('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    26
    (dir, basename) = os.path.split(file._tempname)
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    27
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    28
    file.write('yo\n')
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
    29
    file.discard()
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    30
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    31
    assert not os.path.isfile('foo')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    32
    assert basename not in os.listdir('.')
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    33
    print 'OK'
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    34
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    35
# if a programmer screws up and passes bad args to atomictempfile, they
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    36
# get a plain ordinary TypeError, not infinite recursion
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    37
def test3_oops():
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    38
    try:
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    39
        file = atomictempfile()
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    40
    except TypeError:
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    41
        print "OK"
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    42
    else:
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    43
        print "expected TypeError"
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    44
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    45
if __name__ == '__main__':
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    46
    test1_simple()
15057
774da7121fc9 atomictempfile: make close() consistent with other file-like objects.
Greg Ward <greg@gerg.ca>
parents: 14007
diff changeset
    47
    test2_discard()
14007
d764463b433e atomictempfile: avoid infinite recursion in __del__().
Greg Ward <greg@gerg.ca>
parents:
diff changeset
    48
    test3_oops()