Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: repy/emulfile.py
- ===================================================================
- --- repy/emulfile.py (revision 2330)
- +++ repy/emulfile.py (working copy)
- @@ -16,6 +16,9 @@
- import os
- import idhelper
- +# needed for locking the fileinfo hash
- +import threading
- +
- # I need to rename file so that the checker doesn't complain...
- myfile = file
- @@ -72,10 +75,18 @@
- # Handle the case where the file is open via an exception to prevent the user
- # from removing a file to circumvent resource accounting
- + fileinfolock.acquire()
- for filehandle in fileinfo:
- if filename == fileinfo[filehandle]['filename']:
- + fileinfolock.release()
- raise Exception, 'File "'+filename+'" is open with handle "'+filehandle+'"'
- - return os.remove(filename)
- +
- + try:
- + result = os.remove(filename)
- + finally:
- + fileinfolock.release()
- +
- + return result
- @@ -85,34 +96,129 @@
- def emulated_open(filename, mode="rb"):
- """
- <Purpose>
- - Allows the user program to open a file safely. This function is meant
- - to resemble the builtin "open"
- + Allows the user program to open a file safely. This function is meant
- + to resemble the builtin "open".
- <Arguments>
- filename:
- - The file that should be operated on
- + The file that should be operated on.
- mode:
- - The mode (see open)
- + The mode (see open).
- <Exceptions>
- - As with open, this may raise a number of errors
- + As with open, this may raise a number of errors. Additionally:
- + TypeError if the mode is not a string.
- + ValueError if the modestring is invalid.
- +
- <Side Effects>
- - Opens a file on disk, using a file descriptor. When opened with "w"
- + Opens a file on disk, using a file descriptor. When opened with "w"
- it will truncate the existing file.
- <Returns>
- + A file-like object.
- + """
- +
- + if type(mode) is not str:
- + raise TypeError("Attempted to open file with invalid mode (must be a string).")
- +
- + # We just filter out 'b' / 't' in modestrings because emulated_file opens
- + # everything in binary mode for us.
- +
- + originalmode = mode
- +
- + if 'b' in mode:
- + mode = mode.replace('b','')
- +
- + if 't' in mode:
- + mode = mode.replace('t','')
- +
- + # Now we use our very safe, cross-platform open-like function and other
- + # file-object methods to emulate ANSI file modes.
- +
- + file_object = None
- + if mode == "r":
- + file_object = safe_open(filename, "r")
- +
- + elif mode == "r+":
- + file_object = safe_open(filename, "rw")
- +
- + elif mode == "w" or mode == "w+":
- + file_object = safe_open(filename, "rw", create=True)
- + fileinfo[file_object.filehandle]['fobj'].truncate()
- +
- + elif mode == "a" or mode == "a+":
- + file_object = safe_open(filename, "rw", create=True)
- + file_object.seek(0, os.SEEK_END)
- +
- +
- + if file_object is None:
- + raise ValueError("Invalid or unsupported mode ('%s') passed to open()." % originalmode)
- +
- + return file_object
- +
- +
- +
- +
- +def safe_open(filename, mode="r", create=False):
- + """
- + <Purpose>
- + Allows the user program to open a file safely. This function is not
- + meant to resemble the builtin "open".
- +
- + <Arguments>
- + filename:
- + The file that should be operated on
- + mode:
- + The mode:
- + "r": Open the file for reading.
- + "rw": Open the file for reading and writing.
- +
- + These are the only valid modes accepted by this version of
- + open(). Note: files are always opened in "binary" mode.
- + create:
- + If True, create the file if it doesn't exist already.
- +
- + <Exceptions>
- + As with open, this may raise a number of errors. Additionally:
- +
- + ValueError is raised if this is passed an invalid mode.
- +
- + <Side Effects>
- + Opens a file on disk, using a file descriptor.
- +
- + <Returns>
- A file-like object
- """
- - restrictions.assertisallowed('open',filename,mode)
- + # Only allow 'r', 'rw', and 'U'.
- - return emulated_file(filename, mode)
- + actual_mode = None
- + if mode == "r":
- + actual_mode = "rb"
- + elif mode == "rw":
- + actual_mode = "r+b"
- +
- + if actual_mode is None:
- + raise ValueError("Valid modes for opening a file in repy are 'r' and 'rw'.")
- + restrictions.assertisallowed('open', filename, actual_mode)
- + if create and not os.path.exists(filename):
- + # Create a file by opening it in write mode and then closing it.
- + restrictions.assertisallowed('open', filename, "wb")
- + create_file = emulated_file(filename, "wb")
- + create_file.close()
- +
- + return emulated_file(filename, actual_mode)
- +
- +
- +
- +
- # This keeps the state for the files (the actual objects, etc.)
- fileinfo = {}
- +fileinfolock = threading.Lock()
- @@ -171,15 +277,37 @@
- # It must have a 'b'
- mode = mode + 'b'
- - assert_is_allowed_filename(filename)
- + # Here we are checking that we only open a given file once in 'write' mode
- + # so that file access is more uniform across platforms. (On Microsoft
- + # Windows, for example, writing to the same file from two different file-
- + # handles throws an error because of the way Windows (by default) locks
- + # files opened for writing.)
- + fileinfolock.acquire()
- - self.filehandle = idhelper.getuniqueid()
- + try:
- + # Check the entire fileinfo dictionary for the same file already being
- + # open.
- + for fileinfokey in fileinfo.keys():
- - nanny.tattle_add_item('filesopened',self.filehandle)
- + # If the filename matches this one, raise an exception.
- + if os.path.abspath(fileinfo[fileinfokey]['filename']) == \
- + os.path.abspath(filename)
- + raise ArgumentError(\
- + "A file is only allowed to have one open filehandle.")
- - fileinfo[self.filehandle] = {'filename':filename, 'mode':mode,'fobj':myfile(filename,mode)}
- - self.name=filename
- - self.mode=mode
- + assert_is_allowed_filename(filename)
- +
- + self.filehandle = idhelper.getuniqueid()
- +
- + nanny.tattle_add_item('filesopened',self.filehandle)
- +
- + fileinfo[self.filehandle] = {'filename':filename, 'mode':mode,'fobj':myfile(filename,mode)}
- + self.name=filename
- + self.mode=mode
- +
- + finally:
- + fileinfolock.release()
- +
- return None
- @@ -203,11 +331,16 @@
- nanny.tattle_remove_item('filesopened',myfilehandle)
- - returnvalue = fileinfo[myfilehandle]['fobj'].close()
- + fileinfolock.acquire()
- + try:
- + returnvalue = fileinfo[myfilehandle]['fobj'].close()
- - # delete the filehandle
- - del fileinfo[myfilehandle]
- + # delete the filehandle
- + del fileinfo[myfilehandle]
- + finally:
- + fileinfolock.release()
- +
- return returnvalue
- Index: repy/tests/z_testopen.py
- ===================================================================
- --- repy/tests/z_testopen.py (revision 0)
- +++ repy/tests/z_testopen.py (revision 0)
- @@ -0,0 +1,55 @@
- +# Some tests to ensure open() behaves like our definition.
- +
- +SEEK_SET = 0 # Absolute
- +SEEK_CUR = 1 # Relative
- +SEEK_END = 2 # End of the file
- +
- +try:
- + # Test basic writing / reading
- + fro = open("junk_test.out", "w+")
- + fro.write("hi!")
- + fro.flush()
- + fro.seek(0, SEEK_SET)
- + contents = fro.read()
- + fro.close()
- + if contents != "hi!":
- + print "Failed to write to / read from file!"
- +
- + fro = open("junk_test.out", "r")
- + contents = fro.read()
- + fro.close()
- + if contents != "hi!":
- + print "Failed to write to / read from file!"
- +
- + # Test "w" semantics
- + fro = open("junk_test.out", "w+")
- + contents = fro.read()
- + if contents != "":
- + print "Write mode fails to truncate file!"
- + fro.seek(0, SEEK_SET)
- + fro.write("Testing 123")
- + fro.close()
- +
- + # Test append
- + fro = open("junk_test.out", "a+")
- + fro.write("abc")
- + fro.flush()
- + fro.seek(0, SEEK_SET)
- + contents = fro.read()
- + fro.close()
- + if contents != "Testing 123abc":
- + print "Append mode fails to append!"
- +
- + # Test universal newlines
- + fro = open("junk_test.out", "w+")
- + fro.write("Hello\rMac\r\nWindows\nUnix World!")
- + fro.close()
- + fro = open("junk_test.out", "rU")
- + contents = fro.read()
- + fro.close()
- + if contents != "Hello\nMac\nWindows\nUnix World!":
- + print "Universal readline mode fails to read universally!"
- +
- +finally:
- + if "junk_test.out" in listdir():
- + removefile("junk_test.out")
Add Comment
Please, Sign In to add comment