Commit ea0d2e43 by willmcgugan

Python3 changes

parent 3b900b1c
...@@ -81,3 +81,5 @@ ...@@ -81,3 +81,5 @@
* Added `appdirfs` module to abstract per-user application directories * Added `appdirfs` module to abstract per-user application directories
0.5: 0.5:
* Ported to Python 3.X
...@@ -67,12 +67,14 @@ from fs.path import * ...@@ -67,12 +67,14 @@ from fs.path import *
from fs.local_functools import wraps from fs.local_functools import wraps
from six import PY3 from six import PY3
from six import b
try: try:
if PY3: #if PY3:
import fuse3 as fuse # import fuse3 as fuse
else: #else:
import fuse # import fuse
import fuse_ctypes as fuse
except NotImplementedError: except NotImplementedError:
raise ImportError("FUSE found but not usable") raise ImportError("FUSE found but not usable")
try: try:
...@@ -530,8 +532,12 @@ class MountProcess(subprocess.Popen): ...@@ -530,8 +532,12 @@ class MountProcess(subprocess.Popen):
def __init__(self, fs, path, fuse_opts={}, nowait=False, **kwds): def __init__(self, fs, path, fuse_opts={}, nowait=False, **kwds):
self.path = path self.path = path
if nowait or kwds.get("close_fds",False): if nowait or kwds.get("close_fds",False):
cmd = 'import cPickle; ' if PY3:
cmd = cmd + 'data = cPickle.loads(%s); ' cmd = "from pickle import loads;"
else:
cmd = "from cPickle import loads;"
#cmd = 'import cPickle; '
cmd = cmd + 'data = loads(%s); '
cmd = cmd + 'from fs.expose.fuse import MountProcess; ' cmd = cmd + 'from fs.expose.fuse import MountProcess; '
cmd = cmd + 'MountProcess._do_mount_nowait(data)' cmd = cmd + 'MountProcess._do_mount_nowait(data)'
cmd = cmd % (repr(cPickle.dumps((fs,path,fuse_opts),-1)),) cmd = cmd % (repr(cPickle.dumps((fs,path,fuse_opts),-1)),)
...@@ -539,15 +545,21 @@ class MountProcess(subprocess.Popen): ...@@ -539,15 +545,21 @@ class MountProcess(subprocess.Popen):
super(MountProcess,self).__init__(cmd,**kwds) super(MountProcess,self).__init__(cmd,**kwds)
else: else:
(r,w) = os.pipe() (r,w) = os.pipe()
cmd = 'import cPickle; ' if PY3:
cmd = cmd + 'data = cPickle.loads(%s); ' cmd = "from pickle import loads;"
else:
cmd = "from cPickle import loads;"
#cmd = 'import cPickle; '
cmd = cmd + 'data = loads(%s); '
cmd = cmd + 'from fs.expose.fuse import MountProcess; ' cmd = cmd + 'from fs.expose.fuse import MountProcess; '
cmd = cmd + 'MountProcess._do_mount_wait(data)' cmd = cmd + 'MountProcess._do_mount_wait(data)'
cmd = cmd % (repr(cPickle.dumps((fs,path,fuse_opts,r,w),-1)),) cmd = cmd % (repr(cPickle.dumps((fs,path,fuse_opts,r,w),-1)),)
cmd = [sys.executable,"-c",cmd] cmd = [sys.executable,"-c",cmd]
super(MountProcess,self).__init__(cmd,**kwds) super(MountProcess,self).__init__(cmd,**kwds)
os.close(w) os.close(w)
if os.read(r,1) != "S":
byte = os.read(r, 1)
if byte != b("S"):
self.terminate() self.terminate()
raise RuntimeError("FUSE error: " + os.read(r,20).decode(NATIVE_ENCODING)) raise RuntimeError("FUSE error: " + os.read(r,20).decode(NATIVE_ENCODING))
...@@ -595,7 +607,7 @@ class MountProcess(subprocess.Popen): ...@@ -595,7 +607,7 @@ class MountProcess(subprocess.Popen):
successful = [] successful = []
def ready_callback(): def ready_callback():
successful.append(True) successful.append(True)
os.write(w,"S") os.write(w, b("S"))
os.close(w) os.close(w)
opts["ready_callback"] = ready_callback opts["ready_callback"] = ready_callback
def unmount_callback(): def unmount_callback():
...@@ -603,12 +615,12 @@ class MountProcess(subprocess.Popen): ...@@ -603,12 +615,12 @@ class MountProcess(subprocess.Popen):
opts["unmount_callback"] = unmount_callback opts["unmount_callback"] = unmount_callback
try: try:
mount(fs,path,**opts) mount(fs,path,**opts)
except Exception, e: except Exception, e:
os.write(w,"E"+str(e)) os.write(w,b("E")+b(e))
os.close(w) os.close(w)
else: else:
if not successful: if not successful:
os.write(w,"E") os.write(w,b("E"))
os.close(w) os.close(w)
......
...@@ -49,7 +49,7 @@ import six ...@@ -49,7 +49,7 @@ import six
from six import PY3, b from six import PY3, b
if PY3: if PY3:
_StringIO = six.BytesIO from six import BytesIO as _StringIO
else: else:
try: try:
from cStringIO import StringIO as _StringIO from cStringIO import StringIO as _StringIO
...@@ -669,7 +669,7 @@ class FileWrapper(FileLikeBase): ...@@ -669,7 +669,7 @@ class FileWrapper(FileLikeBase):
return self.wrapped_file.tell() return self.wrapped_file.tell()
def _truncate(self,size): def _truncate(self,size):
return self.wrapped_file.truncate(size) return self.wrapped_file.truncate(size)
class StringIO(FileWrapper): class StringIO(FileWrapper):
...@@ -721,8 +721,8 @@ class SpooledTemporaryFile(FileWrapper): ...@@ -721,8 +721,8 @@ class SpooledTemporaryFile(FileWrapper):
try: try:
stf_args = (max_size,mode,bufsize) + args stf_args = (max_size,mode,bufsize) + args
wrapped_file = _tempfile.SpooledTemporaryFile(*stf_args,**kwds) wrapped_file = _tempfile.SpooledTemporaryFile(*stf_args,**kwds)
#wrapped_file._file = StringIO() wrapped_file._file = StringIO()
wrapped_file._file = six.BytesIO() #wrapped_file._file = six.BytesIO()
self.__is_spooled = True self.__is_spooled = True
except AttributeError: except AttributeError:
ntf_args = (mode,bufsize) + args ntf_args = (mode,bufsize) + args
......
...@@ -30,7 +30,7 @@ from socket import error as socket_error ...@@ -30,7 +30,7 @@ from socket import error as socket_error
from fs.local_functools import wraps from fs.local_functools import wraps
import six import six
from six import PY3 from six import PY3, b
if PY3: if PY3:
from six import BytesIO as StringIO from six import BytesIO as StringIO
...@@ -654,7 +654,7 @@ class _FTPFile(object): ...@@ -654,7 +654,7 @@ class _FTPFile(object):
@fileftperrors @fileftperrors
def read(self, size=None): def read(self, size=None):
if self.conn is None: if self.conn is None:
return '' return b('')
chunks = [] chunks = []
if size is None or size < 0: if size is None or size < 0:
...@@ -682,7 +682,7 @@ class _FTPFile(object): ...@@ -682,7 +682,7 @@ class _FTPFile(object):
self.read_pos += len(data) self.read_pos += len(data)
remaining_bytes -= len(data) remaining_bytes -= len(data)
return ''.join(chunks) return b('').join(chunks)
@fileftperrors @fileftperrors
def write(self, data): def write(self, data):
...@@ -812,11 +812,11 @@ class _FTPFile(object): ...@@ -812,11 +812,11 @@ class _FTPFile(object):
This isn't terribly efficient. It would probably be better to do This isn't terribly efficient. It would probably be better to do
a read followed by splitlines. a read followed by splitlines.
""" """
endings = '\r\n' endings = b('\r\n')
chars = [] chars = []
append = chars.append append = chars.append
read = self.read read = self.read
join = ''.join join = b('').join
while True: while True:
char = read(1) char = read(1)
if not char: if not char:
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
fs.s3fs fs.s3fs
======= =======
**Currently only avaiable on Python2 due to boto not being available for Python3**
FS subclass accessing files in Amazon S3 FS subclass accessing files in Amazon S3
This module provides the class 'S3FS', which implements the FS filesystem This module provides the class 'S3FS', which implements the FS filesystem
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
fs.sftpfs fs.sftpfs
========= =========
**Currently only avaiable on Python2 due to paramiko not being available for Python3**
Filesystem accessing an SFTP server (via paramiko) Filesystem accessing an SFTP server (via paramiko)
""" """
......
...@@ -721,19 +721,18 @@ class FSTestCases(object): ...@@ -721,19 +721,18 @@ class FSTestCases(object):
checkcontents("hello",b("hi")) checkcontents("hello",b("hi"))
self.fs.setcontents("hello",b("1234567890")) self.fs.setcontents("hello",b("1234567890"))
checkcontents("hello",b("1234567890")) checkcontents("hello",b("1234567890"))
with self.fs.open("hello","r+") as f: with self.fs.open("hello","rb+") as f:
f.truncate(7) f.truncate(7)
checkcontents("hello",b("1234567")) checkcontents("hello",b("1234567"))
with self.fs.open("hello","r+") as f: with self.fs.open("hello","rb+") as f:
f.seek(5) f.seek(5)
f.truncate() f.truncate()
checkcontents("hello",b("12345")) checkcontents("hello",b("12345"))
def test_truncate_to_larger_size(self): def test_truncate_to_larger_size(self):
print repr(self.fs) with self.fs.open("hello","wb") as f:
print self.fs.__class__
with self.fs.open("hello","wb") as f:
f.truncate(30) f.truncate(30)
self.assertEquals(self.fs.getsize("hello"), 30) self.assertEquals(self.fs.getsize("hello"), 30)
# Some file systems (FTPFS) don't support both reading and writing # Some file systems (FTPFS) don't support both reading and writing
...@@ -792,34 +791,34 @@ class FSTestCases(object): ...@@ -792,34 +791,34 @@ class FSTestCases(object):
def test_big_file(self): def test_big_file(self):
"""Test handling of a big file (1MB)""" """Test handling of a big file (1MB)"""
chunk_size = 1024 * 256 chunk_size = 1024 * 256
num_chunks = 4 num_chunks = 4
def chunk_stream(): def chunk_stream():
"""Generate predictable-but-randomy binary content.""" """Generate predictable-but-randomy binary content."""
r = random.Random(0) r = random.Random(0)
randint = r.randint randint = r.randint
int2byte = six.int2byte int2byte = six.int2byte
for _i in xrange(num_chunks): for _i in xrange(num_chunks):
c = b("").join(int2byte(randint(0,255)) for _j in xrange(chunk_size//8)) c = b("").join(int2byte(randint(0,255)) for _j in xrange(chunk_size//8))
yield c * 8 yield c * 8
f = self.fs.open("bigfile","wb") f = self.fs.open("bigfile","wb")
try: try:
for chunk in chunk_stream(): for chunk in chunk_stream():
f.write(chunk) f.write(chunk)
finally: finally:
f.close() f.close()
chunks = chunk_stream() chunks = chunk_stream()
f = self.fs.open("bigfile","rb") f = self.fs.open("bigfile","rb")
try: try:
try: try:
while True: while True:
if chunks.next() != f.read(chunk_size): if chunks.next() != f.read(chunk_size):
assert False, "bigfile was corrupted" assert False, "bigfile was corrupted"
except StopIteration: except StopIteration:
if f.read() != b(""): if f.read() != b(""):
assert False, "bigfile was corrupted" assert False, "bigfile was corrupted"
finally: finally:
f.close() f.close()
def test_settimes(self): def test_settimes(self):
def cmp_datetimes(d1, d2): def cmp_datetimes(d1, d2):
...@@ -842,7 +841,7 @@ def chunk_stream(): ...@@ -842,7 +841,7 @@ def chunk_stream():
self.assertTrue(cmp_datetimes(d2, info['modified_time'])) self.assertTrue(cmp_datetimes(d2, info['modified_time']))
# Disabled - see below # May be disabled - see end of file
class ThreadingTestCases(object): class ThreadingTestCases(object):
"""Testcases for thread-safety of FS implementations.""" """Testcases for thread-safety of FS implementations."""
...@@ -911,7 +910,7 @@ class ThreadingTestCases(object): ...@@ -911,7 +910,7 @@ class ThreadingTestCases(object):
def test_setcontents_threaded_samefile(self): def test_setcontents_threaded_samefile(self):
def setcontents(name,contents): def setcontents(name,contents):
f = self.fs.open(name,"w") f = self.fs.open(name,"wb")
self._yield() self._yield()
try: try:
f.write(contents) f.write(contents)
...@@ -1057,6 +1056,6 @@ class ThreadingTestCases(object): ...@@ -1057,6 +1056,6 @@ class ThreadingTestCases(object):
self.assertEquals(self.fs.getcontents("thread2.txt", 'rb'),c) self.assertEquals(self.fs.getcontents("thread2.txt", 'rb'),c)
self._runThreads(thread1,thread2) self._runThreads(thread1,thread2)
# Uncomment to temporarily disable threading tests
class ThreadingTestCases(object): #class ThreadingTestCases(object):
_dont_retest = () # _dont_retest = ()
...@@ -15,7 +15,7 @@ import fs.tests ...@@ -15,7 +15,7 @@ import fs.tests
from fs.path import * from fs.path import *
from fs import zipfs from fs import zipfs
from six import b from six import PY3, b
class TestReadZipFS(unittest.TestCase): class TestReadZipFS(unittest.TestCase):
...@@ -122,9 +122,12 @@ class TestWriteZipFS(unittest.TestCase): ...@@ -122,9 +122,12 @@ class TestWriteZipFS(unittest.TestCase):
def test_creation(self): def test_creation(self):
zf = zipfile.ZipFile(self.temp_filename, "r") zf = zipfile.ZipFile(self.temp_filename, "r")
def check_contents(filename, contents): def check_contents(filename, contents):
zcontents = zf.read(filename.encode("CP437")) if PY3:
zcontents = zf.read(filename)
else:
zcontents = zf.read(filename.encode("CP437"))
self.assertEqual(contents, zcontents) self.assertEqual(contents, zcontents)
check_contents("a.txt", b()"Hello, World!") check_contents("a.txt", b("Hello, World!"))
check_contents("b.txt", b("b")) check_contents("b.txt", b("b"))
check_contents("foo/bar/baz.txt", b("baz")) check_contents("foo/bar/baz.txt", b("baz"))
check_contents("foo/second.txt", b("hai")) check_contents("foo/second.txt", b("hai"))
......
...@@ -30,5 +30,6 @@ commands = nosetests fs.tests -v \ ...@@ -30,5 +30,6 @@ commands = nosetests fs.tests -v \
deps = distribute deps = distribute
six six
dexml dexml
nose nose
winpdb
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