Commit 754fcc98 by willmcgugan

First stab at a Python3 port

parent 87a736d5
......@@ -35,6 +35,10 @@ from fs.path import *
from fs.errors import *
from fs.local_functools import wraps
import compatibility
import six
from six import PY3
class DummyLock(object):
"""A dummy lock object that doesn't do anything.
......@@ -703,7 +707,7 @@ class FS(object):
return sys_path
def getcontents(self, path):
def getcontents(self, path, mode="rb"):
"""Returns the contents of a file as a string.
:param path: A path of file to read
......@@ -712,7 +716,7 @@ class FS(object):
"""
f = None
try:
f = self.open(path, "rb")
f = self.open(path, mode)
contents = f.read()
return contents
finally:
......@@ -731,23 +735,7 @@ class FS(object):
if not data:
self.createfile(path)
else:
f = None
try:
f = self.open(path, 'wb')
if hasattr(data, "read"):
read = data.read
write = f.write
chunk = read(chunk_size)
while chunk:
write(chunk)
chunk = read(chunk_size)
else:
f.write(data)
if hasattr(f, 'flush'):
f.flush()
finally:
if f is not None:
f.close()
compatibility.copy_file_to_fs(data, self, path, chunk_size=chunk_size)
def setcontents_async(self,
path,
......@@ -777,7 +765,53 @@ class FS(object):
if progress_callback is None:
progress_callback = lambda bytes_written:None
finished_event = threading.Event()
def do_setcontents():
if PY3:
try:
f = None
try:
progress_callback(0)
if hasattr(data, "read"):
bytes_written = 0
read = data.read
chunk = read(chunk_size)
if isinstance(chunk, six.text_type):
f = self.open(path, 'w')
else:
f = self.open(path, 'wb')
write = f.write
while chunk:
write(chunk)
bytes_written += len(chunk)
progress_callback(bytes_written)
chunk = read(chunk_size)
else:
if isinstance(data, six.text_type):
f = self.open(path, 'w')
else:
f = self.open(path, 'wb')
f.write(data)
progress_callback(len(data))
if finished_callback is not None:
finished_callback()
finally:
if f is not None:
f.close()
except Exception, e:
if error_callback is not None:
error_callback(e)
raise
finally:
finished_event.set()
else:
try:
f = None
try:
......@@ -812,7 +846,6 @@ class FS(object):
finally:
finished_event.set()
finished_event = threading.Event()
threading.Thread(target=do_setcontents).start()
return finished_event
......
"""
Some functions for Python3 compatibility.
Not for general usage, the functionality in this file is exposed elsewhere
"""
import six
from six import PY3
if PY3:
def copy_file_to_fs(data, dst_fs, dst_path, chunk_size=64 * 1024):
"""Copy data from a string or a file-like object to a given fs/path"""
if hasattr(data, "read"):
read = data.read
chunk = read(chunk_size)
f = None
try:
if isinstance(chunk, six.text_type):
f = dst_fs.open(dst_path, 'w')
else:
f = dst_fs.open(dst_path, 'wb')
write = f.write
while chunk:
write(chunk)
chunk = read(chunk_size)
finally:
if f is not None:
f.close()
else:
f = None
try:
if isinstance(data, six.text_type):
f = dst_fs.open(dst_path, 'w')
else:
f = dst_fs.open(dst_path, 'wb')
f.write(data)
finally:
if f is not None:
f.close()
else:
def copy_file_to_fs(data, dst_fs, dst_path, chunk_size=64 * 1024):
"""Copy data from a string or a file-like object to a given fs/path"""
f = None
try:
f = dst_fs.open(dst_path, 'wb')
if hasattr(data, "read"):
read = data.read
write = f.write
chunk = read(chunk_size)
while chunk:
write(chunk)
chunk = read(chunk_size)
else:
f.write(data)
if hasattr(f, 'flush'):
f.flush()
finally:
if f is not None:
f.close()
......@@ -544,7 +544,7 @@ class MountProcess(subprocess.Popen):
os.close(w)
if os.read(r,1) != "S":
self.terminate()
raise RuntimeError("FUSE error: " + os.read(r,20))
raise RuntimeError("FUSE error: " + os.read(r,20)).decode(NATIVE_ENCODING)
def unmount(self):
"""Cleanly unmount the FUSE filesystem, terminating this subprocess."""
......
......@@ -33,11 +33,6 @@ Other useful classes include:
import tempfile as _tempfile
try:
from cStringIO import StringIO as _StringIO
except ImportError:
from StringIO import StringIO as _StringIO
import fs
......@@ -50,6 +45,17 @@ class NotSeekableError(IOError):
class NotTruncatableError(IOError):
pass
import six
from six import PY3, b
if PY3:
_StringIO = six.BytesIO
else:
try:
from cStringIO import StringIO as _StringIO
except ImportError:
from StringIO import StringIO as _StringIO
class FileLikeBase(object):
"""Base class for implementing file-like objects.
......@@ -265,14 +271,14 @@ class FileLikeBase(object):
if self.closed:
raise IOError("File has been closed")
if self._check_mode("w-") and self._wbuffer is not None:
buffered = ""
buffered = b("")
if self._sbuffer:
buffered = buffered + self._sbuffer
self._sbuffer = None
buffered = buffered + self._wbuffer
self._wbuffer = None
leftover = self._write(buffered,flushing=True)
if leftover:
if leftover and not isinstance(leftover, int):
raise IOError("Could not flush write buffer.")
def close(self):
......@@ -306,7 +312,7 @@ class FileLikeBase(object):
next() returning subsequent lines from the file.
"""
ln = self.readline()
if ln == "":
if ln == b(""):
raise StopIteration()
return ln
......@@ -442,19 +448,19 @@ class FileLikeBase(object):
data = [self._rbuffer]
else:
data = []
self._rbuffer = ""
self._rbuffer = b("")
newData = self._read()
while newData is not None:
data.append(newData)
newData = self._read()
output = "".join(data)
output = b("").join(data)
# Otherwise, we need to return a specific amount of data
else:
if self._rbuffer:
newData = self._rbuffer
data = [newData]
else:
newData = ""
newData = b("")
data = []
sizeSoFar = len(newData)
while sizeSoFar < size:
......@@ -463,20 +469,20 @@ class FileLikeBase(object):
break
data.append(newData)
sizeSoFar += len(newData)
data = "".join(data)
data = b("").join(data)
if sizeSoFar > size:
# read too many bytes, store in the buffer
self._rbuffer = data[size:]
data = data[:size]
else:
self._rbuffer = ""
self._rbuffer = b("")
output = data
return output
def _do_read_rest(self):
"""Private method to read the file through to EOF."""
data = self._do_read(self._bufsize)
while data != "":
while data != b(""):
data = self._do_read(self._bufsize)
def readline(self,size=-1):
......@@ -488,11 +494,11 @@ class FileLikeBase(object):
nextBit = self.read(self._bufsize)
bits.append(nextBit)
sizeSoFar += len(nextBit)
if nextBit == "":
if nextBit == b(""):
break
if size > 0 and sizeSoFar >= size:
break
indx = nextBit.find("\n")
indx = nextBit.find(b("\n"))
# If not found, return whole string up to <size> length
# Any leftovers are pushed onto front of buffer
if indx == -1:
......@@ -508,7 +514,7 @@ class FileLikeBase(object):
extra = bits[-1][indx:]
bits[-1] = bits[-1][:indx]
self._rbuffer = extra + self._rbuffer
return "".join(bits)
return b("").join(bits)
def readlines(self,sizehint=-1):
"""Return a list of all lines in the file."""
......@@ -542,8 +548,8 @@ class FileLikeBase(object):
if self._wbuffer:
string = self._wbuffer + string
leftover = self._write(string)
if leftover is None:
self._wbuffer = ""
if leftover is None or isinstance(leftover, int):
self._wbuffer = b("")
else:
self._wbuffer = leftover
......@@ -649,7 +655,7 @@ class FileWrapper(FileLikeBase):
def _read(self,sizehint=-1):
data = self.wrapped_file.read(sizehint)
if data == "":
if data == b(""):
return None
return data
......@@ -694,7 +700,7 @@ class StringIO(FileWrapper):
if size > curlen:
self.wrapped_file.seek(curlen)
try:
self.wrapped_file.write("\x00"*(size-curlen))
self.wrapped_file.write(b("\x00")*(size-curlen))
finally:
self.wrapped_file.seek(pos)
......@@ -715,7 +721,8 @@ class SpooledTemporaryFile(FileWrapper):
try:
stf_args = (max_size,mode,bufsize) + args
wrapped_file = _tempfile.SpooledTemporaryFile(*stf_args,**kwds)
wrapped_file._file = StringIO()
#wrapped_file._file = StringIO()
wrapped_file._file = six.BytesIO()
self.__is_spooled = True
except AttributeError:
ntf_args = (mode,bufsize) + args
......
......@@ -1170,7 +1170,7 @@ class FTPFS(FS):
self.ftp.storbinary('STOR %s' % _encode(path), data, blocksize=chunk_size)
@ftperrors
def getcontents(self, path):
def getcontents(self, path, mode="rb"):
path = normpath(path)
contents = StringIO()
self.ftp.retrbinary('RETR %s' % _encode(path), contents.write, blocksize=1024*64)
......
......@@ -20,6 +20,9 @@ from fs.filelike import StringIO
from os import SEEK_END
import threading
import six
def _check_mode(mode, mode_chars):
for c in mode_chars:
......@@ -264,10 +267,11 @@ class MemoryFS(FS):
def __str__(self):
return "<MemoryFS>"
__repr__ = __str__
def __repr__(self):
return "MemoryFS()"
def __unicode__(self):
return unicode(self.__str__())
return "<MemoryFS>"
@synchronize
def _get_dir_entry(self, dirpath):
......@@ -600,7 +604,7 @@ class MemoryFS(FS):
dst_dir_entry.xattrs.update(src_xattrs)
@synchronize
def getcontents(self, path):
def getcontents(self, path, mode="rb"):
dir_entry = self._get_dir_entry(path)
if dir_entry is None:
raise ResourceNotFoundError(path)
......
......@@ -91,7 +91,7 @@ class MountFS(FS):
__repr__ = __str__
def __unicode__(self):
return unicode(self.__str__())
return u"<%s [%s]>" % (self.__class__.__name__,self.mount_tree.items(),)
def _delegate(self, path):
path = abspath(normpath(path))
......
......@@ -270,7 +270,7 @@ class OpenerRegistry(object):
file_object.fs = fs
return file_object
def getcontents(self, fs_url):
def getcontents(self, fs_url, mode="rb"):
"""Gets the contents from a given FS url (if it references a file)
:param fs_url: a FS URL e.g. ftp://ftp.mozilla.org/README
......@@ -278,7 +278,7 @@ class OpenerRegistry(object):
"""
fs, path = self.parse(fs_url)
return fs.getcontents(path)
return fs.getcontents(path, mode)
def opendir(self, fs_url, writeable=True, create_dir=False):
"""Opens an FS object from an FS URL
......
......@@ -205,7 +205,8 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
@convert_os_errors
def open(self, path, mode="r", **kwargs):
mode = filter(lambda c: c in "rwabt+",mode)
#mode = filter(lambda c: c in "rwabt+",mode)
mode = ''.join(c for c in mode if c in 'rwabt+')
sys_path = self.getsyspath(path)
try:
return open(sys_path, mode, kwargs.get("buffering", -1))
......
......@@ -39,6 +39,7 @@ from fs import SEEK_SET, SEEK_CUR, SEEK_END
_SENTINAL = object()
from six import PY3, b
class RemoteFileBuffer(FileWrapper):
"""File-like object providing buffer for local file operations.
......@@ -186,7 +187,7 @@ class RemoteFileBuffer(FileWrapper):
self.wrapped_file.seek(curpos)
def _read(self, length=None):
if length < 0:
if length is not None and length < 0:
length = None
with self._lock:
self._fillbuffer(length)
......@@ -668,7 +669,7 @@ class CacheFSMixin(FS):
def getsize(self,path):
return self.getinfo(path)["size"]
def setcontents(self, path, contents="", chunk_size=64*1024):
def setcontents(self, path, contents=b(""), chunk_size=64*1024):
supsc = super(CacheFSMixin,self).setcontents
res = supsc(path, contents, chunk_size=chunk_size)
with self.__cache_lock:
......
......@@ -155,11 +155,11 @@ class S3FS(FS):
super(S3FS,self).__setstate__(state)
self._tlocal = thread_local()
def __str__(self):
def __repr__(self):
args = (self.__class__.__name__,self._bucket_name,self._prefix)
return '<%s: %s:%s>' % args
__repr__ = __str__
__str__ = __repr__
def _s3path(self,path):
"""Get the absolute path to a file stored in S3."""
......
......@@ -177,7 +177,7 @@ class SFTPFS(FS):
self._transport = connection
def __unicode__(self):
return '<SFTPFS: %s>' % self.desc('/')
return u'<SFTPFS: %s>' % self.desc('/')
@classmethod
def _agent_auth(cls, transport, username):
......
......@@ -49,10 +49,10 @@ class TempFS(OSFS):
self._cleaned = False
super(TempFS, self).__init__(self._temp_dir, dir_mode=dir_mode, thread_synchronize=thread_synchronize)
def __str__(self):
def __repr__(self):
return '<TempFS: %s>' % self._temp_dir
__repr__ = __str__
__str__ = __repr__
def __unicode__(self):
return u'<TempFS: %s>' % self._temp_dir
......
......@@ -11,7 +11,7 @@ from __future__ import with_statement
# be captured by nose and reported appropriately
import sys
import logging
logging.basicConfig(level=logging.ERROR, stream=sys.stdout)
#logging.basicConfig(level=logging.ERROR, stream=sys.stdout)
from fs.base import *
from fs.path import *
......@@ -31,6 +31,8 @@ try:
except ImportError:
import dummy_threading as threading
import six
from six import PY3, b
class FSTestCases(object):
"""Base suite of testcases for filesystem implementations.
......@@ -109,54 +111,54 @@ class FSTestCases(object):
def test_writefile(self):
self.assertRaises(ResourceNotFoundError,self.fs.open,"test1.txt")
f = self.fs.open("test1.txt","w")
f.write("testing")
f = self.fs.open("test1.txt","wb")
f.write(b("testing"))
f.close()
self.assertTrue(self.check("test1.txt"))
f = self.fs.open("test1.txt","r")
self.assertEquals(f.read(),"testing")
f = self.fs.open("test1.txt","rb")
self.assertEquals(f.read(),b("testing"))
f.close()
f = self.fs.open("test1.txt","w")
f.write("test file overwrite")
f = self.fs.open("test1.txt","wb")
f.write(b("test file overwrite"))
f.close()
self.assertTrue(self.check("test1.txt"))
f = self.fs.open("test1.txt","r")
self.assertEquals(f.read(),"test file overwrite")
f = self.fs.open("test1.txt","rb")
self.assertEquals(f.read(),b("test file overwrite"))
f.close()
def test_setcontents(self):
# setcontents() should accept both a string...
self.fs.setcontents("hello","world")
self.assertEquals(self.fs.getcontents("hello"),"world")
self.fs.setcontents("hello",b("world"))
self.assertEquals(self.fs.getcontents("hello", "rb"),b("world"))
# ...and a file-like object
self.fs.setcontents("hello",StringIO("to you, good sir!"))
self.assertEquals(self.fs.getcontents("hello"),"to you, good sir!")
self.fs.setcontents("hello",StringIO(b("to you, good sir!")))
self.assertEquals(self.fs.getcontents("hello", "rb"),b("to you, good sir!"))
# setcontents() should accept both a string...
self.fs.setcontents("hello","world", chunk_size=2)
self.assertEquals(self.fs.getcontents("hello"),"world")
self.fs.setcontents("hello",b("world"), chunk_size=2)
self.assertEquals(self.fs.getcontents("hello", "rb"),b("world"))
# ...and a file-like object
self.fs.setcontents("hello",StringIO("to you, good sir!"), chunk_size=2)
self.assertEquals(self.fs.getcontents("hello"),"to you, good sir!")
self.fs.setcontents("hello",StringIO(b("to you, good sir!")), chunk_size=2)
self.assertEquals(self.fs.getcontents("hello", "rb"),b("to you, good sir!"))
def test_setcontents_async(self):
# setcontents() should accept both a string...
self.fs.setcontents_async("hello", "world").wait()
self.assertEquals(self.fs.getcontents("hello"), "world")
self.fs.setcontents_async("hello", b("world")).wait()
self.assertEquals(self.fs.getcontents("hello", "rb"), b("world"))
# ...and a file-like object
self.fs.setcontents_async("hello",StringIO("to you, good sir!")).wait()
self.assertEquals(self.fs.getcontents("hello"), "to you, good sir!")
self.fs.setcontents_async("hello", "world", chunk_size=2).wait()
self.assertEquals(self.fs.getcontents("hello"), "world")
self.fs.setcontents_async("hello",StringIO(b("to you, good sir!"))).wait()
self.assertEquals(self.fs.getcontents("hello"), b("to you, good sir!"))
self.fs.setcontents_async("hello", b("world"), chunk_size=2).wait()
self.assertEquals(self.fs.getcontents("hello", "rb"), b("world"))
# ...and a file-like object
self.fs.setcontents_async("hello", StringIO("to you, good sir!"), chunk_size=2).wait()
self.assertEquals(self.fs.getcontents("hello"), "to you, good sir!")
self.fs.setcontents_async("hello", StringIO(b("to you, good sir!")), chunk_size=2).wait()
self.assertEquals(self.fs.getcontents("hello", "rb"), b("to you, good sir!"))
def test_isdir_isfile(self):
self.assertFalse(self.fs.exists("dir1"))
self.assertFalse(self.fs.isdir("dir1"))
self.assertFalse(self.fs.isfile("a.txt"))
self.fs.setcontents("a.txt", '')
self.fs.setcontents("a.txt", b(''))
self.assertFalse(self.fs.isdir("dir1"))
self.assertTrue(self.fs.exists("a.txt"))
self.assertTrue(self.fs.isfile("a.txt"))
......@@ -172,10 +174,10 @@ class FSTestCases(object):
def check_unicode(items):
for item in items:
self.assertTrue(isinstance(item,unicode))
self.fs.setcontents(u"a", '')
self.fs.setcontents("b", '')
self.fs.setcontents("foo", '')
self.fs.setcontents("bar", '')
self.fs.setcontents(u"a", b(''))
self.fs.setcontents("b", b(''))
self.fs.setcontents("foo", b(''))
self.fs.setcontents("bar", b(''))
# Test listing of the root directory
d1 = self.fs.listdir()
self.assertEqual(len(d1), 4)
......@@ -196,10 +198,10 @@ class FSTestCases(object):
# Create some deeper subdirectories, to make sure their
# contents are not inadvertantly included
self.fs.makedir("p/1/2/3",recursive=True)
self.fs.setcontents("p/1/2/3/a", '')
self.fs.setcontents("p/1/2/3/b", '')
self.fs.setcontents("p/1/2/3/foo", '')
self.fs.setcontents("p/1/2/3/bar", '')
self.fs.setcontents("p/1/2/3/a", b(''))
self.fs.setcontents("p/1/2/3/b", b(''))
self.fs.setcontents("p/1/2/3/foo", b(''))
self.fs.setcontents("p/1/2/3/bar", b(''))
self.fs.makedir("q")
# Test listing just files, just dirs, and wildcards
dirs_only = self.fs.listdir(dirs_only=True)
......@@ -236,10 +238,10 @@ class FSTestCases(object):
def check_equal(items,target):
names = [nm for (nm,info) in items]
self.assertEqual(sorted(names),sorted(target))
self.fs.setcontents(u"a", '')
self.fs.setcontents("b", '')
self.fs.setcontents("foo", '')
self.fs.setcontents("bar", '')
self.fs.setcontents(u"a", b(''))
self.fs.setcontents("b", b(''))
self.fs.setcontents("foo", b(''))
self.fs.setcontents("bar", b(''))
# Test listing of the root directory
d1 = self.fs.listdirinfo()
self.assertEqual(len(d1), 4)
......@@ -261,10 +263,10 @@ class FSTestCases(object):
# Create some deeper subdirectories, to make sure their
# contents are not inadvertantly included
self.fs.makedir("p/1/2/3",recursive=True)
self.fs.setcontents("p/1/2/3/a", '')
self.fs.setcontents("p/1/2/3/b", '')
self.fs.setcontents("p/1/2/3/foo", '')
self.fs.setcontents("p/1/2/3/bar", '')
self.fs.setcontents("p/1/2/3/a", b(''))
self.fs.setcontents("p/1/2/3/b", b(''))
self.fs.setcontents("p/1/2/3/foo", b(''))
self.fs.setcontents("p/1/2/3/bar", b(''))
self.fs.makedir("q")
# Test listing just files, just dirs, and wildcards
dirs_only = self.fs.listdirinfo(dirs_only=True)
......@@ -297,7 +299,7 @@ class FSTestCases(object):
def test_walk(self):
self.fs.setcontents('a.txt', 'hello')
self.fs.setcontents('b.txt', 'world')
self.fs.makeopendir('foo').setcontents('c', '123')
self.fs.makeopendir('foo').setcontents('c', b('123'))
sorted_walk = sorted([(d,sorted(fs)) for (d,fs) in self.fs.walk()])
self.assertEquals(sorted_walk,
[("/",["a.txt","b.txt"]),
......@@ -320,10 +322,10 @@ class FSTestCases(object):
assert found_c, "depth search order was wrong: " + str(list(self.fs.walk(search="depth")))
def test_walk_wildcard(self):
self.fs.setcontents('a.txt', 'hello')
self.fs.setcontents('b.txt', 'world')
self.fs.makeopendir('foo').setcontents('c', '123')
self.fs.makeopendir('.svn').setcontents('ignored', '')
self.fs.setcontents('a.txt', b('hello'))
self.fs.setcontents('b.txt', b('world'))
self.fs.makeopendir('foo').setcontents('c', b('123'))
self.fs.makeopendir('.svn').setcontents('ignored', b(''))
for dir_path, paths in self.fs.walk(wildcard='*.txt'):
for path in paths:
self.assert_(path.endswith('.txt'))
......@@ -332,24 +334,24 @@ class FSTestCases(object):
self.assert_(path.endswith('.txt'))
def test_walk_dir_wildcard(self):
self.fs.setcontents('a.txt', 'hello')
self.fs.setcontents('b.txt', 'world')
self.fs.makeopendir('foo').setcontents('c', '123')
self.fs.makeopendir('.svn').setcontents('ignored', '')
self.fs.setcontents('a.txt', b('hello'))
self.fs.setcontents('b.txt', b('world'))
self.fs.makeopendir('foo').setcontents('c', b('123'))
self.fs.makeopendir('.svn').setcontents('ignored', b(''))
for dir_path, paths in self.fs.walk(dir_wildcard=lambda fn:not fn.endswith('.svn')):
for path in paths:
self.assert_('.svn' not in path)
def test_walkfiles(self):
self.fs.makeopendir('bar').setcontents('a.txt', '123')
self.fs.makeopendir('foo').setcontents('b', '123')
self.fs.makeopendir('bar').setcontents('a.txt', b('123'))
self.fs.makeopendir('foo').setcontents('b', b('123'))
self.assertEquals(sorted(self.fs.walkfiles()),["/bar/a.txt","/foo/b"])
self.assertEquals(sorted(self.fs.walkfiles(dir_wildcard="*foo*")),["/foo/b"])
self.assertEquals(sorted(self.fs.walkfiles(wildcard="*.txt")),["/bar/a.txt"])
def test_walkdirs(self):
self.fs.makeopendir('bar').setcontents('a.txt', '123')
self.fs.makeopendir('foo').makeopendir("baz").setcontents('b', '123')
self.fs.makeopendir('bar').setcontents('a.txt', b('123'))
self.fs.makeopendir('foo').makeopendir("baz").setcontents('b', b('123'))
self.assertEquals(sorted(self.fs.walkdirs()),["/","/bar","/foo","/foo/baz"])
self.assertEquals(sorted(self.fs.walkdirs(wildcard="*foo*")),["/","/foo","/foo/baz"])
......@@ -357,8 +359,8 @@ class FSTestCases(object):
alpha = u"\N{GREEK SMALL LETTER ALPHA}"
beta = u"\N{GREEK SMALL LETTER BETA}"
self.fs.makedir(alpha)
self.fs.setcontents(alpha+"/a", '')
self.fs.setcontents(alpha+"/"+beta, '')
self.fs.setcontents(alpha+"/a", b(''))
self.fs.setcontents(alpha+"/"+beta, b(''))
self.assertTrue(self.check(alpha))
self.assertEquals(sorted(self.fs.listdir(alpha)),["a",beta])
......@@ -375,18 +377,18 @@ class FSTestCases(object):
self.assert_(check("a/b/child"))
self.assertRaises(DestinationExistsError,self.fs.makedir,"/a/b")
self.fs.makedir("/a/b",allow_recreate=True)
self.fs.setcontents("/a/file", '')
self.fs.setcontents("/a/file", b(''))
self.assertRaises(ResourceInvalidError,self.fs.makedir,"a/file")
def test_remove(self):
self.fs.setcontents("a.txt", '')
self.fs.setcontents("a.txt", b(''))
self.assertTrue(self.check("a.txt"))
self.fs.remove("a.txt")
self.assertFalse(self.check("a.txt"))
self.assertRaises(ResourceNotFoundError,self.fs.remove,"a.txt")
self.fs.makedir("dir1")
self.assertRaises(ResourceInvalidError,self.fs.remove,"dir1")
self.fs.setcontents("/dir1/a.txt", '')
self.fs.setcontents("/dir1/a.txt", b(''))
self.assertTrue(self.check("dir1/a.txt"))
self.fs.remove("dir1/a.txt")
self.assertFalse(self.check("/dir1/a.txt"))
......@@ -413,13 +415,13 @@ class FSTestCases(object):
self.assert_(not check("foo/bar"))
self.assert_(not check("foo"))
self.fs.makedir("foo/bar/baz", recursive=True)
self.fs.setcontents("foo/file.txt", "please don't delete me")
self.fs.setcontents("foo/file.txt", b("please don't delete me"))
self.fs.removedir("foo/bar/baz", recursive=True)
self.assert_(not check("foo/bar/baz"))
self.assert_(not check("foo/bar"))
# Ensure that force=True works as expected
self.fs.makedir("frollic/waggle", recursive=True)
self.fs.setcontents("frollic/waddle.txt","waddlewaddlewaddle")
self.fs.setcontents("frollic/waddle.txt",b("waddlewaddlewaddle"))
self.assertRaises(DirectoryNotEmptyError,self.fs.removedir,"frollic")
self.assertRaises(ResourceInvalidError,self.fs.removedir,"frollic/waddle.txt")
self.fs.removedir("frollic",force=True)
......@@ -439,14 +441,14 @@ class FSTestCases(object):
def test_rename(self):
check = self.check
# test renaming a file in the same directory
self.fs.setcontents("foo.txt","Hello, World!")
self.fs.setcontents("foo.txt",b("Hello, World!"))
self.assert_(check("foo.txt"))
self.fs.rename("foo.txt", "bar.txt")
self.assert_(check("bar.txt"))
self.assert_(not check("foo.txt"))
# test renaming a directory in the same directory
self.fs.makedir("dir_a")
self.fs.setcontents("dir_a/test.txt","testerific")
self.fs.setcontents("dir_a/test.txt",b("testerific"))
self.assert_(check("dir_a"))
self.fs.rename("dir_a","dir_b")
self.assert_(check("dir_b"))
......@@ -462,7 +464,7 @@ class FSTestCases(object):
self.assertRaises(ParentDirectoryMissingError,self.fs.rename,"dir_a/test.txt","nonexistent/test.txt")
def test_info(self):
test_str = "Hello, World!"
test_str = b("Hello, World!")
self.fs.setcontents("info.txt",test_str)
info = self.fs.getinfo("info.txt")
self.assertEqual(info['size'], len(test_str))
......@@ -471,18 +473,18 @@ class FSTestCases(object):
self.assertRaises(ResourceNotFoundError,self.fs.getinfo,"info.txt/inval")
def test_getsize(self):
test_str = "*"*23
test_str = b("*")*23
self.fs.setcontents("info.txt",test_str)
size = self.fs.getsize("info.txt")
self.assertEqual(size, len(test_str))
def test_movefile(self):
check = self.check
contents = "If the implementation is hard to explain, it's a bad idea."
contents = b("If the implementation is hard to explain, it's a bad idea.")
def makefile(path):
self.fs.setcontents(path,contents)
def checkcontents(path):
check_contents = self.fs.getcontents(path)
check_contents = self.fs.getcontents(path, "rb")
self.assertEqual(check_contents,contents)
return contents == check_contents
......@@ -511,7 +513,7 @@ class FSTestCases(object):
def test_movedir(self):
check = self.check
contents = "If the implementation is hard to explain, it's a bad idea."
contents = b("If the implementation is hard to explain, it's a bad idea.")
def makefile(path):
self.fs.setcontents(path, contents)
......@@ -556,11 +558,11 @@ class FSTestCases(object):
def test_copyfile(self):
check = self.check
contents = "If the implementation is hard to explain, it's a bad idea."
contents = b("If the implementation is hard to explain, it's a bad idea.")
def makefile(path,contents=contents):
self.fs.setcontents(path,contents)
def checkcontents(path,contents=contents):
check_contents = self.fs.getcontents(path)
check_contents = self.fs.getcontents(path, "rb")
self.assertEqual(check_contents,contents)
return contents == check_contents
......@@ -580,18 +582,18 @@ class FSTestCases(object):
self.assert_(check("/c.txt"))
self.assert_(checkcontents("/c.txt"))
makefile("foo/bar/a.txt","different contents")
self.assert_(checkcontents("foo/bar/a.txt","different contents"))
makefile("foo/bar/a.txt",b("different contents"))
self.assert_(checkcontents("foo/bar/a.txt",b("different contents")))
self.assertRaises(DestinationExistsError,self.fs.copy,"foo/bar/a.txt","/c.txt")
self.assert_(checkcontents("/c.txt"))
self.fs.copy("foo/bar/a.txt","/c.txt",overwrite=True)
self.assert_(checkcontents("foo/bar/a.txt","different contents"))
self.assert_(checkcontents("/c.txt","different contents"))
self.assert_(checkcontents("foo/bar/a.txt",b("different contents")))
self.assert_(checkcontents("/c.txt",b("different contents")))
def test_copydir(self):
check = self.check
contents = "If the implementation is hard to explain, it's a bad idea."
contents = b("If the implementation is hard to explain, it's a bad idea.")
def makefile(path):
self.fs.setcontents(path,contents)
def checkcontents(path):
......@@ -630,7 +632,7 @@ class FSTestCases(object):
def test_copydir_with_dotfile(self):
check = self.check
contents = "If the implementation is hard to explain, it's a bad idea."
contents = b("If the implementation is hard to explain, it's a bad idea.")
def makefile(path):
self.fs.setcontents(path,contents)
......@@ -650,13 +652,13 @@ class FSTestCases(object):
def test_readwriteappendseek(self):
def checkcontents(path, check_contents):
read_contents = self.fs.getcontents(path)
read_contents = self.fs.getcontents(path, "rb")
self.assertEqual(read_contents,check_contents)
return read_contents == check_contents
test_strings = ["Beautiful is better than ugly.",
"Explicit is better than implicit.",
"Simple is better than complex."]
all_strings = "".join(test_strings)
test_strings = [b("Beautiful is better than ugly."),
b("Explicit is better than implicit."),
b("Simple is better than complex.")]
all_strings = b("").join(test_strings)
self.assertRaises(ResourceNotFoundError, self.fs.open, "a.txt", "r")
self.assert_(not self.fs.exists("a.txt"))
......@@ -689,67 +691,67 @@ class FSTestCases(object):
self.assert_(checkcontents("b.txt", test_strings[2]))
f5 = self.fs.open("c.txt", "wb")
for s in test_strings:
f5.write(s+"\n")
f5.write(s+b("\n"))
f5.close()
f6 = self.fs.open("c.txt", "rb")
for s, t in zip(f6, test_strings):
self.assertEqual(s, t+"\n")
self.assertEqual(s, t+b("\n"))
f6.close()
f7 = self.fs.open("c.txt", "rb")
f7.seek(13)
word = f7.read(6)
self.assertEqual(word, "better")
self.assertEqual(word, b("better"))
f7.seek(1, os.SEEK_CUR)
word = f7.read(4)
self.assertEqual(word, "than")
self.assertEqual(word, b("than"))
f7.seek(-9, os.SEEK_END)
word = f7.read(7)
self.assertEqual(word, "complex")
self.assertEqual(word, b("complex"))
f7.close()
self.assertEqual(self.fs.getcontents("a.txt"), all_strings)
self.assertEqual(self.fs.getcontents("a.txt", "rb"), all_strings)
def test_truncate(self):
def checkcontents(path, check_contents):
read_contents = self.fs.getcontents(path)
read_contents = self.fs.getcontents(path, "rb")
self.assertEqual(read_contents,check_contents)
return read_contents == check_contents
self.fs.setcontents("hello","world")
checkcontents("hello","world")
self.fs.setcontents("hello","hi")
checkcontents("hello","hi")
self.fs.setcontents("hello","1234567890")
checkcontents("hello","1234567890")
self.fs.setcontents("hello",b("world"))
checkcontents("hello",b("world"))
self.fs.setcontents("hello",b("hi"))
checkcontents("hello",b("hi"))
self.fs.setcontents("hello",b("1234567890"))
checkcontents("hello",b("1234567890"))
with self.fs.open("hello","r+") as f:
f.truncate(7)
checkcontents("hello","1234567")
checkcontents("hello",b("1234567"))
with self.fs.open("hello","r+") as f:
f.seek(5)
f.truncate()
checkcontents("hello","12345")
checkcontents("hello",b("12345"))
def test_truncate_to_larger_size(self):
with self.fs.open("hello","w") as f:
with self.fs.open("hello","wb") as f:
f.truncate(30)
self.assertEquals(self.fs.getsize("hello"), 30)
# Some file systems (FTPFS) don't support both reading and writing
if self.fs.getmeta('file.read_and_write', True):
with self.fs.open("hello","r+") as f:
with self.fs.open("hello","rb+") as f:
f.seek(25)
f.write("123456")
f.write(b("123456"))
with self.fs.open("hello","r") as f:
with self.fs.open("hello","rb") as f:
f.seek(25)
self.assertEquals(f.read(),"123456")
self.assertEquals(f.read(),b("123456"))
def test_write_past_end_of_file(self):
if self.fs.getmeta('file.read_and_write', True):
with self.fs.open("write_at_end","w") as f:
with self.fs.open("write_at_end","wb") as f:
f.seek(25)
f.write("EOF")
with self.fs.open("write_at_end","r") as f:
self.assertEquals(f.read(),"\x00"*25 + "EOF")
f.write(b("EOF"))
with self.fs.open("write_at_end","rb") as f:
self.assertEquals(f.read(),b("\x00")*25 + b("EOF"))
def test_with_statement(self):
......@@ -760,24 +762,24 @@ class FSTestCases(object):
# A successful 'with' statement
contents = "testing the with statement"
code = "from __future__ import with_statement\n"
code += "with self.fs.open('f.txt','w-') as testfile:\n"
code += "with self.fs.open('f.txt','wb-') as testfile:\n"
code += " testfile.write(contents)\n"
code += "self.assertEquals(self.fs.getcontents('f.txt'),contents)"
code += "self.assertEquals(self.fs.getcontents('f.txt', 'rb'),contents)"
code = compile(code,"<string>",'exec')
eval(code)
# A 'with' statement raising an error
contents = "testing the with statement"
code = "from __future__ import with_statement\n"
code += "with self.fs.open('f.txt','w-') as testfile:\n"
code += "with self.fs.open('f.txt','wb-') as testfile:\n"
code += " testfile.write(contents)\n"
code += " raise ValueError\n"
code = compile(code,"<string>",'exec')
self.assertRaises(ValueError,eval,code,globals(),locals())
self.assertEquals(self.fs.getcontents('f.txt'),contents)
self.assertEquals(self.fs.getcontents('f.txt', 'rb'),contents)
def test_pickling(self):
if self.fs.getmeta('pickle_contents', True):
self.fs.setcontents("test1","hello world")
self.fs.setcontents("test1",b("hello world"))
fs2 = pickle.loads(pickle.dumps(self.fs))
self.assert_(fs2.isfile("test1"))
fs3 = pickle.loads(pickle.dumps(self.fs,-1))
......@@ -789,14 +791,15 @@ class FSTestCases(object):
def test_big_file(self):
"""Test handling of a big file (1MB)"""
chunk_size = 1024 * 256
num_chunks = 4
def chunk_stream():
chunk_size = 1024 * 256
num_chunks = 4
def chunk_stream():
"""Generate predictable-but-randomy binary content."""
r = random.Random(0)
randint = r.randint
for i in xrange(num_chunks):
c = "".join(chr(randint(0,255)) for j in xrange(chunk_size/8))
int2byte = six.int2byte
for _i in xrange(num_chunks):
c = b("").join(int2byte(randint(0,255)) for _j in xrange(chunk_size//8))
yield c * 8
f = self.fs.open("bigfile","wb")
try:
......@@ -812,7 +815,7 @@ class FSTestCases(object):
if chunks.next() != f.read(chunk_size):
assert False, "bigfile was corrupted"
except StopIteration:
if f.read() != "":
if f.read() != b(""):
assert False, "bigfile was corrupted"
finally:
f.close()
......@@ -825,7 +828,7 @@ class FSTestCases(object):
return int(dts1) == int(dts2)
d1 = datetime.datetime(2010, 6, 20, 11, 0, 9, 987699)
d2 = datetime.datetime(2010, 7, 5, 11, 0, 9, 500000)
self.fs.setcontents('/dates.txt', 'check dates')
self.fs.setcontents('/dates.txt', b('check dates'))
# If the implementation supports settimes, check that the times
# can be set and then retrieved
try:
......@@ -838,9 +841,12 @@ class FSTestCases(object):
self.assertTrue(cmp_datetimes(d2, info['modified_time']))
# Disabled - see below
class ThreadingTestCases(object):
"""Testcases for thread-safety of FS implementations."""
# These are either too slow to be worth repeating,
# or cannot possibly break cross-thread.
_dont_retest = ("test_pickling","test_multiple_overwrite",)
......@@ -885,7 +891,7 @@ class ThreadingTestCases(object):
def test_setcontents_threaded(self):
def setcontents(name,contents):
f = self.fs.open(name,"w")
f = self.fs.open(name,"wb")
self._yield()
try:
f.write(contents)
......@@ -893,13 +899,13 @@ class ThreadingTestCases(object):
finally:
f.close()
def thread1():
c = "thread1 was 'ere"
c = b("thread1 was 'ere")
setcontents("thread1.txt",c)
self.assertEquals(self.fs.getcontents("thread1.txt"),c)
self.assertEquals(self.fs.getcontents("thread1.txt", 'rb'),c)
def thread2():
c = "thread2 was 'ere"
c = b("thread2 was 'ere")
setcontents("thread2.txt",c)
self.assertEquals(self.fs.getcontents("thread2.txt"),c)
self.assertEquals(self.fs.getcontents("thread2.txt", 'rb'),c)
self._runThreads(thread1,thread2)
def test_setcontents_threaded_samefile(self):
......@@ -912,17 +918,17 @@ class ThreadingTestCases(object):
finally:
f.close()
def thread1():
c = "thread1 was 'ere"
c = b("thread1 was 'ere")
setcontents("threads.txt",c)
self._yield()
self.assertEquals(self.fs.listdir("/"),["threads.txt"])
def thread2():
c = "thread2 was 'ere"
c = b("thread2 was 'ere")
setcontents("threads.txt",c)
self._yield()
self.assertEquals(self.fs.listdir("/"),["threads.txt"])
def thread3():
c = "thread3 was 'ere"
c = b("thread3 was 'ere")
setcontents("threads.txt",c)
self._yield()
self.assertEquals(self.fs.listdir("/"),["threads.txt"])
......@@ -1011,9 +1017,9 @@ class ThreadingTestCases(object):
def test_concurrent_copydir(self):
self.fs.makedir("a")
self.fs.makedir("a/b")
self.fs.setcontents("a/hello.txt","hello world")
self.fs.setcontents("a/guido.txt","is a space alien")
self.fs.setcontents("a/b/parrot.txt","pining for the fiords")
self.fs.setcontents("a/hello.txt",b("hello world"))
self.fs.setcontents("a/guido.txt",b("is a space alien"))
self.fs.setcontents("a/b/parrot.txt",b("pining for the fiords"))
def copydir():
self._yield()
self.fs.copydir("a","copy of a")
......@@ -1030,22 +1036,26 @@ class ThreadingTestCases(object):
pass
self.assertTrue(self.fs.isdir("copy of a"))
self.assertTrue(self.fs.isdir("copy of a/b"))
self.assertEqual(self.fs.getcontents("copy of a/b/parrot.txt"),"pining for the fiords")
self.assertEqual(self.fs.getcontents("copy of a/hello.txt"),"hello world")
self.assertEqual(self.fs.getcontents("copy of a/guido.txt"),"is a space alien")
self.assertEqual(self.fs.getcontents("copy of a/b/parrot.txt", 'rb'),b("pining for the fiords"))
self.assertEqual(self.fs.getcontents("copy of a/hello.txt", 'rb'),b("hello world"))
self.assertEqual(self.fs.getcontents("copy of a/guido.txt", 'rb'),b("is a space alien"))
def test_multiple_overwrite(self):
contents = ["contents one","contents the second","number three"]
contents = [b("contents one"),b("contents the second"),b("number three")]
def thread1():
for i in xrange(30):
for c in contents:
self.fs.setcontents("thread1.txt",c)
self.assertEquals(self.fs.getsize("thread1.txt"),len(c))
self.assertEquals(self.fs.getcontents("thread1.txt"),c)
self.assertEquals(self.fs.getcontents("thread1.txt", 'rb'),c)
def thread2():
for i in xrange(30):
for c in contents:
self.fs.setcontents("thread2.txt",c)
self.assertEquals(self.fs.getsize("thread2.txt"),len(c))
self.assertEquals(self.fs.getcontents("thread2.txt"),c)
self.assertEquals(self.fs.getcontents("thread2.txt", 'rb'),c)
self._runThreads(thread1,thread2)
class ThreadingTestCases(object):
_dont_retest = ()
......@@ -20,6 +20,10 @@ from fs.errors import *
from fs import rpcfs
from fs.expose.xmlrpc import RPCFSServer
import six
from six import PY3, b
class TestRPCFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
def makeServer(self,fs,addr):
......@@ -106,7 +110,7 @@ class TestRPCFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
sock = socket.socket(af, socktype, proto)
sock.settimeout(.1)
sock.connect(sa)
sock.send("\n")
sock.send(b("\n"))
except socket.error, e:
pass
finally:
......@@ -114,10 +118,16 @@ class TestRPCFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
sock.close()
from fs import sftpfs
from fs.expose.sftp import BaseSFTPServer
try:
from fs import sftpfs
from fs.expose.sftp import BaseSFTPServer
except ImportError:
if not PY3:
raise
class TestSFTPFS(TestRPCFS):
__test__ = not PY3
def makeServer(self,fs,addr):
return BaseSFTPServer(addr,fs)
......@@ -209,7 +219,7 @@ if dokan.is_available:
def test_safety_wrapper(self):
rawfs = MemoryFS()
safefs = dokan.Win32SafetyFS(rawfs)
rawfs.setcontents("autoRun.inf","evilcodeevilcode")
rawfs.setcontents("autoRun.inf", b("evilcodeevilcode"))
self.assertTrue(safefs.exists("_autoRun.inf"))
self.assertTrue("autoRun.inf" not in safefs.listdir("/"))
safefs.setcontents("file:stream","test")
......
......@@ -12,9 +12,13 @@ import time
from os.path import abspath
import urllib
from six import PY3
try:
from pyftpdlib import ftpserver
except ImportError:
if not PY3:
raise ImportError("Requires pyftpdlib <http://code.google.com/p/pyftpdlib/>")
from fs.path import *
......@@ -24,6 +28,8 @@ from fs import ftpfs
ftp_port = 30000
class TestFTPFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
__test__ = not PY3
def setUp(self):
global ftp_port
ftp_port += 1
......
......@@ -22,6 +22,7 @@ from fs.tempfs import TempFS
from fs.path import *
from fs.local_functools import wraps
from six import PY3, b
class RemoteTempFS(TempFS):
"""
......@@ -79,7 +80,7 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
self.fs.close()
self.fakeOff()
def fake_setcontents(self, path, content='', chunk_size=16*1024):
def fake_setcontents(self, path, content=b(''), chunk_size=16*1024):
''' Fake replacement for RemoteTempFS setcontents() '''
raise self.FakeException("setcontents should not be called here!")
......@@ -99,8 +100,8 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
'''
Tests on-demand loading of remote content in RemoteFileBuffer
'''
contents = "Tristatricettri stribrnych strikacek strikalo" + \
"pres tristatricettri stribrnych strech."
contents = b("Tristatricettri stribrnych strikacek strikalo") + \
b("pres tristatricettri stribrnych strech.")
f = self.fs.open('test.txt', 'wb')
f.write(contents)
f.close()
......@@ -136,10 +137,10 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
# Rollback position 5 characters before eof
f._rfile.seek(len(contents[:-5]))
# Write 10 new characters (will make contents longer for 5 chars)
f.write(u'1234567890')
f.write(b('1234567890'))
f.flush()
# We are on the end of file (and buffer not serve anything anymore)
self.assertEquals(f.read(), '')
self.assertEquals(f.read(), b(''))
f.close()
self.fakeOn()
......@@ -147,7 +148,7 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
# Check if we wrote everything OK from
# previous writing over the remote buffer edge
f = self.fs.open('test.txt', 'rb')
self.assertEquals(f.read(), contents[:-5] + u'1234567890')
self.assertEquals(f.read(), contents[:-5] + b('1234567890'))
f.close()
self.fakeOff()
......@@ -161,19 +162,19 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
'''
self.fakeOn()
f = self.fs.open('test.txt', 'wb', write_on_flush=True)
f.write('Sample text')
f.write(b('Sample text'))
self.assertRaises(self.FakeException, f.flush)
f.write('Second sample text')
f.write(b('Second sample text'))
self.assertRaises(self.FakeException, f.close)
self.fakeOff()
f.close()
self.fakeOn()
f = self.fs.open('test.txt', 'wb', write_on_flush=False)
f.write('Sample text')
f.write(b('Sample text'))
# FakeException is not raised, because setcontents is not called
f.flush()
f.write('Second sample text')
f.write(b('Second sample text'))
self.assertRaises(self.FakeException, f.close)
self.fakeOff()
......@@ -183,8 +184,8 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
back to remote destination and opened file is still
in good condition.
'''
contents = "Zlutoucky kun upel dabelske ody."
contents2 = 'Ententyky dva spaliky cert vyletel z elektriky'
contents = b("Zlutoucky kun upel dabelske ody.")
contents2 = b('Ententyky dva spaliky cert vyletel z elektriky')
f = self.fs.open('test.txt', 'wb')
f.write(contents)
......@@ -195,17 +196,17 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCases, ThreadingTestCases):
self.assertEquals(f.read(10), contents[:10])
self.assertEquals(f._rfile.tell(), 10)
# Write garbage to file to mark it as _changed
f.write('x')
f.write(b('x'))
# This should read the rest of file and store file back to again.
f.flush()
f.seek(0)
# Try if we have unocrrupted file locally...
self.assertEquals(f.read(), contents[:10] + 'x' + contents[11:])
self.assertEquals(f.read(), contents[:10] + b('x') + contents[11:])
f.close()
# And if we have uncorrupted file also on storage
f = self.fs.open('test.txt', 'rb')
self.assertEquals(f.read(), contents[:10] + 'x' + contents[11:])
self.assertEquals(f.read(), contents[:10] + b('x') + contents[11:])
f.close()
# Now try it again, but write garbage behind edge of remote file
......@@ -243,7 +244,7 @@ class TestCacheFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
self.fs.cache_timeout = None
try:
self.assertFalse(self.fs.isfile("hello"))
self.wrapped_fs.setcontents("hello","world")
self.wrapped_fs.setcontents("hello",b("world"))
self.assertTrue(self.fs.isfile("hello"))
self.wrapped_fs.remove("hello")
self.assertTrue(self.fs.isfile("hello"))
......@@ -257,11 +258,11 @@ class TestCacheFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
self.fs.cache_timeout = None
try:
self.assertFalse(self.fs.isfile("hello"))
self.wrapped_fs.setcontents("hello","world")
self.wrapped_fs.setcontents("hello",b("world"))
self.assertTrue(self.fs.isfile("hello"))
self.wrapped_fs.remove("hello")
self.assertTrue(self.fs.isfile("hello"))
self.wrapped_fs.setcontents("hello","world")
self.wrapped_fs.setcontents("hello",b("world"))
self.assertTrue(self.fs.isfile("hello"))
self.fs.remove("hello")
self.assertFalse(self.fs.isfile("hello"))
......@@ -315,7 +316,7 @@ class DisconnectingFS(WrapFS):
time.sleep(random.random()*0.1)
self._connected = not self._connected
def setcontents(self, path, contents='', chunk_size=64*1024):
def setcontents(self, path, contents=b(''), chunk_size=64*1024):
return self.wrapped_fs.setcontents(path, contents)
def close(self):
......
......@@ -13,7 +13,13 @@ import unittest
from fs.tests import FSTestCases, ThreadingTestCases
from fs.path import *
from fs import s3fs
from six import PY3
try:
from fs import s3fs
except ImportError:
if not PY3:
raise
class TestS3FS(unittest.TestCase,FSTestCases,ThreadingTestCases):
# Disable the tests by default
......
......@@ -29,6 +29,8 @@ if sys.platform == "win32":
else:
watch_win32 = None
import six
from six import PY3, b
class WatcherTestCases:
"""Testcases for filesystems providing change watcher support.
......@@ -88,11 +90,11 @@ class WatcherTestCases:
def test_watch_readfile(self):
self.setupWatchers()
self.fs.setcontents("hello","hello world")
self.fs.setcontents("hello", b("hello world"))
self.assertEventOccurred(CREATED,"/hello")
self.clearCapturedEvents()
old_atime = self.fs.getinfo("hello").get("accessed_time")
self.assertEquals(self.fs.getcontents("hello"),"hello world")
self.assertEquals(self.fs.getcontents("hello"), b("hello world"))
if not isinstance(self.watchfs,PollingWatchableFS):
# Help it along by updting the atime.
# TODO: why is this necessary?
......@@ -121,17 +123,17 @@ class WatcherTestCases:
def test_watch_writefile(self):
self.setupWatchers()
self.fs.setcontents("hello","hello world")
self.fs.setcontents("hello", b("hello world"))
self.assertEventOccurred(CREATED,"/hello")
self.clearCapturedEvents()
self.fs.setcontents("hello","hello again world")
self.fs.setcontents("hello", b("hello again world"))
self.assertEventOccurred(MODIFIED,"/hello")
def test_watch_single_file(self):
self.fs.setcontents("hello","hello world")
self.fs.setcontents("hello", b("hello world"))
events = []
self.watchfs.add_watcher(events.append,"/hello",(MODIFIED,))
self.fs.setcontents("hello","hello again world")
self.fs.setcontents("hello", b("hello again world"))
self.fs.remove("hello")
self.waitForEvents()
for evt in events:
......@@ -140,10 +142,10 @@ class WatcherTestCases:
def test_watch_single_file_remove(self):
self.fs.makedir("testing")
self.fs.setcontents("testing/hello","hello world")
self.fs.setcontents("testing/hello", b("hello world"))
events = []
self.watchfs.add_watcher(events.append,"/testing/hello",(REMOVED,))
self.fs.setcontents("testing/hello","hello again world")
self.fs.setcontents("testing/hello", b("hello again world"))
self.waitForEvents()
self.fs.remove("testing/hello")
self.waitForEvents()
......@@ -154,7 +156,7 @@ class WatcherTestCases:
def test_watch_iter_changes(self):
changes = iter_changes(self.watchfs)
self.fs.makedir("test1")
self.fs.setcontents("test1/hello","hello world")
self.fs.setcontents("test1/hello", b("hello world"))
self.waitForEvents()
self.fs.removedir("test1",force=True)
self.waitForEvents()
......
......@@ -15,11 +15,15 @@ import tempfile
from fs import osfs
from fs.errors import *
from fs.path import *
from fs import wrapfs
import six
from six import PY3, b
from fs import wrapfs
class TestWrapFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
__test__ = False
def setUp(self):
self.temp_dir = tempfile.mkdtemp(u"fstest")
self.fs = wrapfs.WrapFS(osfs.OSFS(self.temp_dir))
......@@ -67,7 +71,7 @@ class TestLimitSizeFS(TestWrapFS):
for i in xrange(1024*2):
try:
total_written += 1030
self.fs.setcontents("file"+str(i),"C"*1030)
self.fs.setcontents("file %i" % i, b("C")*1030)
except StorageSpaceError:
self.assertTrue(total_written > 1024*1024*2)
self.assertTrue(total_written < 1024*1024*2 + 1030)
......
......@@ -120,8 +120,8 @@ class WrapFS(FS):
def __unicode__(self):
return u"<%s: %s>" % (self.__class__.__name__,self.wrapped_fs,)
def __str__(self):
return unicode(self).encode(sys.getdefaultencoding(),"replace")
#def __str__(self):
# return unicode(self).encode(sys.getdefaultencoding(),"replace")
@rewrite_errors
......@@ -155,10 +155,11 @@ class WrapFS(FS):
# We can't pass setcontents() through to the wrapped FS if the
# wrapper has defined a _file_wrap method, as it would bypass
# the file contents wrapping.
if self._file_wrap.im_func is WrapFS._file_wrap.im_func:
#if self._file_wrap.im_func is WrapFS._file_wrap.im_func:
if getattr(self.__class__, '_file_wrap', None) is getattr(WrapFS, '_file_wrap', None):
return self.wrapped_fs.setcontents(self._encode(path), data, chunk_size=chunk_size)
else:
return super(WrapFS,self).setcontents(path, data, chunk_size)
return super(WrapFS,self).setcontents(path, data, chunk_size=chunk_size)
@rewrite_errors
def createfile(self, path):
......
......@@ -95,7 +95,7 @@ class LimitSizeFS(WrapFS):
def setcontents(self, path, data, chunk_size=64*1024):
f = None
try:
f = self.open(path, 'w')
f = self.open(path, 'wb')
if hasattr(data, 'read'):
chunk = data.read(chunk_size)
while chunk:
......
......@@ -37,7 +37,7 @@ class SubFS(WrapFS):
return u'<SubFS: %s/%s>' % (self.wrapped_fs, self.sub_dir.lstrip('/'))
def __repr__(self):
return str(self)
return "SubFS(%r, %r)" % (self.wrapped_fs, self.sub_dir)
def desc(self, path):
if path in ('', '/'):
......
......@@ -142,7 +142,7 @@ class ZipFS(FS):
return "<ZipFS: %s>" % self.zip_path
def __unicode__(self):
return unicode(self.__str__())
return u"<ZipFS: %s>" % self.zip_path
def _parse_resource_list(self):
for path in self.zf.namelist():
......@@ -209,7 +209,7 @@ class ZipFS(FS):
raise ValueError("Mode must contain be 'r' or 'w'")
@synchronize
def getcontents(self, path):
def getcontents(self, path, mode="rb"):
if not self.exists(path):
raise ResourceNotFoundError(path)
path = normpath(relpath(path))
......
#!/usr/bin/env python
from distutils.core import setup
from fs import __version__ as VERSION
#from distribute_setup import use_setuptools
#use_setuptools()
from setuptools import setup
import sys
PY3 = sys.version_info >= (3,)
VERSION = "0.4.1"
COMMANDS = ['fscat',
'fscp',
......@@ -17,7 +23,7 @@ COMMANDS = ['fscat',
classifiers = [
'Development Status :: 3 - Alpha',
"Development Status :: 5 - Production/Stable",
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
......@@ -30,7 +36,12 @@ long_desc = """Pyfilesystem is a module that provides a simplified common interf
Even if you only need to work with file and directories on the local hard-drive, Pyfilesystem can simplify your code and make it more robust -- with the added advantage that you can change where the files are located by changing a single line of code.
"""
setup(name='fs',
extra = {}
if PY3:
extra["use_2to3"] = True
setup(install_requires=['distribute'],
name='fs',
version=VERSION,
description="Filesystem abstraction",
long_description=long_desc,
......@@ -55,5 +66,6 @@ setup(name='fs',
'fs.commands'],
scripts=['fs/commands/%s' % command for command in COMMANDS],
classifiers=classifiers,
**extra
)
[tox]
envlist = py25,py26,py27
envlist = py25,py26,py27,py32
[testenv]
deps = dexml
deps = distribute
six
dexml
paramiko
boto
nose
mako
pyftpdlib
commands = nosetests -v \
changedir=.tox
commands = nosetests fs.tests -v \
[]
[testenv:py25]
deps = dexml
deps = distribute
six
dexml
paramiko
boto
nose
mako
pyftpdlib
simplejson
[testenv:py32]
commands = nosetests fs.tests -v \
[]
deps = distribute
six
dexml
nose
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