Commit 8fcf4df8 by rfkelly0

add module "fs.filelike" with utils for building file-like objects.

This is a local copy of the guts of my "filelike" module, re-licensed under
the MIT license.

This commit also uses it to fix a few edge-cases in various filesystem
implementations (e.g. truncating StringIO objects).
parent 739272ca
...@@ -57,4 +57,6 @@ ...@@ -57,4 +57,6 @@
* Added utils.isdir(fs,path,info) and utils.isfile(fs,path,info); these * Added utils.isdir(fs,path,info) and utils.isfile(fs,path,info); these
can often determine whether a path is a file or directory by inspecting can often determine whether a path is a file or directory by inspecting
the info dict and avoid an additional query to the filesystem. the info dict and avoid an additional query to the filesystem.
* Added utility module 'fs.filelike' with some helpers for building and
manipulating file-like objects.
...@@ -12,15 +12,13 @@ Contributed under the terms of the BSD License: ...@@ -12,15 +12,13 @@ Contributed under the terms of the BSD License:
http://www.opensource.org/licenses/bsd-license.php http://www.opensource.org/licenses/bsd-license.php
""" """
from struct import pack, unpack
from fs.base import * from fs.base import *
from fs.memoryfs import MemoryFS from fs.memoryfs import MemoryFS
from fs.contrib.bigfs.subrangefile import SubrangeFile from fs.filelike import StringIO
from struct import pack, unpack from fs.contrib.bigfs.subrangefile import SubrangeFile
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
class BIGEntry: class BIGEntry:
def __init__(self, filename, offset, storedSize, isCompressed, realSize): def __init__(self, filename, offset, storedSize, isCompressed, realSize):
......
...@@ -29,7 +29,6 @@ import stat as statinfo ...@@ -29,7 +29,6 @@ import stat as statinfo
import time import time
import SocketServer as sockserv import SocketServer as sockserv
import threading import threading
from StringIO import StringIO
import paramiko import paramiko
...@@ -37,6 +36,7 @@ from fs.base import flags_to_mode ...@@ -37,6 +36,7 @@ from fs.base import flags_to_mode
from fs.path import * from fs.path import *
from fs.errors import * from fs.errors import *
from fs.local_functools import wraps from fs.local_functools import wraps
from fs.filelike import StringIO
# Default host key used by BaseSFTPServer # Default host key used by BaseSFTPServer
......
This diff is collapsed. Click to expand it.
...@@ -29,11 +29,6 @@ import re ...@@ -29,11 +29,6 @@ import re
from socket import error as socket_error from socket import error as socket_error
from fs.local_functools import wraps from fs.local_functools import wraps
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import time import time
import sys import sys
......
...@@ -16,11 +16,7 @@ from fs.path import iteratepath, pathsplit, normpath ...@@ -16,11 +16,7 @@ from fs.path import iteratepath, pathsplit, normpath
from fs.base import * from fs.base import *
from fs.errors import * from fs.errors import *
from fs import _thread_synchronize_default from fs import _thread_synchronize_default
from fs.filelike import StringIO
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
def _check_mode(mode, mode_chars): def _check_mode(mode, mode_chars):
......
...@@ -3,9 +3,10 @@ fs.multifs ...@@ -3,9 +3,10 @@ fs.multifs
========== ==========
A MultiFS is a filesytem composed of a sequence of other filesystems, where A MultiFS is a filesytem composed of a sequence of other filesystems, where
the directory structure of each filesystem is overlaid over the previous filesystem. the directory structure of each filesystem is overlaid over the previous
When you attempt to access a file from the MultiFS it will try each 'child' filesystem. When you attempt to access a file from the MultiFS it will try
FS in order, until it either finds a path that exists or raises a ResourceNotFoundError. each 'child' FS in order, until it either finds a path that exists or raises a
ResourceNotFoundError.
One use for such a filesystem would be to selectively override a set of files, One use for such a filesystem would be to selectively override a set of files,
to customize behaviour. For example, to create a filesystem that could be used to customize behaviour. For example, to create a filesystem that could be used
...@@ -61,11 +62,11 @@ from fs.errors import ResourceNotFoundError ...@@ -61,11 +62,11 @@ from fs.errors import ResourceNotFoundError
class MultiFS(FS): class MultiFS(FS):
"""A MultiFS is a filesystem that delegates to a sequence of other filesystems. """A filesystem that delegates to a sequence of other filesystems.
Operations on the MultiFS will try each 'child' filesystem in order, until it
succeeds. In effect, creating a filesystem that combines the files and dirs of
its children.
Operations on the MultiFS will try each 'child' filesystem in order, until
it succeeds. In effect, creating a filesystem that combines the files and
dirs of its children.
""" """
def __init__(self): def __init__(self):
......
...@@ -14,17 +14,7 @@ from fs.base import * ...@@ -14,17 +14,7 @@ from fs.base import *
from fs.errors import * from fs.errors import *
from fs.path import * from fs.path import *
from StringIO import StringIO from fs.filelike import StringIO
if hasattr(StringIO,"__exit__"):
class StringIO(StringIO):
pass
else:
class StringIO(StringIO):
def __enter__(self):
return self
def __exit__(self,exc_type,exc_value,traceback):
self.close()
return False
def re_raise_faults(func): def re_raise_faults(func):
...@@ -173,14 +163,19 @@ class RPCFS(FS): ...@@ -173,14 +163,19 @@ class RPCFS(FS):
f.seek(0,2) f.seek(0,2)
oldflush = f.flush oldflush = f.flush
oldclose = f.close oldclose = f.close
oldtruncate = f.truncate
def newflush(): def newflush():
oldflush() oldflush()
self.proxy.set_contents(path,xmlrpclib.Binary(f.getvalue())) self.proxy.set_contents(path,xmlrpclib.Binary(f.getvalue()))
def newclose(): def newclose():
f.flush() f.flush()
oldclose() oldclose()
def newtruncate(size=None):
oldtruncate(size)
f.flush()
f.flush = newflush f.flush = newflush
f.close = newclose f.close = newclose
f.truncate = newtruncate
return f return f
def exists(self, path): def exists(self, path):
......
...@@ -109,7 +109,7 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases): ...@@ -109,7 +109,7 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
f = self.fs.open('test.txt', 'rb') f = self.fs.open('test.txt', 'rb')
self.assertEquals(f.read(10), contents[:10]) self.assertEquals(f.read(10), contents[:10])
f.file.seek(0, SEEK_END) f.wrapped_file.seek(0, SEEK_END)
self.assertEquals(f._rfile.tell(), 10) self.assertEquals(f._rfile.tell(), 10)
f.seek(20) f.seek(20)
self.assertEquals(f.tell(), 20) self.assertEquals(f.tell(), 20)
...@@ -136,9 +136,9 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases): ...@@ -136,9 +136,9 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
f._rfile.seek(len(contents[:-5])) f._rfile.seek(len(contents[:-5]))
# Write 10 new characters (will make contents longer for 5 chars) # Write 10 new characters (will make contents longer for 5 chars)
f.write(u'1234567890') f.write(u'1234567890')
f.flush()
# We are on the end of file (and buffer not serve anything anymore) # We are on the end of file (and buffer not serve anything anymore)
self.assertEquals(f.read(), '') self.assertEquals(f.read(), '')
f.close()
self.fakeOn() self.fakeOn()
......
...@@ -11,15 +11,11 @@ import datetime ...@@ -11,15 +11,11 @@ import datetime
from fs.base import * from fs.base import *
from fs.path import * from fs.path import *
from fs.errors import * from fs.errors import *
from fs.filelike import StringIO
from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED, BadZipfile, LargeZipFile from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED, BadZipfile, LargeZipFile
from memoryfs import MemoryFS from memoryfs import MemoryFS
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import tempfs import tempfs
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment