--- fs/appdirfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/appdirfs.py
@@ -84,6 +84,6 @@ class UserLogFS(OSFS):
 
 if __name__ == "__main__":
     udfs = UserDataFS('exampleapp', appauthor='pyfs')
-    print udfs
+    print(udfs)
     udfs2 = UserDataFS('exampleapp2', appauthor='pyfs', create=False)
-    print udfs2
+    print(udfs2)
--- fs/appdirs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/appdirs.py
@@ -21,7 +21,7 @@ import os
 PY3 = sys.version_info[0] == 3
 
 if PY3:
-    unicode = str
+    str = str
 
 class AppDirsError(Exception):
     pass
@@ -248,7 +248,7 @@ def _get_win_folder_from_registry(csidl_name):
     registry for this guarantees us the correct answer for all CSIDL_*
     names.
     """
-    import _winreg
+    import winreg
 
     shell_folder_name = {
         "CSIDL_APPDATA": "AppData",
@@ -256,9 +256,9 @@ def _get_win_folder_from_registry(csidl_name):
         "CSIDL_LOCAL_APPDATA": "Local AppData",
     }[csidl_name]
 
-    key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
+    key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
         r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
-    dir, type = _winreg.QueryValueEx(key, shell_folder_name)
+    dir, type = winreg.QueryValueEx(key, shell_folder_name)
     return dir
 
 def _get_win_folder_with_pywin32(csidl_name):
@@ -268,7 +268,7 @@ def _get_win_folder_with_pywin32(csidl_name):
     # not return unicode strings when there is unicode data in the
     # path.
     try:
-        dir = unicode(dir)
+        dir = str(dir)
 
         # Downgrade to short path name if have highbit chars. See
         # <http://bugs.activestate.com/show_bug.cgi?id=85099>.
@@ -337,9 +337,9 @@ if __name__ == "__main__":
     print("-- app dirs (without optional 'version')")
     dirs = AppDirs(appname, appauthor, version="1.0")
     for prop in props:
-        print("%s: %s" % (prop, getattr(dirs, prop)))
+        print(("%s: %s" % (prop, getattr(dirs, prop))))
 
     print("\n-- app dirs (with optional 'version')")
     dirs = AppDirs(appname, appauthor)
     for prop in props:
-        print("%s: %s" % (prop, getattr(dirs, prop)))
+        print(("%s: %s" % (prop, getattr(dirs, prop))))
--- fs/base.py.orig	2022-03-04 17:14:43 UTC
+++ fs/base.py
@@ -12,8 +12,8 @@ For more information regarding implementing a working 
 
 """
 
-from __future__ import with_statement
 
+
 __all__ = ['DummyLock',
            'silence_fserrors',
            'NullFile',
@@ -109,7 +109,7 @@ class NullFile(object):
     def flush(self):
         pass
 
-    def next(self):
+    def __next__(self):
         raise StopIteration
 
     def readline(self, *args, **kwargs):
@@ -900,7 +900,7 @@ class FS(object):
                                   chunk_size=1024 * 64,
                                   progress_callback=progress_callback,
                                   finished_callback=finished_callback)
-            except Exception, e:
+            except Exception as e:
                 if error_callback is not None:
                     error_callback(e)
             finally:
@@ -1156,7 +1156,7 @@ class FS(object):
     def _shutil_copyfile(cls, src_syspath, dst_syspath):
         try:
             shutil.copyfile(src_syspath, dst_syspath)
-        except IOError, e:
+        except IOError as e:
             #  shutil reports ENOENT when a parent directory is missing
             if getattr(e, "errno", None) == errno.ENOENT:
                 if not os.path.exists(dirname(dst_syspath)):
--- fs/browsewin.py.orig	2022-03-04 17:14:43 UTC
+++ fs/browsewin.py
@@ -24,7 +24,7 @@ class InfoFrame(wx.Frame):
 
         self.SetTitle("FS Object info - %s (%s)" % (path, desc))
 
-        keys = info.keys()
+        keys = list(info.keys())
         keys.sort()
 
         self.list_ctrl = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
@@ -36,7 +36,7 @@ class InfoFrame(wx.Frame):
         self.list_ctrl.SetColumnWidth(1, 300)
 
         for key in sorted(keys, key=lambda k:k.lower()):
-            self.list_ctrl.Append((key, unicode(info.get(key))))
+            self.list_ctrl.Append((key, str(info.get(key))))
             
         self.Center()
 
@@ -50,7 +50,7 @@ class BrowseFrame(wx.Frame):
 
         self.fs = fs
         self.hide_dotfiles = hide_dotfiles
-        self.SetTitle("FS Browser - " + unicode(fs))
+        self.SetTitle("FS Browser - " + str(fs))
 
         self.tree = wx.gizmos.TreeListCtrl(self, -1, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
 
@@ -105,7 +105,7 @@ class BrowseFrame(wx.Frame):
         try:
             paths = ( [(True, p) for p in self.fs.listdir(path, absolute=True, dirs_only=True)] +
                       [(False, p) for p in self.fs.listdir(path, absolute=True, files_only=True)] )
-        except FSError, e:
+        except FSError as e:
             msg = "Failed to get directory listing for %s\n\nThe following error was reported:\n\n%s" % (path, e)
             wx.MessageDialog(self, msg, "Error listing directory", wx.OK).ShowModal()
             paths = []
@@ -194,6 +194,6 @@ def browse(fs, hide_dotfiles=False):
 
 
 if __name__ == "__main__":
-    from osfs import OSFS
+    from .osfs import OSFS
     home_fs = OSFS("~/")
     browse(home_fs, True)
--- fs/commands/fscp.py.orig	2022-03-04 17:14:43 UTC
+++ fs/commands/fscp.py
@@ -3,7 +3,7 @@ from fs.utils import copyfile, copyfile_non_atomic
 from fs.path import pathjoin, iswildcard
 from fs.commands.runner import Command
 import sys
-import Queue as queue
+import queue as queue
 import time
 import threading
 
@@ -31,7 +31,7 @@ class FileOpThread(threading.Thread):            
                     self.dest_fs.makedir(path, recursive=True, allow_recreate=True)
                 else:                                                                
                     self.action(fs, path, self.dest_fs, dest_path, overwrite=True)                    
-            except Exception, e:                
+            except Exception as e:                
                 self.on_error(e)                                
                 self.queue.task_done()                                  
                 break                   
@@ -147,7 +147,7 @@ Copy SOURCE to DESTINATION"""
                                 file_queue,
                                 self.on_done,
                                 self.on_error)
-                        for i in xrange(options.threads)]
+                        for i in range(options.threads)]
         
         for thread in threads:
             thread.start()
@@ -188,7 +188,7 @@ Copy SOURCE to DESTINATION"""
         
         if self.action_errors:
             for error in self.action_errors:
-                self.error(self.wrap_error(unicode(error)) + '\n')            
+                self.error(self.wrap_error(str(error)) + '\n')            
             sys.stdout.flush()
         else:
             if complete and options.progress:
@@ -204,9 +204,9 @@ Copy SOURCE to DESTINATION"""
         try:
             if self.options.verbose:
                 if path_type == self.DIR:
-                    print "mkdir %s" % dst_fs.desc(dst_path)
+                    print("mkdir %s" % dst_fs.desc(dst_path))
                 else:
-                    print "%s -> %s" % (src_fs.desc(src_path), dst_fs.desc(dst_path))
+                    print("%s -> %s" % (src_fs.desc(src_path), dst_fs.desc(dst_path)))
             elif self.options.progress:
                 self.done_files += 1        
                 sys.stdout.write(self.progress_bar(self.total_files, self.done_files, self.get_verb()))
--- fs/commands/fsinfo.py.orig	2022-03-04 17:14:43 UTC
+++ fs/commands/fsinfo.py
@@ -31,12 +31,12 @@ Display information regarding an FS resource"""
             return val
 
         def make_printable(text):
-            if not isinstance(text, basestring):
+            if not isinstance(text, str):
                 try:
                     text = str(text)
                 except:
                     try:
-                        text = unicode(text)
+                        text = str(text)
                     except:
                         text = repr(text)
             return text
@@ -48,16 +48,16 @@ Display information regarding an FS resource"""
                                                    dirs_only=options.dirsonly):                        
             if not options.omit:
                 if options.simple:           
-                    file_line = u'%s\n' % self.wrap_filename(path)
+                    file_line = '%s\n' % self.wrap_filename(path)
                 else:
-                    file_line = u'[%s] %s\n' % (self.wrap_filename(path), self.wrap_faded(fs.desc(path)))
+                    file_line = '[%s] %s\n' % (self.wrap_filename(path), self.wrap_faded(fs.desc(path)))
                 self.output(file_line)            
             info = fs.getinfo(path)
                                             
-            for k, v in info.items():
+            for k, v in list(info.items()):
                 if k.startswith('_'):
                     del info[k]
-                elif not isinstance(v, (basestring, int, long, float, bool, datetime)):
+                elif not isinstance(v, (str, int, float, bool, datetime)):
                     del info[k]                
                         
             if keys:            
--- fs/commands/fsls.py.orig	2022-03-04 17:14:43 UTC
+++ fs/commands/fsls.py
@@ -37,7 +37,7 @@ List contents of [PATH]"""
         output = self.output
 
         if not args:
-            args = [u'.']
+            args = ['.']
 
         dir_paths = []
         file_paths = []
@@ -75,13 +75,13 @@ List contents of [PATH]"""
 
         if options.syspath:
             # Path without a syspath, just won't be displayed
-            dir_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in dir_paths])
-            file_paths = filter(None, [fs.getsyspath(path, allow_none=True) for path in file_paths])
+            dir_paths = [_f for _f in [fs.getsyspath(path, allow_none=True) for path in dir_paths] if _f]
+            file_paths = [_f for _f in [fs.getsyspath(path, allow_none=True) for path in file_paths] if _f]
 
         if options.url:
             # Path without a syspath, just won't be displayed
-            dir_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in dir_paths])
-            file_paths = filter(None, [fs.getpathurl(path, allow_none=True) for path in file_paths])
+            dir_paths = [_f for _f in [fs.getpathurl(path, allow_none=True) for path in dir_paths] if _f]
+            file_paths = [_f for _f in [fs.getpathurl(path, allow_none=True) for path in file_paths] if _f]
 
         dirs = frozenset(dir_paths)
         paths = sorted(dir_paths + file_paths, key=lambda p: p.lower())
@@ -95,7 +95,7 @@ List contents of [PATH]"""
         def columnize(paths, num_columns):
 
             col_height = (len(paths) + num_columns - 1) / num_columns
-            columns = [[] for _ in xrange(num_columns)]
+            columns = [[] for _ in range(num_columns)]
             col_no = 0
             col_pos = 0
             for path in paths:
@@ -128,11 +128,11 @@ List contents of [PATH]"""
 
         def condense_columns(columns):
             max_column_height = max([len(col) for col in columns])
-            lines = [[] for _ in xrange(max_column_height)]
+            lines = [[] for _ in range(max_column_height)]
             for column in columns:
                 for line, path in zip(lines, column):
                     line.append(path)
-            return '\n'.join(u'  '.join(line) for line in lines)
+            return '\n'.join('  '.join(line) for line in lines)
 
         if options.long:
             for path in paths:
@@ -151,7 +151,7 @@ List contents of [PATH]"""
             while num_cols:
                 col_height = (num_paths + num_cols - 1) // num_cols
                 line_width = 0
-                for col_no in xrange(num_cols):
+                for col_no in range(num_cols):
                     try:
                         col_width = max(path_widths[col_no * col_height: (col_no + 1) * col_height])
                     except ValueError:
--- fs/commands/fsserve.py.orig	2015-04-12 17:24:29 UTC
+++ fs/commands/fsserve.py
@@ -82,7 +82,7 @@ Serves the contents of PATH with one of a number of me
                 try:
                     self.output("Starting sftp server on %s:%i\n" % (options.addr, port), verbose=True)
                     server.serve_forever()
-                except Exception, e:
+                except Exception as e:
                     pass
                 finally:
                     server.server_close()
@@ -90,7 +90,7 @@ Serves the contents of PATH with one of a number of me
             else:
                 self.error("Server type '%s' not recognised\n" % options.type)
 
-        except IOError, e:
+        except IOError as e:
             if e.errno == errno.EACCES:
                 self.error('Permission denied\n')
                 return 1
--- fs/commands/fstree.py.orig	2022-03-04 17:14:43 UTC
+++ fs/commands/fstree.py
@@ -34,7 +34,7 @@ Recursively display the contents of PATH in an ascii t
     
         for fs, path, is_dir in self.get_resources(args, single=True):                            
             if not is_dir:
-                self.error(u"'%s' is not a dir\n" % path)
+                self.error("'%s' is not a dir\n" % path)
                 return 1
             fs.cache_hint(True)
             if options.gui:
--- fs/commands/runner.py.orig	2022-03-04 17:14:43 UTC
+++ fs/commands/runner.py
@@ -68,7 +68,7 @@ else:
 
 
 def _unicode(text):
-    if not isinstance(text, unicode):
+    if not isinstance(text, str):
         return text.decode('ascii', 'replace')
     return text
 
@@ -128,17 +128,17 @@ class Command(object):
         text = _unicode(text)
         if not self.terminal_colors:
             return text
-        return u'\x1b[2m%s\x1b[0m' % text
+        return '\x1b[2m%s\x1b[0m' % text
 
     def wrap_link(self, text):
         if not self.terminal_colors:
             return text
-        return u'\x1b[1;33m%s\x1b[0m' % text
+        return '\x1b[1;33m%s\x1b[0m' % text
 
     def wrap_strong(self, text):
         if not self.terminal_colors:
             return text
-        return u'\x1b[1m%s\x1b[0m' % text
+        return '\x1b[1m%s\x1b[0m' % text
 
     def wrap_table_header(self, name):
         if not self.terminal_colors:
@@ -215,10 +215,10 @@ class Command(object):
         return resources
 
     def ask(self, msg):
-        return raw_input('%s: %s ' % (self.name, msg))
+        return input('%s: %s ' % (self.name, msg))
 
     def text_encode(self, text):
-        if not isinstance(text, unicode):
+        if not isinstance(text, str):
             text = text.decode('ascii', 'replace')
         text = text.encode(self.encoding, 'replace')
         return text
@@ -226,7 +226,7 @@ class Command(object):
     def output(self, msgs, verbose=False):
         if verbose and not self.options.verbose:
             return
-        if isinstance(msgs, basestring):
+        if isinstance(msgs, str):
             msgs = (msgs,)
         for msg in msgs:
             self.output_file.write(self.text_encode(msg))
@@ -276,7 +276,7 @@ class Command(object):
 
         opener_table = []
 
-        for fs_opener in opener.openers.itervalues():
+        for fs_opener in opener.openers.values():
             names = fs_opener.names
             desc = getattr(fs_opener, 'desc', '')
             opener_table.append((names, desc))
@@ -346,12 +346,12 @@ class Command(object):
                 opener.add(new_opener)
 
         if not six.PY3:
-            args = [unicode(arg, sys.getfilesystemencoding()) for arg in args]
+            args = [str(arg, sys.getfilesystemencoding()) for arg in args]
         self.verbose = options.verbose
         try:
             return self.do_run(options, args) or 0
-        except FSError, e:
-            self.error(self.wrap_error(unicode(e)) + '\n')
+        except FSError as e:
+            self.error(self.wrap_error(str(e)) + '\n')
             if options.debug:
                 raise
             return 1
@@ -361,8 +361,8 @@ class Command(object):
             return 0
         except SystemExit:
             return 0
-        except Exception, e:
-            self.error(self.wrap_error('Error - %s\n' % unicode(e)))
+        except Exception as e:
+            self.error(self.wrap_error('Error - %s\n' % str(e)))
             if options.debug:
                 raise
             return 1
--- fs/contrib/archivefs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/archivefs.py
@@ -62,7 +62,7 @@ class ArchiveFS(FS):
         :param thread_synchronize: set to True (default) to enable thread-safety
         """
         super(ArchiveFS, self).__init__(thread_synchronize=thread_synchronize)
-        if isinstance(f, basestring):
+        if isinstance(f, str):
             self.fileobj = None
             self.root_path = f
         else:
@@ -83,7 +83,7 @@ class ArchiveFS(FS):
         return "<ArchiveFS: %s>" % self.root_path
 
     def __unicode__(self):
-        return u"<ArchiveFS: %s>" % self.root_path
+        return "<ArchiveFS: %s>" % self.root_path
 
     def getmeta(self, meta_name, default=NoDefaultMeta):
         if meta_name == 'read_only':
@@ -446,7 +446,7 @@ class ArchiveMountFS(mountfs.MountFS):
             else:
                 listing = self.listdir(path, *args, **kwargs)
             if dirs_only:
-                listing = filter(isdir, listing)
+                listing = list(filter(isdir, listing))
             return listing
 
         if wildcard is None:
--- fs/contrib/bigfs/__init__.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/bigfs/__init__.py
@@ -149,7 +149,7 @@ class _ExceptionProxy(object):
     def __setattr__(self, name, value):
         raise ValueError("File has been closed")
 
-    def __nonzero__(self):
+    def __bool__(self):
         return False
 
 
@@ -193,7 +193,7 @@ class BigFS(FS):
         return "<BigFS: %s>" % self.big_path
 
     def __unicode__(self):
-        return unicode(self.__str__())
+        return str(self.__str__())
 
 
     def _parse_resource_list(self, g):
--- fs/contrib/bigfs/subrangefile.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/bigfs/subrangefile.py
@@ -33,7 +33,7 @@ class SubrangeFile:
         return "<SubrangeFile: %s@%d size=%d>" % (self.name, self.startOffset, self.fileSize)
 
     def __unicode__(self):
-        return unicode(self.__str__())
+        return str(self.__str__())
 
     def size(self):
         return self.fileSize
--- fs/contrib/davfs/__init__.py.orig	2015-04-12 17:24:29 UTC
+++ fs/contrib/davfs/__init__.py
@@ -16,21 +16,21 @@ Requires the dexml module:
 #  Copyright (c) 2009-2010, Cloud Matrix Pty. Ltd.
 #  All rights reserved; available under the terms of the MIT License.
 
-from __future__ import with_statement
 
+
 import os
 import sys
-import httplib
+import http.client
 import socket
-from urlparse import urlparse
+from urllib.parse import urlparse
 import stat as statinfo
-from urllib import quote as urlquote
-from urllib import unquote as urlunquote
+from urllib.parse import quote as urlquote
+from urllib.parse import unquote as urlunquote
 import base64
 import re
 import time
 import datetime
-import cookielib
+import http.cookiejar
 import fnmatch
 import xml.dom.pulldom
 import threading
@@ -78,8 +78,8 @@ class DAVFS(FS):
     """
 
     connection_classes = {
-        "http":  httplib.HTTPConnection,
-        "https":  httplib.HTTPSConnection,
+        "http":  http.client.HTTPConnection,
+        "https":  http.client.HTTPSConnection,
     }
 
     _DEFAULT_PORT_NUMBERS = {
@@ -116,7 +116,7 @@ class DAVFS(FS):
         self._connections = []
         self._free_connections = {}
         self._connection_lock = threading.Lock()
-        self._cookiejar = cookielib.CookieJar()
+        self._cookiejar = http.cookiejar.CookieJar()
         super(DAVFS,self).__init__(thread_synchronize=thread_synchronize)
         #  Check that the server speaks WebDAV, and normalize the URL
         #  after any redirects have been followed.
@@ -221,14 +221,14 @@ class DAVFS(FS):
         self._free_connections = {}
         self._connection_lock = threading.Lock()
         self._url_p = urlparse(self.url)
-        self._cookiejar = cookielib.CookieJar()
+        self._cookiejar = http.cookiejar.CookieJar()
 
     def getpathurl(self, path, allow_none=False):
         """Convert a client-side path into a server-side URL."""
         path = relpath(normpath(path))
         if path.endswith("/"):
             path = path[:-1]
-        if isinstance(path,unicode):
+        if isinstance(path,str):
             path = path.encode("utf8")
         return self.url + urlquote(path)
 
@@ -291,7 +291,7 @@ class DAVFS(FS):
         """Perform a single HTTP request, without any error handling."""
         if self.closed:
             raise RemoteConnectionError("",msg="FS is closed")
-        if isinstance(url,basestring):
+        if isinstance(url,str):
             url = urlparse(url)
         if self.credentials is not None:
             username = self.credentials.get("username","")
@@ -310,7 +310,7 @@ class DAVFS(FS):
                 if hasattr(body,"md5"):
                     md5 = body.md5.decode("hex").encode("base64")
                     con.putheader("Content-MD5",md5)
-                for hdr,val in headers.iteritems():
+                for hdr,val in headers.items():
                     con.putheader(hdr,val)
                 self._cookiejar.add_cookie_header(FakeReq(con,url.scheme,url.path))
                 con.endheaders()
@@ -332,7 +332,7 @@ class DAVFS(FS):
                     self._give_connection(url,con)
                 resp.close = new_close
                 return resp
-        except socket.error, e:
+        except socket.error as e:
             if not fresh:
                 return self._raw_request(url,method,body,headers,num_tries)
             if e.args[0] in _RETRYABLE_ERRORS:
@@ -479,7 +479,7 @@ class DAVFS(FS):
                 if not entry_ok:
                     continue
                 if wildcard is not None:
-                    if isinstance(wildcard,basestring):
+                    if isinstance(wildcard,str):
                         if not fnmatch.fnmatch(nm,wildcard):
                             continue
                     else:
@@ -530,7 +530,7 @@ class DAVFS(FS):
                 if not entry_ok:
                     continue
                 if wildcard is not None:
-                    if isinstance(wildcard,basestring):
+                    if isinstance(wildcard,str):
                         if not fnmatch.fnmatch(nm,wildcard):
                             continue
                     else:
@@ -610,7 +610,7 @@ class DAVFS(FS):
                 if self._isurl(path,res.href):
                     info.update(self._info_from_propfind(res))
             if "st_mode" not in info:
-               info["st_mode"] = 0700 | statinfo.S_IFREG
+               info["st_mode"] = 0o700 | statinfo.S_IFREG
             return info
         finally:
             response.close()
@@ -647,7 +647,7 @@ class DAVFS(FS):
             # TODO: should check for status of the propfind first...
             # check for directory indicator
             if findElements("DAV:","collection"):
-                info["st_mode"] = 0700 | statinfo.S_IFDIR
+                info["st_mode"] = 0o700 | statinfo.S_IFDIR
             # check for content length
             cl = findElements("DAV:","getcontentlength")
             if cl:
@@ -674,7 +674,7 @@ class DAVFS(FS):
                 if etag:
                     info["etag"] = etag
         if "st_mode" not in info:
-            info["st_mode"] = 0700 | statinfo.S_IFREG
+            info["st_mode"] = 0o700 | statinfo.S_IFREG
         return info
 
 
--- fs/contrib/davfs/util.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/davfs/util.py
@@ -8,7 +8,7 @@
 
 import os
 import re
-import cookielib
+import http.cookiejar
 
 
 def get_fileno(file):
@@ -130,7 +130,7 @@ class FakeResp:
 #  is a tweaked version of the cookielib function of the same name.
 #
 _test_cookie = "sessionid=e9c9b002befa93bd865ce155270307ef; Domain=.cloud.me; expires=Wed, 10-Feb-2010 03:27:20 GMT; httponly; Max-Age=1209600; Path=/, sessionid_https=None; Domain=.cloud.me; expires=Wed, 10-Feb-2010 03:27:20 GMT; httponly; Max-Age=1209600; Path=/; secure"
-if len(cookielib.parse_ns_headers([_test_cookie])) != 2:
+if len(http.cookiejar.parse_ns_headers([_test_cookie])) != 2:
     def parse_ns_headers(ns_headers):
       """Improved parser for netscape-style cookies.
 
@@ -170,13 +170,13 @@ if len(cookielib.parse_ns_headers([_test_cookie])) != 
                     # convert expires date to seconds since epoch
                     if v.startswith('"'): v = v[1:]
                     if v.endswith('"'): v = v[:-1]
-                    v = cookielib.http2time(v)  # None if invalid
+                    v = http.cookiejar.http2time(v)  # None if invalid
             pairs.append((k, v))
         if pairs:
             if not version_set:
                 pairs.append(("version", "0"))
             result.append(pairs)
       return result
-    cookielib.parse_ns_headers = parse_ns_headers
-    assert len(cookielib.parse_ns_headers([_test_cookie])) == 2 
+    http.cookiejar.parse_ns_headers = parse_ns_headers
+    assert len(http.cookiejar.parse_ns_headers([_test_cookie])) == 2 
 
--- fs/contrib/davfs/xmlobj.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/davfs/xmlobj.py
@@ -9,9 +9,9 @@ of dexml.Model subclasses.
 
 """
 
-from urlparse import urlparse, urlunparse
+from urllib.parse import urlparse, urlunparse
 
-from httplib import responses as STATUS_CODE_TEXT
+from http.client import responses as STATUS_CODE_TEXT
 STATUS_CODE_TEXT[207] = "Multi-Status"
 
 import dexml
@@ -86,7 +86,7 @@ class StatusField(fields.Value):
         return val
 
     def __set__(self,instance,value):
-        if isinstance(value,basestring):
+        if isinstance(value,str):
             # sanity check it
             bits = value.split(" ")
             if len(bits) < 3 or bits[0] != "HTTP/1.1":
--- fs/contrib/sqlitefs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/contrib/sqlitefs.py
@@ -24,7 +24,7 @@ def fetchone(cursor):
     '''
     row = None
     try:
-        row = cursor.next()
+        row = next(cursor)
     except:
         pass
     return(row)
@@ -62,7 +62,7 @@ class SqliteFsFileBase(object):
     __repr__ = __str__
 
     def __unicode__(self):
-        return u"<SqliteFS File in %s %s>" % (self.fs, self.path)
+        return "<SqliteFS File in %s %s>" % (self.fs, self.path)
 
     def __del__(self):
         if not self.closed:
@@ -74,7 +74,7 @@ class SqliteFsFileBase(object):
     def __iter__(self):
         raise OperationFailedError('__iter__', self.path)
         
-    def next(self):
+    def __next__(self):
         raise OperationFailedError('next', self.path)
         
     def readline(self, *args, **kwargs):
@@ -139,8 +139,8 @@ class SqliteReadableFile(SqliteFsFileBase):
     def __iter__(self):
         return iter(self.real_stream)
 
-    def next(self):
-        return self.real_stream.next()
+    def __next__(self):
+        return next(self.real_stream)
 
     def readline(self, *args, **kwargs):
         return self.real_stream.readline(*args, **kwargs)
@@ -438,7 +438,7 @@ class SqliteFS(FS):
         get the directory information dictionary.
         '''
         info = dict()
-        info['st_mode'] = 0755
+        info['st_mode'] = 0o755
         return info
         
     def _get_file_info(self, path):
@@ -460,7 +460,7 @@ class SqliteFS(FS):
         info['created'] = row[2]
         info['last_modified'] = row[3]
         info['last_accessed'] = row[4]
-        info['st_mode'] = 0666
+        info['st_mode'] = 0o666
         return(info)
         
     def _isfile(self,path):
@@ -551,7 +551,7 @@ class SqliteFS(FS):
             pass
         
         if( absolute == False):
-            pathlist = map(lambda dpath:frombase(path,dpath), pathlist)
+            pathlist = [frombase(path,dpath) for dpath in pathlist]
             
         return(pathlist)
         
--- fs/contrib/tahoelafs/__init__.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/tahoelafs/__init__.py
@@ -70,8 +70,8 @@ from fs import _thread_synchronize_default, SEEK_END
 from fs.remote import CacheFSMixin, RemoteFileBuffer
 from fs.base import fnmatch, NoDefaultMeta
 
-from util import TahoeUtil
-from connection import Connection   
+from .util import TahoeUtil
+from .connection import Connection   
 
 from six import b
 
@@ -240,7 +240,7 @@ class _TahoeLAFS(FS):
                 continue
             
             if wildcard is not None:
-                if isinstance(wildcard,basestring):
+                if isinstance(wildcard,str):
                     if not fnmatch.fnmatch(item['name'], wildcard):
                         continue
                 else:
@@ -269,7 +269,7 @@ class _TahoeLAFS(FS):
         
         try:
             self.tahoeutil.unlink(self.dircap, path)
-        except Exception, e:
+        except Exception as e:
             raise errors.ResourceInvalidError(path)
     
     @_fix_path
@@ -341,8 +341,8 @@ class _TahoeLAFS(FS):
     
     def _log(self, level, message):
         if not logger.isEnabledFor(level): return
-        logger.log(level, u'(%d) %s' % (id(self),
-                                unicode(message).encode('ASCII', 'replace')))
+        logger.log(level, '(%d) %s' % (id(self),
+                                str(message).encode('ASCII', 'replace')))
         
     @_fix_path
     def getpathurl(self, path, allow_none=False, webapi=None):
@@ -353,11 +353,11 @@ class _TahoeLAFS(FS):
             webapi = self.connection.webapi
         self._log(DEBUG, "Retrieving URL for %s over %s" % (path, webapi))
         path = self.tahoeutil.fixwinpath(path, False)
-        return u"%s/uri/%s%s" % (webapi, self.dircap, path)
+        return "%s/uri/%s%s" % (webapi, self.dircap, path)
 
     @_fix_path
     def getrange(self, path, offset, length=None):
-        return self.connection.get(u'/uri/%s%s' % (self.dircap, path),
+        return self.connection.get('/uri/%s%s' % (self.dircap, path),
                     offset=offset, length=length)
        
     @_fix_path             
@@ -379,10 +379,10 @@ class _TahoeLAFS(FS):
             file.seek(0)
 
             if size > self.largefilesize:
-                self.connection.put(u'/uri/%s%s' % (self.dircap, path),
+                self.connection.put('/uri/%s%s' % (self.dircap, path),
                     "PyFilesystem.TahoeLAFS: Upload started, final size %d" % size)
 
-        self.connection.put(u'/uri/%s%s' % (self.dircap, path), file, size=size)
+        self.connection.put('/uri/%s%s' % (self.dircap, path), file, size=size)
 
     @_fix_path
     def getinfo(self, path): 
--- fs/contrib/tahoelafs/connection.py.orig	2015-04-12 17:24:29 UTC
+++ fs/contrib/tahoelafs/connection.py
@@ -10,17 +10,19 @@ if python3:
     from urllib.parse import urlencode, pathname2url, quote
     from urllib.request import Request, urlopen
 else:
-    from urllib import urlencode, pathname2url
-    from urllib2 import Request, urlopen, quote
+    from urllib.parse import urlencode
+    from urllib.request import pathname2url
+    from urllib.request import Request, urlopen
+    from urllib.parse import quote
 
 class PutRequest(Request):
     def __init__(self, *args, **kwargs):
-        self.get_method = lambda: u'PUT'
+        self.get_method = lambda: 'PUT'
         Request.__init__(self, *args, **kwargs)
          
 class DeleteRequest(Request):
     def __init__(self, *args, **kwargs):
-        self.get_method = lambda: u'DELETE'
+        self.get_method = lambda: 'DELETE'
         Request.__init__(self, *args, **kwargs)
               
 class Connection:
@@ -32,7 +34,7 @@ class Connection:
         '''
             Retrieve length of string or file object and prepare HTTP headers.
         '''
-        if isinstance(f, basestring):
+        if isinstance(f, str):
             # Just set up content length
             size = len(f)
         elif getattr(f, 'read', None):
@@ -50,20 +52,20 @@ class Connection:
 
     def _urlencode(self, data):
         _data = {}
-        for k, v in data.items():
+        for k, v in list(data.items()):
             _data[k.encode('utf-8')] = v.encode('utf-8')
         return urlencode(_data)
 
     def _quotepath(self, path, params={}):
         q = quote(path.encode('utf-8'), safe='/')
         if params:
-            return u"%s?%s" % (q, self._urlencode(params))
+            return "%s?%s" % (q, self._urlencode(params))
         return q
         
     def _urlopen(self, req):
         try:
             return urlopen(req)
-        except Exception, e:
+        except Exception as e:
             if not getattr(e, 'getcode', None):
                 raise errors.RemoteConnectionError(str(e))
             code = e.getcode()
@@ -85,7 +87,7 @@ class Connection:
         data = self._urlencode(data)
         path = self._quotepath(path)
         if data: 
-            path = u'?'.join([path, data])
+            path = '?'.join([path, data])
 
         headers = {}
         headers.update(self.headers)
--- fs/contrib/tahoelafs/test_tahoelafs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/tahoelafs/test_tahoelafs.py
@@ -35,7 +35,7 @@ class TestTahoeLAFS(unittest.TestCase,FSTestCases):#,T
          
     def test_dircap(self):
         # Is dircap in correct format?
-        self.assert_(self.dircap.startswith('URI:DIR2:') and len(self.dircap) > 50)
+        self.assertTrue(self.dircap.startswith('URI:DIR2:') and len(self.dircap) > 50)
      
     def test_concurrent_copydir(self):
         #  makedir() on TahoeLAFS is currently not atomic
--- fs/contrib/tahoelafs/util.py.orig	2022-03-04 17:14:43 UTC
+++ fs/contrib/tahoelafs/util.py
@@ -19,7 +19,7 @@ except ImportError:
     try:
         import json
     except ImportError:
-        print "simplejson (http://pypi.python.org/pypi/simplejson/) required"
+        print("simplejson (http://pypi.python.org/pypi/simplejson/) required")
         raise
     
 from .connection import Connection
@@ -29,22 +29,22 @@ python3 = int(platform.python_version_tuple()[0]) > 2
 if python3:
     from urllib.error import HTTPError
 else:
-    from urllib2 import HTTPError 
+    from urllib.error import HTTPError 
     
 class TahoeUtil:
     def __init__(self, webapi):
         self.connection = Connection(webapi)
         
     def createdircap(self):
-        return self.connection.post(u'/uri', params={u't': u'mkdir'}).read()
+        return self.connection.post('/uri', params={'t': 'mkdir'}).read()
             
     def unlink(self, dircap, path=None):
         path = self.fixwinpath(path, False)
-        self.connection.delete(u'/uri/%s%s' % (dircap, path))
+        self.connection.delete('/uri/%s%s' % (dircap, path))
     
     def info(self, dircap, path):
         path = self.fixwinpath(path, False)
-        meta = json.load(self.connection.get(u'/uri/%s%s' % (dircap, path), {u't': u'json'}))
+        meta = json.load(self.connection.get('/uri/%s%s' % (dircap, path), {'t': 'json'}))
         return self._info(path, meta)
             
     def fixwinpath(self, path, direction=True):
@@ -74,7 +74,7 @@ class TahoeUtil:
         if type == 'unknown':
             raise errors.ResourceNotFoundError(path)
         
-        info = {'name': unicode(self.fixwinpath(path, True)),
+        info = {'name': str(self.fixwinpath(path, True)),
                 'type': type,
                 'size': data.get('size', 0),
                 'ctime': None,
@@ -83,22 +83,22 @@ class TahoeUtil:
             info['ctime'] = data['metadata'].get('ctime')
     
         if info['type'] == 'dirnode':
-            info['st_mode'] = 0777 |  statinfo.S_IFDIR 
+            info['st_mode'] = 0o777 |  statinfo.S_IFDIR 
         else:
-            info['st_mode'] = 0644
+            info['st_mode'] = 0o644
 
         return info
         
     def list(self, dircap, path=None):
         path = self.fixwinpath(path, False)
         
-        data = json.load(self.connection.get(u'/uri/%s%s' % (dircap, path), {u't': u'json'}))     
+        data = json.load(self.connection.get('/uri/%s%s' % (dircap, path), {'t': 'json'}))     
 
         if len(data) < 2 or data[0] != 'dirnode':
             raise errors.ResourceInvalidError('Metadata in unknown format!')
         
         data = data[1]['children']
-        for i in data.keys():
+        for i in list(data.keys()):
             x = self._info(i, data[i])
             yield x
 
@@ -106,7 +106,7 @@ class TahoeUtil:
         path = self.fixwinpath(path, False)    
         path = pathsplit(path)
         
-        self.connection.post(u"/uri/%s%s" % (dircap, path[0]), data={u't': u'mkdir', u'name': path[1]})
+        self.connection.post("/uri/%s%s" % (dircap, path[0]), data={'t': 'mkdir', 'name': path[1]})
     
     def move(self, dircap, src, dst):
         if src == '/' or dst == '/':
@@ -120,8 +120,8 @@ class TahoeUtil:
         
         if src_tuple[0] == dst_tuple[0]:
             # Move inside one directory
-            self.connection.post(u"/uri/%s%s" % (dircap, src_tuple[0]), data={u't': u'rename',
-                                        u'from_name': src_tuple[1], u'to_name': dst_tuple[1]})
+            self.connection.post("/uri/%s%s" % (dircap, src_tuple[0]), data={'t': 'rename',
+                                        'from_name': src_tuple[1], 'to_name': dst_tuple[1]})
             return
 
         # Move to different directory. Firstly create link on dst, then remove from src
@@ -133,7 +133,7 @@ class TahoeUtil:
             self.unlink(dircap, dst)
          
         uri = self.info(dircap, src)['uri']
-        self.connection.put(u"/uri/%s%s" % (dircap, dst), data=uri, params={u't': u'uri'})        
+        self.connection.put("/uri/%s%s" % (dircap, dst), data=uri, params={'t': 'uri'})        
         if uri != self.info(dircap, dst)['uri']:
             raise errors.OperationFailedError('Move failed')
         
--- fs/errors.py.orig	2015-04-12 17:24:29 UTC
+++ fs/errors.py
@@ -57,19 +57,19 @@ class FSError(Exception):
 
     def __str__(self):
         keys = {}
-        for k,v in self.__dict__.iteritems():
-            if isinstance(v,unicode):
+        for k,v in self.__dict__.items():
+            if isinstance(v,str):
                 v = v.encode(sys.getfilesystemencoding())
             keys[k] = v
         return str(self.msg % keys)
 
     def __unicode__(self):
         keys = {}
-        for k,v in self.__dict__.iteritems():
+        for k,v in self.__dict__.items():
             if isinstance(v, six.binary_type):
                 v = v.decode(sys.getfilesystemencoding(), 'replace')
             keys[k] = v
-        return unicode(self.msg, encoding=sys.getfilesystemencoding(), errors='replace') % keys
+        return str(self.msg, encoding=sys.getfilesystemencoding(), errors='replace') % keys
 
     def __reduce__(self):
         return (self.__class__,(),self.__dict__.copy(),)
@@ -217,33 +217,33 @@ def convert_fs_errors(func):
     def wrapper(*args,**kwds):
         try:
             return func(*args,**kwds)
-        except ResourceNotFoundError, e:
+        except ResourceNotFoundError as e:
             raise OSError(errno.ENOENT,str(e))
-        except ParentDirectoryMissingError, e:
+        except ParentDirectoryMissingError as e:
             if sys.platform == "win32":
                 raise OSError(errno.ESRCH,str(e))
             else:
                 raise OSError(errno.ENOENT,str(e))
-        except ResourceInvalidError, e:
+        except ResourceInvalidError as e:
             raise OSError(errno.EINVAL,str(e))
-        except PermissionDeniedError, e:
+        except PermissionDeniedError as e:
             raise OSError(errno.EACCES,str(e))
-        except ResourceLockedError, e:
+        except ResourceLockedError as e:
             if sys.platform == "win32":
                 raise WindowsError(32,str(e))
             else:
                 raise OSError(errno.EACCES,str(e))
-        except DirectoryNotEmptyError, e:
+        except DirectoryNotEmptyError as e:
             raise OSError(errno.ENOTEMPTY,str(e))
-        except DestinationExistsError, e:
+        except DestinationExistsError as e:
             raise OSError(errno.EEXIST,str(e))
-        except StorageSpaceError, e:
+        except StorageSpaceError as e:
             raise OSError(errno.ENOSPC,str(e))
-        except RemoteConnectionError, e:
+        except RemoteConnectionError as e:
             raise OSError(errno.ENETDOWN,str(e))
-        except UnsupportedError, e:
+        except UnsupportedError as e:
             raise OSError(errno.ENOSYS,str(e))
-        except FSError, e:
+        except FSError as e:
             raise OSError(errno.EFAULT,str(e))
     return wrapper
 
@@ -255,7 +255,7 @@ def convert_os_errors(func):
     def wrapper(self,*args,**kwds):
         try:
             return func(self,*args,**kwds)
-        except (OSError,IOError), e:
+        except (OSError,IOError) as e:
             (exc_type,exc_inst,tb) = sys.exc_info()
             path = getattr(e,"filename",None)
             if path and path[0] == "/" and hasattr(self,"root_path"):
@@ -263,53 +263,53 @@ def convert_os_errors(func):
                 if isprefix(self.root_path,path):
                     path = path[len(self.root_path):]
             if not hasattr(e,"errno") or not e.errno:
-                raise OperationFailedError(opname,details=e),None,tb
+                raise OperationFailedError(opname,details=e).with_traceback(tb)
             if e.errno == errno.ENOENT:
-                raise ResourceNotFoundError(path,opname=opname,details=e),None,tb
+                raise ResourceNotFoundError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.EFAULT:
                 # This can happen when listdir a directory that is deleted by another thread
                 # Best to interpret it as a resource not found
-                raise ResourceNotFoundError(path,opname=opname,details=e),None,tb
+                raise ResourceNotFoundError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.ESRCH:
-                raise ResourceNotFoundError(path,opname=opname,details=e),None,tb
+                raise ResourceNotFoundError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.ENOTEMPTY:
-                raise DirectoryNotEmptyError(path,opname=opname,details=e),None,tb
+                raise DirectoryNotEmptyError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.EEXIST:
-                raise DestinationExistsError(path,opname=opname,details=e),None,tb
+                raise DestinationExistsError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == 183: # some sort of win32 equivalent to EEXIST
-                raise DestinationExistsError(path,opname=opname,details=e),None,tb
+                raise DestinationExistsError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.ENOTDIR:
-                raise ResourceInvalidError(path,opname=opname,details=e),None,tb
+                raise ResourceInvalidError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.EISDIR:
-                raise ResourceInvalidError(path,opname=opname,details=e),None,tb
+                raise ResourceInvalidError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.EINVAL:
-                raise ResourceInvalidError(path,opname=opname,details=e),None,tb
+                raise ResourceInvalidError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.ENOSPC:
-                raise StorageSpaceError(opname,path=path,details=e),None,tb
+                raise StorageSpaceError(opname,path=path,details=e).with_traceback(tb)
             if e.errno == errno.EPERM:
-                raise PermissionDeniedError(opname,path=path,details=e),None,tb
+                raise PermissionDeniedError(opname,path=path,details=e).with_traceback(tb)
             if hasattr(errno,"ENONET") and e.errno == errno.ENONET:
-                raise RemoteConnectionError(opname,path=path,details=e),None,tb
+                raise RemoteConnectionError(opname,path=path,details=e).with_traceback(tb)
             if e.errno == errno.ENETDOWN:
-                raise RemoteConnectionError(opname,path=path,details=e),None,tb
+                raise RemoteConnectionError(opname,path=path,details=e).with_traceback(tb)
             if e.errno == errno.ECONNRESET:
-                raise RemoteConnectionError(opname,path=path,details=e),None,tb
+                raise RemoteConnectionError(opname,path=path,details=e).with_traceback(tb)
             if e.errno == errno.EACCES:
                 if sys.platform == "win32":
                     if e.args[0] and e.args[0] == 32:
-                        raise ResourceLockedError(path,opname=opname,details=e),None,tb
-                raise PermissionDeniedError(opname,details=e),None,tb
+                        raise ResourceLockedError(path,opname=opname,details=e).with_traceback(tb)
+                raise PermissionDeniedError(opname,details=e).with_traceback(tb)
             # Sometimes windows gives some random errors...
             if sys.platform == "win32":
                 if e.errno in (13,):
-                    raise ResourceInvalidError(path,opname=opname,details=e),None,tb
+                    raise ResourceInvalidError(path,opname=opname,details=e).with_traceback(tb)
             if e.errno == errno.ENAMETOOLONG:
-                raise PathError(path,details=e),None,tb
+                raise PathError(path,details=e).with_traceback(tb)
             if e.errno == errno.EOPNOTSUPP:
-                raise UnsupportedError(opname,details=e),None,tb
+                raise UnsupportedError(opname,details=e).with_traceback(tb)
             if e.errno == errno.ENOSYS:
-                raise UnsupportedError(opname,details=e),None,tb
-            raise OperationFailedError(opname,details=e),None,tb
+                raise UnsupportedError(opname,details=e).with_traceback(tb)
+            raise OperationFailedError(opname,details=e).with_traceback(tb)
     return wrapper
 
 
--- fs/expose/dokan/__init__.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/dokan/__init__.py
@@ -54,8 +54,8 @@ systems with Dokan installed.
 #  Copyright (c) 2009-2010, Cloud Matrix Pty. Ltd.
 #  All rights reserved; available under the terms of the MIT License.
 
-from __future__ import with_statement
 
+
 import sys
 
 import os
@@ -64,7 +64,7 @@ import errno
 import time
 import stat as statinfo
 import subprocess
-import cPickle
+import pickle
 import datetime
 import ctypes
 from collections import deque
@@ -76,7 +76,7 @@ from fs.local_functools import wraps
 from fs.wrapfs import WrapFS
 
 try:
-    import libdokan
+    from . import libdokan
 except (NotImplementedError, EnvironmentError, ImportError, NameError,):
     is_available = False
     sys.modules.pop("fs.expose.dokan.libdokan", None)
@@ -171,12 +171,12 @@ def handle_fs_errors(func):
     def wrapper(*args,**kwds):
         try:
             res = func(*args,**kwds)
-        except OSError, e:
+        except OSError as e:
             if e.errno:
                 res = -1 * _errno2syserrcode(e.errno)
             else:
                 res = -1
-        except Exception, e:
+        except Exception as e:
             raise
         else:
             if res is None:
@@ -424,7 +424,7 @@ class FSOperations(object):
         info.contents.Context = 1
         try:
             f = self.fs.open(path, mode)
-            print path, mode, repr(f)
+            print(path, mode, repr(f))
         except ResourceInvalidError:
             info.contents.IsDirectory = True
         except FSError:
@@ -896,10 +896,10 @@ def mount(fs, drive, foreground=False, ready_callback=
     def check_ready(mp=None):
         if ready_callback is not False:
             check_alive(mp)
-            for _ in xrange(100):
+            for _ in range(100):
                 try:
                     os.stat(drive+":\\")
-                except EnvironmentError, e:
+                except EnvironmentError as e:
                     check_alive(mp)
                     time.sleep(0.05)
                 else:
@@ -989,7 +989,7 @@ class MountProcess(subprocess.Popen):
         cmd = cmd + "data = cPickle.loads(%s); "
         cmd = cmd + "from fs.expose.dokan import MountProcess; "
         cmd = cmd + "MountProcess._do_mount(data)"
-        cmd = cmd % (repr(cPickle.dumps((fs,drive,dokan_opts,nowait),-1)),)
+        cmd = cmd % (repr(pickle.dumps((fs,drive,dokan_opts,nowait),-1)),)
         cmd = [sys.executable,"-c",cmd]
         super(MountProcess,self).__init__(cmd,**kwds)
 
--- fs/expose/ftp.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/ftp.py
@@ -28,7 +28,7 @@ from fs.osfs import OSFS
 from fs.errors import convert_fs_errors
 from fs import iotools
 
-from six import text_type as unicode
+from six import text_type as str
 
 
 # Get these once so we can reuse them:
@@ -107,9 +107,9 @@ class FTPFS(ftpserver.AbstractedFS):
     def chdir(self, path):
         # We dont' use the decorator here, we actually decode a version of the
         # path for use with pyfs, but keep the original for use with pyftpdlib.
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             # pyftpdlib 0.7.x
-            unipath = unicode(path, self.encoding)
+            unipath = str(path, self.encoding)
         else:
             # pyftpdlib 1.x
             unipath = path
@@ -134,7 +134,7 @@ class FTPFS(ftpserver.AbstractedFS):
     @convert_fs_errors
     @decode_args
     def listdir(self, path):
-        return map(lambda x: x.encode(self.encoding), self.fs.listdir(path))
+        return [x.encode(self.encoding) for x in self.fs.listdir(path)]
 
     @convert_fs_errors
     @decode_args
@@ -190,7 +190,7 @@ class FTPFS(ftpserver.AbstractedFS):
             kwargs['st_mode'] = info['mode']
         else:
             # Otherwise, build one. Not executable by default.
-            mode = 0660
+            mode = 0o660
             # Merge in the type (dir or file). File is tested first, some file systems
             # such as ArchiveMountFS treat archive files as directories too. By checking
             # file first, any such files will be only files (not directories).
@@ -198,7 +198,7 @@ class FTPFS(ftpserver.AbstractedFS):
                 mode |= stat.S_IFREG
             elif self.fs.isdir(path):
                 mode |= stat.S_IFDIR
-                mode |= 0110  # Merge in exec bit to signal dir is listable
+                mode |= 0o110  # Merge in exec bit to signal dir is listable
             kwargs['st_mode'] = mode
         return FakeStat(**kwargs)
 
--- fs/expose/fuse/__init__.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/fuse/__init__.py
@@ -56,7 +56,7 @@ import errno
 import time
 import stat as statinfo
 import subprocess
-import cPickle
+import pickle
 
 import logging
 logger = logging.getLogger("fs.expose.fuse")
@@ -404,9 +404,9 @@ class FSOperations(Operations):
         #  The interesting stuff
         if 'st_mode' not in info:
             if self.fs.isdir(path):
-                info['st_mode'] = 0755
+                info['st_mode'] = 0o755
             else:
-                info['st_mode'] = 0666
+                info['st_mode'] = 0o666
         mode = info['st_mode']
         if not statinfo.S_ISDIR(mode) and not statinfo.S_ISREG(mode):
             if self.fs.isdir(path):
@@ -432,7 +432,7 @@ class FSOperations(Operations):
         except KeyError:
             pass
         else:
-            info["st_size"] = max(written_sizes.values() + [info["st_size"]])
+            info["st_size"] = max(list(written_sizes.values()) + [info["st_size"]])
         return info
 
 
@@ -491,7 +491,7 @@ def unmount(path):
     else:
         args = ["fusermount", "-u", path]
 
-    for num_tries in xrange(3):
+    for num_tries in range(3):
         p = subprocess.Popen(args,
                              stderr=subprocess.PIPE,
                              stdout=subprocess.PIPE)
@@ -554,7 +554,7 @@ class MountProcess(subprocess.Popen):
             cmd = cmd + 'data = loads(%s); '
             cmd = cmd + 'from fs.expose.fuse import MountProcess; '
             cmd = cmd + 'MountProcess._do_mount_nowait(data)'
-            cmd = cmd % (repr(cPickle.dumps((fs, path, fuse_opts), -1)),)
+            cmd = cmd % (repr(pickle.dumps((fs, path, fuse_opts), -1)),)
             cmd = [sys.executable, "-c", cmd]
             super(MountProcess, self).__init__(cmd, **kwds)
         else:
@@ -567,7 +567,7 @@ class MountProcess(subprocess.Popen):
             cmd = cmd + 'data = loads(%s); '
             cmd = cmd + 'from fs.expose.fuse import MountProcess; '
             cmd = cmd + 'MountProcess._do_mount_wait(data)'
-            cmd = cmd % (repr(cPickle.dumps((fs, path, fuse_opts, r, w), -1)),)
+            cmd = cmd % (repr(pickle.dumps((fs, path, fuse_opts, r, w), -1)),)
             cmd = [sys.executable, "-c", cmd]
             super(MountProcess, self).__init__(cmd, **kwds)
             os.close(w)
@@ -635,8 +635,8 @@ class MountProcess(subprocess.Popen):
         opts["unmount_callback"] = unmount_callback
         try:
             mount(fs, path, **opts)
-        except Exception, e:
-            os.write(w, b("E") + unicode(e).encode('ascii', errors='replace'))
+        except Exception as e:
+            os.write(w, b("E") + str(e).encode('ascii', errors='replace'))
             os.close(w)
 
         if not successful:
@@ -653,5 +653,5 @@ if __name__ == "__main__":
         os.makedirs(mount_point)
 
     def ready_callback():
-        print "READY"
+        print("READY")
     mount(TempFS(), mount_point, foreground=True, ready_callback=ready_callback)
--- fs/expose/fuse/fuse_ctypes.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/fuse/fuse_ctypes.py
@@ -12,8 +12,8 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-from __future__ import division
 
+
 from ctypes import *
 from ctypes.util import find_library
 from errno import *
@@ -273,7 +273,7 @@ def time_of_timespec(ts):
     return ts.tv_sec + ts.tv_nsec / 10 ** 9
 
 def set_st_attrs(st, attrs):
-    for key, val in attrs.items():
+    for key, val in list(attrs.items()):
         if key in ('st_atime', 'st_mtime', 'st_ctime'):
             timespec = getattr(st, key + 'spec')
             timespec.tv_sec = int(val)
@@ -314,7 +314,7 @@ class FUSE(object):
         kwargs.setdefault('fsname', operations.__class__.__name__)
         args.append('-o')
         args.append(','.join(key if val == True else '%s=%s' % (key, val)
-            for key, val in kwargs.items()))
+            for key, val in list(kwargs.items())))
         args.append(mountpoint)
         argv = (c_char_p * len(args))(*args)
         
@@ -331,7 +331,7 @@ class FUSE(object):
         """Decorator for the methods that follow"""
         try:
             return func(*args, **kwargs) or 0
-        except OSError, e:
+        except OSError as e:
             return -(e.errno or EFAULT)
         except:
             print_exc()
@@ -400,7 +400,7 @@ class FUSE(object):
     def statfs(self, path, buf):
         stv = buf.contents
         attrs = self.operations('statfs', path)
-        for key, val in attrs.items():
+        for key, val in list(attrs.items()):
             if hasattr(stv, key):
                 setattr(stv, key, val)
         return 0
@@ -576,7 +576,7 @@ class Operations(object):
         
         if path != '/':
             raise OSError(ENOENT, '')
-        return dict(st_mode=(S_IFDIR | 0755), st_nlink=2)
+        return dict(st_mode=(S_IFDIR | 0o755), st_nlink=2)
     
     def getxattr(self, path, name, position=0):
         raise OSError(ENOTSUP, '')
@@ -667,13 +667,13 @@ class Operations(object):
 
 class LoggingMixIn:
     def __call__(self, op, path, *args):
-        print '->', op, path, repr(args)
+        print('->', op, path, repr(args))
         ret = '[Unknown Error]'
         try:
             ret = getattr(self, op)(path, *args)
             return ret
-        except OSError, e:
+        except OSError as e:
             ret = str(e)
             raise
         finally:
-            print '<-', op, repr(ret)
+            print('<-', op, repr(ret))
--- fs/expose/fuse/fuse.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/fuse/fuse.py
@@ -12,8 +12,8 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-from __future__ import division
 
+
 from ctypes import *
 from ctypes.util import find_library
 from errno import *
@@ -269,7 +269,7 @@ def time_of_timespec(ts):
     return ts.tv_sec + ts.tv_nsec / 10 ** 9
 
 def set_st_attrs(st, attrs):
-    for key, val in attrs.items():
+    for key, val in list(attrs.items()):
         if key in ('st_atime', 'st_mtime', 'st_ctime'):
             timespec = getattr(st, key + 'spec')
             timespec.tv_sec = int(val)
@@ -312,7 +312,7 @@ class FUSE(object):
         kwargs.setdefault('fsname', operations.__class__.__name__)
         args.append('-o')
         args.append(','.join(key if val == True else '%s=%s' % (key, val)
-            for key, val in kwargs.items()))
+            for key, val in list(kwargs.items())))
         args.append(mountpoint)
         argv = (c_char_p * len(args))(*args)
         
@@ -331,7 +331,7 @@ class FUSE(object):
         """Decorator for the methods that follow"""
         try:
             return func(*args, **kwargs) or 0
-        except OSError, e:
+        except OSError as e:
             return -(e.errno or EFAULT)
         except:
             print_exc()
@@ -406,7 +406,7 @@ class FUSE(object):
     def statfs(self, path, buf):
         stv = buf.contents
         attrs = self.operations('statfs', path)
-        for key, val in attrs.items():
+        for key, val in list(attrs.items()):
             if hasattr(stv, key):
                 setattr(stv, key, val)
         return 0
@@ -579,7 +579,7 @@ class Operations(object):
         
         if path != '/':
             raise FuseOSError(ENOENT)
-        return dict(st_mode=(S_IFDIR | 0755), st_nlink=2)
+        return dict(st_mode=(S_IFDIR | 0o755), st_nlink=2)
     
     def getxattr(self, path, name, position=0):
         raise FuseOSError(ENOTSUP)
@@ -670,13 +670,13 @@ class Operations(object):
 
 class LoggingMixIn:
     def __call__(self, op, path, *args):
-        print '->', op, path, repr(args)
+        print('->', op, path, repr(args))
         ret = '[Unhandled Exception]'
         try:
             ret = getattr(self, op)(path, *args)
             return ret
-        except OSError, e:
+        except OSError as e:
             ret = str(e)
             raise
         finally:
-            print '<-', op, repr(ret)
+            print('<-', op, repr(ret))
--- fs/expose/fuse/fuse3.py.orig	2022-03-04 17:14:43 UTC
+++ fs/expose/fuse/fuse3.py
@@ -229,7 +229,7 @@ def time_of_timespec(ts):
     return ts.tv_sec + ts.tv_nsec / 10 ** 9
 
 def set_st_attrs(st, attrs):
-    for key, val in attrs.items():
+    for key, val in list(attrs.items()):
         if key in ('st_atime', 'st_mtime', 'st_ctime'):
             timespec = getattr(st, key + 'spec')
             timespec.tv_sec = int(val)
@@ -274,7 +274,7 @@ class FUSE(object):
         kwargs.setdefault('fsname', operations.__class__.__name__)
         args.append('-o')
         args.append(','.join(key if val == True else '%s=%s' % (key, val)
-            for key, val in kwargs.items()))
+            for key, val in list(kwargs.items())))
         args.append(mountpoint)
         argv = (c_char_p * len(args))(*args)
 
@@ -361,7 +361,7 @@ class FUSE(object):
     def statfs(self, path, buf):
         stv = buf.contents
         attrs = self.operations('statfs', path)
-        for key, val in attrs.items():
+        for key, val in list(attrs.items()):
             if hasattr(stv, key):
                 setattr(stv, key, val)
         return 0
--- fs/expose/http.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/http.py
@@ -1,13 +1,13 @@
 __all__ = ["serve_fs"]
 
-import SimpleHTTPServer
-import SocketServer
+import http.server
+import socketserver
 from fs.path import pathjoin, dirname
 from fs.errors import FSError
 from time import mktime
-from cStringIO import StringIO
+from io import StringIO
 import cgi
-import urllib
+import urllib.request, urllib.parse, urllib.error
 import posixpath
 import time
 import threading
@@ -16,13 +16,13 @@ import socket
 def _datetime_to_epoch(d):
     return mktime(d.timetuple())
 
-class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+class FSHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
 
     """A hacked together version of SimpleHTTPRequestHandler"""
 
     def __init__(self, fs, request, client_address, server):
         self._fs = fs
-        SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
+        http.server.SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
 
     def do_GET(self):
         """Serve a GET request."""
@@ -69,7 +69,7 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTP
         try:
             info = self._fs.getinfo(path)
             f = self._fs.open(path, 'rb')
-        except FSError, e:
+        except FSError as e:
             self.send_error(404, str(e))
             return None
         self.send_response(200)
@@ -98,7 +98,7 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTP
         paths = [p+'/' for p in sorted(dir_paths, key=lambda p:p.lower())] + sorted(file_paths, key=lambda p:p.lower())
         #list.sort(key=lambda a: a.lower())
         f = StringIO()
-        displaypath = cgi.escape(urllib.unquote(self.path))
+        displaypath = cgi.escape(urllib.parse.unquote(self.path))
         f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
         f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
         f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
@@ -106,11 +106,11 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTP
 
         parent = dirname(path)
         if path != parent:
-            f.write('<li><a href="%s">../</a></li>' % urllib.quote(parent.rstrip('/') + '/'))
+            f.write('<li><a href="%s">../</a></li>' % urllib.parse.quote(parent.rstrip('/') + '/'))
 
         for path in paths:
             f.write('<li><a href="%s">%s</a>\n'
-                    % (urllib.quote(path), cgi.escape(path)))
+                    % (urllib.parse.quote(path), cgi.escape(path)))
         f.write("</ul>\n<hr>\n</body>\n</html>\n")
         length = f.tell()
         f.seek(0)
@@ -124,7 +124,7 @@ class FSHTTPRequestHandler(SimpleHTTPServer.SimpleHTTP
         # abandon query parameters
         path = path.split('?',1)[0]
         path = path.split('#',1)[0]
-        path = posixpath.normpath(urllib.unquote(path))
+        path = posixpath.normpath(urllib.parse.unquote(path))
         return path
 
 
@@ -143,7 +143,7 @@ def serve_fs(fs, address='', port=8000):
 
     #class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
     #    pass
-    httpd = SocketServer.TCPServer((address, port), Handler, bind_and_activate=False)
+    httpd = socketserver.TCPServer((address, port), Handler, bind_and_activate=False)
     #httpd = ThreadedTCPServer((address, port), Handler, bind_and_activate=False)
     httpd.allow_reuse_address = True
     httpd.server_bind()
--- fs/expose/importhook.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/importhook.py
@@ -60,7 +60,7 @@ class FSImportHook(object):
     def __init__(self,fs_or_url):
         #  If given a string, try to open it as an FS url.
         #  Don't open things on the local filesystem though.
-        if isinstance(fs_or_url,basestring):
+        if isinstance(fs_or_url,str):
             if ":/" not in fs_or_url:
                 raise ImportError
             try:
@@ -182,7 +182,7 @@ class FSImportHook(object):
         mod.__loader__ = self
         sys.modules[fullname] = mod
         try:
-            exec code in mod.__dict__
+            exec(code, mod.__dict__)
             mod.__file__ = self.get_filename(fullname,info)
             if self.is_package(fullname,info):
                 if self.path is None:
@@ -231,7 +231,7 @@ class FSImportHook(object):
         """Read the specified data file."""
         try:
             return self.fs.getcontents(path, 'rb')
-        except FSError, e:
+        except FSError as e:
             raise IOError(str(e))
 
     def get_filename(self,fullname,info=None):
--- fs/expose/sftp.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/sftp.py
@@ -24,12 +24,12 @@ is, you probably don't want to use it.
 
 """
 
-from __future__ import with_statement
 
+
 import os
 import stat as statinfo
 import time
-import SocketServer
+import socketserver
 import threading
 
 import paramiko
@@ -73,11 +73,11 @@ def report_sftp_errors(func):
     def wrapper(*args,**kwds):
         try:
             return func(*args, **kwds)
-        except ResourceNotFoundError, e:
+        except ResourceNotFoundError as e:
             return paramiko.SFTP_NO_SUCH_FILE
-        except UnsupportedError, e:
+        except UnsupportedError as e:
             return paramiko.SFTP_OP_UNSUPPORTED
-        except FSError, e:
+        except FSError as e:
             return paramiko.SFTP_FAILURE
     return wrapper
 
@@ -114,7 +114,7 @@ class SFTPServerInterface(paramiko.SFTPServerInterface
 
     @report_sftp_errors
     def list_folder(self, path):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
         stats = []
         for entry in self.fs.listdir(path, absolute=True):
@@ -125,7 +125,7 @@ class SFTPServerInterface(paramiko.SFTPServerInterface
 
     @report_sftp_errors
     def stat(self, path):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
 
         info = self.fs.getinfo(path)
@@ -146,9 +146,9 @@ class SFTPServerInterface(paramiko.SFTPServerInterface
                 stat.st_mtime = time.mktime(info.get("modified_time").timetuple())
 
         if isdir(self.fs, path, info):
-            stat.st_mode = 0777 | statinfo.S_IFDIR
+            stat.st_mode = 0o777 | statinfo.S_IFDIR
         else:
-            stat.st_mode = 0777 | statinfo.S_IFREG
+            stat.st_mode = 0o777 | statinfo.S_IFREG
         return stat
 
     def lstat(self, path):
@@ -156,16 +156,16 @@ class SFTPServerInterface(paramiko.SFTPServerInterface
 
     @report_sftp_errors
     def remove(self, path):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
         self.fs.remove(path)
         return paramiko.SFTP_OK
 
     @report_sftp_errors
     def rename(self, oldpath, newpath):
-        if not isinstance(oldpath, unicode):
+        if not isinstance(oldpath, str):
             oldpath = oldpath.decode(self.encoding)
-        if not isinstance(newpath, unicode):
+        if not isinstance(newpath, str):
             newpath = newpath.decode(self.encoding)
         if self.fs.isfile(oldpath):
             self.fs.move(oldpath, newpath)
@@ -175,14 +175,14 @@ class SFTPServerInterface(paramiko.SFTPServerInterface
 
     @report_sftp_errors
     def mkdir(self, path, attr):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
         self.fs.makedir(path)
         return paramiko.SFTP_OK
 
     @report_sftp_errors
     def rmdir(self, path):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
         self.fs.removedir(path)
         return paramiko.SFTP_OK
@@ -224,7 +224,7 @@ class SFTPHandle(paramiko.SFTPHandle):
         super(SFTPHandle, self).__init__(flags)
         mode = flags_to_mode(flags)
         self.owner = owner
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.owner.encoding)
         self.path = path
         self._file = owner.fs.open(path, mode)
@@ -263,7 +263,7 @@ class SFTPServer(paramiko.SFTPServer):
         super(SFTPServer, self).finish_subsystem()
 
 
-class SFTPRequestHandler(SocketServer.BaseRequestHandler):
+class SFTPRequestHandler(socketserver.BaseRequestHandler):
     """SocketServer RequestHandler subclass for BaseSFTPServer.
 
     This RequestHandler subclass creates a paramiko Transport, sets up the
@@ -305,7 +305,7 @@ class SFTPRequestHandler(SocketServer.BaseRequestHandl
 
 
 
-class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
+class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
     pass
 
 
@@ -334,7 +334,7 @@ class BaseSFTPServer(ThreadedTCPServer):
         self.host_key = host_key
         if RequestHandlerClass is None:
             RequestHandlerClass = SFTPRequestHandler
-        SocketServer.TCPServer.__init__(self, address, RequestHandlerClass)
+        socketserver.TCPServer.__init__(self, address, RequestHandlerClass)
 
     def shutdown_request(self, request):
         # Prevent TCPServer from closing the connection prematurely
--- fs/expose/wsgi/__init__.py.orig	2022-03-04 17:14:43 UTC
+++ fs/expose/wsgi/__init__.py
@@ -1 +1 @@
-from wsgi import serve_fs
+from .wsgi import serve_fs
--- fs/expose/wsgi/serve_home.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/wsgi/serve_home.py
@@ -1,10 +1,10 @@
 from wsgiref.simple_server import make_server
 
 from fs.osfs import OSFS
-from wsgi import serve_fs
+from .wsgi import serve_fs
 osfs = OSFS('~/')
 application = serve_fs(osfs)
 
 httpd = make_server('', 8000, application)
-print "Serving on http://127.0.0.1:8000"
+print("Serving on http://127.0.0.1:8000")
 httpd.serve_forever()
--- fs/expose/wsgi/wsgi.py.orig	2015-04-12 17:24:29 UTC
+++ fs/expose/wsgi/wsgi.py
@@ -1,5 +1,5 @@
 
-import urlparse
+import urllib.parse
 import mimetypes
 
 from fs.errors import FSError
@@ -10,7 +10,7 @@ from datetime import datetime
 try:
     from mako.template import Template
 except ImportError:
-    print "Requires mako templates http://www.makotemplates.org/"
+    print("Requires mako templates http://www.makotemplates.org/")
     raise
 
 
@@ -28,7 +28,7 @@ class WSGIServer(object):
     def __init__(self, serve_fs, indexes=True, dir_template=None, chunk_size=16*1024*1024):
 
         if dir_template is None:
-            from dirtemplate import template as dir_template
+            from .dirtemplate import template as dir_template
 
         self.serve_fs = serve_fs
         self.indexes = indexes
@@ -57,7 +57,7 @@ class WSGIServer(object):
         serving_file = None
         try:
             serving_file = self.serve_fs.open(path, 'rb')
-        except Exception, e:
+        except Exception as e:
             if serving_file is not None:
                 serving_file.close()
             return self.serve_500(request, str(e))
--- fs/expose/xmlrpc.py.orig	2022-03-04 17:14:43 UTC
+++ fs/expose/xmlrpc.py
@@ -15,8 +15,8 @@ an FS object, which can then be exposed using whatever
 
 """
 
-import xmlrpclib
-from SimpleXMLRPCServer import SimpleXMLRPCServer
+import xmlrpc.client
+from xmlrpc.server import SimpleXMLRPCServer
 from datetime import datetime
 import base64
 
@@ -61,13 +61,13 @@ class RPCFSInterface(object):
 
     def getmeta(self, meta_name):
         meta = self.fs.getmeta(meta_name)
-        if isinstance(meta, basestring):
+        if isinstance(meta, str):
             meta = self.decode_path(meta)
         return meta
 
     def getmeta_default(self, meta_name, default):
         meta = self.fs.getmeta(meta_name, default)
-        if isinstance(meta, basestring):
+        if isinstance(meta, str):
             meta = self.decode_path(meta)
         return meta
 
@@ -77,7 +77,7 @@ class RPCFSInterface(object):
     def get_contents(self, path, mode="rb"):
         path = self.decode_path(path)
         data = self.fs.getcontents(path, mode)
-        return xmlrpclib.Binary(data)
+        return xmlrpc.client.Binary(data)
 
     def set_contents(self, path, data):
         path = self.decode_path(path)
@@ -119,16 +119,16 @@ class RPCFSInterface(object):
 
     def settimes(self, path, accessed_time, modified_time):
         path = self.decode_path(path)
-        if isinstance(accessed_time, xmlrpclib.DateTime):
+        if isinstance(accessed_time, xmlrpc.client.DateTime):
             accessed_time = datetime.strptime(accessed_time.value, "%Y%m%dT%H:%M:%S")
-        if isinstance(modified_time, xmlrpclib.DateTime):
+        if isinstance(modified_time, xmlrpc.client.DateTime):
             modified_time = datetime.strptime(modified_time.value, "%Y%m%dT%H:%M:%S")
         return self.fs.settimes(path, accessed_time, modified_time)
 
     def getinfo(self, path):
         path = self.decode_path(path)
         info = self.fs.getinfo(path)
-        info = dict((k, v) for k, v in info.iteritems()
+        info = dict((k, v) for k, v in info.items()
                     if k in self._allowed_info)
         return info
 
--- fs/filelike.py.orig	2022-03-04 17:14:43 UTC
+++ fs/filelike.py
@@ -52,9 +52,9 @@ if PY3:
     from six import BytesIO as _StringIO
 else:
     try:
-        from cStringIO import StringIO as _StringIO
+        from io import StringIO as _StringIO
     except ImportError:
-        from StringIO import StringIO as _StringIO
+        from io import StringIO as _StringIO
 
 
 class FileLikeBase(object):
@@ -305,7 +305,7 @@ class FileLikeBase(object):
         self.close()
         return False
 
-    def next(self):
+    def __next__(self):
         """next() method complying with the iterator protocol.
 
         File-like objects are their own iterators, with each call to
--- fs/ftpfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/ftpfs.py
@@ -37,9 +37,9 @@ if PY3:
     from six import BytesIO as StringIO
 else:
     try:
-        from cStringIO import StringIO
+        from io import StringIO
     except ImportError:
-        from StringIO import StringIO
+        from io import StringIO
 
 import time
 
@@ -221,10 +221,10 @@ class FTPListDataParser(object):
                 elif c == 'r':
                     result.try_retr = True
                 elif c == 's':
-                    result.size = long(buf[i+1:j])
+                    result.size = int(buf[i+1:j])
                 elif c == 'm':
                     result.mtime_type = MTIME_TYPE.LOCAL
-                    result.mtime = long(buf[i+1:j])
+                    result.mtime = int(buf[i+1:j])
                 elif c == 'i':
                     result.id_type = ID_TYPE.FULL
                     result.id = buf[i+1:j-i-1]
@@ -285,7 +285,7 @@ class FTPListDataParser(object):
 
                 elif state == 4: # getting tentative size
                     try:
-                        size = long(buf[i:j])
+                        size = int(buf[i:j])
                     except ValueError:
                         pass
                     state = 5
@@ -295,25 +295,25 @@ class FTPListDataParser(object):
                     if month >= 0:
                         state = 6
                     else:
-                        size = long(buf[i:j])
+                        size = int(buf[i:j])
 
                 elif state == 6: # have size and month
-                    mday = long(buf[i:j])
+                    mday = int(buf[i:j])
                     state = 7
 
                 elif state == 7: # have size, month, mday
                     if (j - i == 4) and (buf[i+1] == ':'):
-                        hour = long(buf[i])
-                        minute = long(buf[i+2:i+4])
+                        hour = int(buf[i])
+                        minute = int(buf[i+2:i+4])
                         result.mtime_type = MTIME_TYPE.REMOTE_MINUTE
                         result.mtime = self._guess_time(month, mday, hour, minute)
                     elif (j - i == 5) and (buf[i+2] == ':'):
-                        hour = long(buf[i:i+2])
-                        minute = long(buf[i+3:i+5])
+                        hour = int(buf[i:i+2])
+                        minute = int(buf[i+3:i+5])
                         result.mtime_type = MTIME_TYPE.REMOTE_MINUTE
                         result.mtime = self._guess_time(month, mday, hour, minute)
                     elif j - i >= 4:
-                        year = long(buf[i:j])
+                        year = int(buf[i:j])
                         result.mtime_type = MTIME_TYPE.REMOTE_DAY
                         result.mtime = self._get_mtime(year, month, mday)
                     else:
@@ -379,7 +379,7 @@ class FTPListDataParser(object):
             j = i
 
             j = buf.index('-', j)
-            mday = long(buf[i:j])
+            mday = int(buf[i:j])
 
             j = _skip(buf, j, '-')
             i = j
@@ -391,13 +391,13 @@ class FTPListDataParser(object):
             j = _skip(buf, j, '-')
             i = j
             j = buf.index(' ', j)
-            year = long(buf[i:j])
+            year = int(buf[i:j])
 
             j = _skip(buf, j, ' ')
             i = j
 
             j = buf.index(':', j)
-            hour = long(buf[i:j])
+            hour = int(buf[i:j])
             j = _skip(buf, j, ':')
             i = j
 
@@ -406,7 +406,7 @@ class FTPListDataParser(object):
                 if j == buflen:
                     raise IndexError # abort, abort!
 
-            minute = long(buf[i:j])
+            minute = int(buf[i:j])
 
             result.mtime_type = MTIME_TYPE.REMOTE_MINUTE
             result.mtime = self._get_mtime(year, month, mday, hour, minute)
@@ -430,17 +430,17 @@ class FTPListDataParser(object):
             result = FTPListData(buf)
 
             j = buf.index('-', j)
-            month = long(buf[i:j])
+            month = int(buf[i:j])
 
             j = _skip(buf, j, '-')
             i = j
             j = buf.index('-', j)
-            mday = long(buf[i:j])
+            mday = int(buf[i:j])
 
             j = _skip(buf, j, '-')
             i = j
             j = buf.index(' ', j)
-            year = long(buf[i:j])
+            year = int(buf[i:j])
             if year < 50:
                 year += 2000
             if year < 1000:
@@ -449,14 +449,14 @@ class FTPListDataParser(object):
             j = _skip(buf, j, ' ')
             i = j
             j = buf.index(':', j)
-            hour = long(buf[i:j])
+            hour = int(buf[i:j])
             j = _skip(buf, j, ':')
             i = j
             while not (buf[j] in 'AP'):
                 j += 1
                 if j == buflen:
                     raise IndexError
-            minute = long(buf[i:j])
+            minute = int(buf[i:j])
 
             if buf[j] == 'A':
                 j += 1
@@ -482,7 +482,7 @@ class FTPListDataParser(object):
                 i = j
                 j = buf.index(' ', j)
 
-                result.size = long(buf[i:j])
+                result.size = int(buf[i:j])
                 result.try_retr = True
 
             j = _skip(buf, j, ' ')
@@ -546,10 +546,10 @@ class FTPMlstDataParser(object):
                                                      int(factvalue[12:14]),
                                                      0, 0, 0))
                 elif factname == 'size':
-                    result.size = long(factvalue)
+                    result.size = int(factvalue)
                 elif factname == 'sizd':
                     # some FTP servers report directory size with sizd
-                    result.size = long(factvalue)
+                    result.size = int(factvalue)
                 elif factname == 'type':
                     if factvalue.lower() == 'file':
                         result.try_retr = True
@@ -605,7 +605,7 @@ def fileftperrors(f):
         try:
             try:
                 ret = f(self, *args, **kwargs)
-            except Exception, e:
+            except Exception as e:
                 self.ftpfs._translate_exception(args[0] if args else '', e)
         finally:
             self._lock.release()
@@ -795,16 +795,16 @@ class _FTPFile(object):
                 self.conn.close()
                 self.conn = None
                 self.ftp.voidresp()
-            except error_temp, error_perm:
+            except error_temp as error_perm:
                 pass
         if self.ftp is not None:
             try:
                 self.ftp.close()
-            except error_temp, error_perm:
+            except error_temp as error_perm:
                 pass
         self.closed = True
 
-    def next(self):
+    def __next__(self):
         return self.readline()
 
     def readline(self, size=None):
@@ -823,7 +823,7 @@ def ftperrors(f):
             try:
                 try:
                     ret = f(self, *args, **kwargs)
-                except Exception, e:
+                except Exception as e:
                     self._translate_exception(args[0] if args else '', e)
             finally:
                 self._leave_dircache()
@@ -834,7 +834,7 @@ def ftperrors(f):
 
 
 def _encode(s):
-    if isinstance(s, unicode):
+    if isinstance(s, str):
         return s.encode('utf-8')
     return s
 
@@ -956,7 +956,7 @@ class FTPFS(FS):
             return features
 
         def on_line(line):
-            if not isinstance(line, unicode):
+            if not isinstance(line, str):
                 line = line.decode('utf-8')
             info = parse_ftp_list_line(line, self.use_mlst)
             if info:
@@ -986,7 +986,7 @@ class FTPFS(FS):
                     else: # Matrix FTP server has bug
                         on_line(list_line)
                 # if it's a dir, then we can send a MLSD
-                if dirlist[dirlist.keys()[0]]['try_cwd']:
+                if dirlist[list(dirlist.keys())[0]]['try_cwd']:
                     dirlist = {}
                     self.ftp.retrlines("MLSD " + encoded_path, on_line)
             else:
@@ -996,11 +996,11 @@ class FTPFS(FS):
         self.dircache[path] = dirlist
 
         def is_symlink(info):
-            return info['try_retr'] and info['try_cwd'] and info.has_key('target')
+            return info['try_retr'] and info['try_cwd'] and 'target' in info
 
         def resolve_symlink(linkpath):
             linkinfo = self.getinfo(linkpath)
-            if not linkinfo.has_key('resolved'):
+            if 'resolved' not in linkinfo:
                 linkinfo['resolved'] = linkpath
             if is_symlink(linkinfo):
                 target = linkinfo['target']
@@ -1036,7 +1036,7 @@ class FTPFS(FS):
         else:
             dircache = self.dircache
             paths = [normpath(abspath(path)) for path in paths]
-            for cached_path in dircache.keys():
+            for cached_path in list(dircache.keys()):
                 for path in paths:
                     if isbase(cached_path, path):
                         dircache.pop(cached_path, None)
@@ -1083,7 +1083,7 @@ class FTPFS(FS):
             else:
                 ftp.connect(self.host, self.port, self.timeout)
             ftp.login(self.user, self.passwd, self.acct)
-        except socket_error, e:
+        except socket_error as e:
             raise RemoteConnectionError(str(e), details=e)
         return ftp
 
@@ -1104,7 +1104,7 @@ class FTPFS(FS):
         return '<FTPFS %s>' % self.host
 
     def __unicode__(self):
-        return u'<FTPFS %s>' % self.host
+        return '<FTPFS %s>' % self.host
 
     @convert_os_errors
     def _translate_exception(self, path, exception):
@@ -1225,7 +1225,7 @@ class FTPFS(FS):
             raise ResourceNotFoundError(path)
         if not self.isdir(path):
             raise ResourceInvalidError(path)
-        paths = self._readdir(path).keys()
+        paths = list(self._readdir(path).keys())
 
         return self._listdir_helper(path, paths, wildcard, full, absolute, dirs_only, files_only)
 
@@ -1266,7 +1266,7 @@ class FTPFS(FS):
                     self.ftp.mkd(_encode(path))
                 except error_reply:
                     return
-                except error_perm, e:
+                except error_perm as e:
                     if recursive or allow_recreate:
                         return
                     if str(e).split(' ', 1)[0]=='550':
@@ -1337,7 +1337,7 @@ class FTPFS(FS):
         try:
             self.refresh_dircache(dirname(src), dirname(dst))
             self.ftp.rename(_encode(src), _encode(dst))
-        except error_perm, exception:
+        except error_perm as exception:
             code, message = str(exception).split(' ', 1)
             if code == "550":
                 if not self.exists(dirname(dst)):
--- fs/httpfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/httpfs.py
@@ -10,8 +10,8 @@ from fs.path import normpath
 from fs.errors import ResourceNotFoundError, UnsupportedError
 from fs.filelike import FileWrapper
 from fs import iotools
-
-from urllib2 import urlopen, URLError
+from urllib.request import urlopen
+from urllib.error import URLError
 from datetime import datetime
 
 
@@ -50,9 +50,9 @@ class HTTPFS(FS):
         url = self._make_url(path)
         try:
             f = urlopen(url)
-        except URLError, e:
+        except URLError as e:
             raise ResourceNotFoundError(path, details=e)
-        except OSError, e:
+        except OSError as e:
             raise ResourceNotFoundError(path, details=e)
 
         return FileWrapper(f)
--- fs/iotools.py.orig	2022-03-04 17:14:43 UTC
+++ fs/iotools.py
@@ -1,6 +1,6 @@
-from __future__ import unicode_literals
-from __future__ import print_function
 
+
+
 from fs import SEEK_SET, SEEK_CUR, SEEK_END
 
 import io
@@ -178,7 +178,7 @@ def make_bytes_io(data, encoding=None, errors=None):
     if hasattr(data, 'mode') and 'b' in data.mode:
         # It's already a binary file
         return data
-    if not isinstance(data, basestring):
+    if not isinstance(data, str):
         # It's a file, but we don't know if its binary
         # TODO: Is there a better way than reading the entire file?
         data = data.read() or b''
--- fs/memoryfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/memoryfs.py
@@ -78,10 +78,10 @@ class MemoryFile(object):
         return "<MemoryFile in %s %s>" % (self.memory_fs, self.path)
 
     def __repr__(self):
-        return u"<MemoryFile in %s %s>" % (self.memory_fs, self.path)
+        return "<MemoryFile in %s %s>" % (self.memory_fs, self.path)
 
     def __unicode__(self):
-        return u"<MemoryFile in %s %s>" % (self.memory_fs, self.path)
+        return "<MemoryFile in %s %s>" % (self.memory_fs, self.path)
 
     def __del__(self):
         if not self.closed:
@@ -101,7 +101,7 @@ class MemoryFile(object):
     def next(self):
         if 'r' not in self.mode and '+' not in self.mode:
             raise IOError("File not open for reading")
-        return self.mem_file.next()
+        return next(self.mem_file)
 
     @seek_and_lock
     def readline(self, *args, **kwargs):
@@ -218,7 +218,7 @@ class DirEntry(object):
         if self.isfile():
             return "<file %s>" % self.name
         elif self.isdir():
-            return "<dir %s>" % "".join("%s: %s" % (k, v.desc_contents()) for k, v in self.contents.iteritems())
+            return "<dir %s>" % "".join("%s: %s" % (k, v.desc_contents()) for k, v in self.contents.items())
 
     def isdir(self):
         return self.type == "dir"
@@ -559,10 +559,10 @@ class MemoryFS(FS):
             raise ResourceNotFoundError(path)
         if dir_entry.isfile():
             raise ResourceInvalidError(path, msg="not a directory: %(path)s")
-        paths = dir_entry.contents.keys()
+        paths = list(dir_entry.contents.keys())
         for (i,p) in enumerate(paths):
-            if not isinstance(p,unicode):
-                paths[i] = unicode(p)
+            if not isinstance(p,str):
+                paths[i] = str(p)
         return self._listdir_helper(path, paths, wildcard, full, absolute, dirs_only, files_only)
 
     @synchronize
@@ -578,10 +578,10 @@ class MemoryFS(FS):
         info['accessed_time'] = dir_entry.accessed_time
 
         if dir_entry.isdir():
-            info['st_mode'] = 0755 | stat.S_IFDIR
+            info['st_mode'] = 0o755 | stat.S_IFDIR
         else:
             info['size'] = len(dir_entry.data or b(''))
-            info['st_mode'] = 0666 | stat.S_IFREG
+            info['st_mode'] = 0o666 | stat.S_IFREG
 
         return info
 
@@ -671,12 +671,12 @@ class MemoryFS(FS):
     @synchronize
     def setxattr(self, path, key, value):
         dir_entry = self._dir_entry(path)
-        key = unicode(key)
+        key = str(key)
         dir_entry.xattrs[key] = value
 
     @synchronize
     def getxattr(self, path, key, default=None):
-        key = unicode(key)
+        key = str(key)
         dir_entry = self._dir_entry(path)
         return dir_entry.xattrs.get(key, default)
 
@@ -691,4 +691,4 @@ class MemoryFS(FS):
     @synchronize
     def listxattrs(self, path):
         dir_entry = self._dir_entry(path)
-        return dir_entry.xattrs.keys()
+        return list(dir_entry.xattrs.keys())
--- fs/mountfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/mountfs.py
@@ -61,7 +61,7 @@ class DirMount(object):
         return "<DirMount %s, %s>" % (self.path, self.fs)
 
     def __unicode__(self):
-        return u"<DirMount %s, %s>" % (self.path, self.fs)
+        return "<DirMount %s, %s>" % (self.path, self.fs)
 
 
 class FileMount(object):
@@ -90,12 +90,12 @@ class MountFS(FS):
         self.mount_tree = PathMap()
 
     def __str__(self):
-        return "<%s [%s]>" % (self.__class__.__name__,self.mount_tree.items(),)
+        return "<%s [%s]>" % (self.__class__.__name__,list(self.mount_tree.items()),)
 
     __repr__ = __str__
 
     def __unicode__(self):
-        return u"<%s [%s]>" % (self.__class__.__name__,self.mount_tree.items(),)
+        return "<%s [%s]>" % (self.__class__.__name__,list(self.mount_tree.items()),)
 
     def _delegate(self, path):
         path = abspath(normpath(path))
@@ -119,7 +119,7 @@ class MountFS(FS):
             return self, "/", path
 
         try:
-            self.mount_tree.iternames(path).next()
+            next(self.mount_tree.iternames(path))
         except StopIteration:
             return None, None, None
         else:
@@ -129,7 +129,7 @@ class MountFS(FS):
     def close(self):
         # Explicitly closes children if requested
         if self.auto_close:
-            for mount in self.mount_tree.itervalues():
+            for mount in self.mount_tree.values():
                 mount.fs.close()
         # Free references (which may incidently call the close method of the child filesystems)
         self.mount_tree.clear()
--- fs/multifs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/multifs.py
@@ -106,7 +106,7 @@ class MultiFS(FS):
 
     @synchronize
     def __unicode__(self):
-        return u"<MultiFS: %s>" % ", ".join(unicode(fs) for fs in self.fs_sequence)
+        return "<MultiFS: %s>" % ", ".join(str(fs) for fs in self.fs_sequence)
 
     def _get_priority(self, name):
         return self.fs_priorities[name]
@@ -128,7 +128,7 @@ class MultiFS(FS):
 
     def _priority_sort(self):
         """Sort filesystems by priority order"""
-        priority_order = sorted(self.fs_lookup.keys(), key=lambda n: self.fs_priorities[n], reverse=True)
+        priority_order = sorted(list(self.fs_lookup.keys()), key=lambda n: self.fs_priorities[n], reverse=True)
         self.fs_sequence = [self.fs_lookup[name] for name in priority_order]
 
     @synchronize
@@ -214,7 +214,7 @@ class MultiFS(FS):
             return self.writefs
         for fs in self:
             if fs.exists(path):
-                for fs_name, fs_object in self.fs_lookup.iteritems():
+                for fs_name, fs_object in self.fs_lookup.items():
                     if fs is fs_object:
                         return fs_name, fs
         raise ResourceNotFoundError(path, msg="Path does not map to any filesystem: %(path)s")
--- fs/opener.py.orig	2022-03-04 17:14:43 UTC
+++ fs/opener.py
@@ -72,7 +72,7 @@ from fs.filelike import FileWrapper
 from os import getcwd
 import os.path
 import re
-from urlparse import urlparse
+from urllib.parse import urlparse
 
 class OpenerError(Exception):
     """The base exception thrown by openers"""
@@ -794,7 +794,7 @@ example:
     def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir):
 
         from fs.mountfs import MountFS
-        from ConfigParser import ConfigParser
+        from configparser import ConfigParser
         cfg = ConfigParser()
 
         if '#' in fs_path:
@@ -830,7 +830,7 @@ example:
     def get_fs(cls, registry, fs_name, fs_name_params, fs_path, writeable, create_dir):
 
         from fs.multifs import MultiFS
-        from ConfigParser import ConfigParser
+        from configparser import ConfigParser
         cfg = ConfigParser()
 
         if '#' in fs_path:
--- fs/osfs/__init__.py.orig	2015-11-13 22:18:37 UTC
+++ fs/osfs/__init__.py
@@ -48,13 +48,13 @@ def _os_stat(path):
 
 
 @convert_os_errors
-def _os_mkdir(name, mode=0777):
+def _os_mkdir(name, mode=0o777):
     """Replacement for os.mkdir that raises FSError subclasses."""
     return os.mkdir(name, mode)
 
 
 @convert_os_errors
-def _os_makedirs(name, mode=0777):
+def _os_makedirs(name, mode=0o777):
     """Replacement for os.makdirs that raises FSError subclasses.
 
     This implementation also correctly handles win32 long filenames (those
@@ -71,7 +71,7 @@ def _os_makedirs(name, mode=0777):
     if head and tail and not os.path.exists(head):
         try:
             _os_makedirs(head, mode)
-        except OSError, e:
+        except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
         if tail == os.curdir:
@@ -98,11 +98,11 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
              'atomic.setcontents': False}
 
     if platform.system() == 'Windows':
-        _meta["invalid_path_chars"] = ''.join(chr(n) for n in xrange(31)) + '\\:*?"<>|'
+        _meta["invalid_path_chars"] = ''.join(chr(n) for n in range(31)) + '\\:*?"<>|'
     else:
         _meta["invalid_path_chars"] = '\0'
 
-    def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0700, use_long_paths=True):
+    def __init__(self, root_path, thread_synchronize=_thread_synchronize_default, encoding=None, create=False, dir_mode=0o700, use_long_paths=True):
         """
         Creates an FS object that represents the OS Filesystem under a given root path
 
@@ -124,13 +124,13 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
         if sys.platform == "win32":
             if use_long_paths and not root_path.startswith("\\\\?\\"):
                 if not root_path.startswith("\\"):
-                    root_path = u"\\\\?\\" + root_path
+                    root_path = "\\\\?\\" + root_path
                 else:
                     # Explicitly mark UNC paths, seems to work better.
                     if root_path.startswith("\\\\"):
-                        root_path = u"\\\\?\\UNC\\" + root_path[2:]
+                        root_path = "\\\\?\\UNC\\" + root_path[2:]
                     else:
-                        root_path = u"\\\\?" + root_path
+                        root_path = "\\\\?" + root_path
             #  If it points at the root of a drive, it needs a trailing slash.
             if len(root_path) == 6 and not root_path.endswith("\\"):
                 root_path = root_path + "\\"
@@ -155,16 +155,16 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
         return "<OSFS: %r>" % self.root_path
 
     def __unicode__(self):
-        return u"<OSFS: %s>" % self.root_path
+        return "<OSFS: %s>" % self.root_path
 
     def _decode_path(self, p):
-        if isinstance(p, unicode):
+        if isinstance(p, str):
             return p
         return p.decode(self.encoding, 'replace')
 
     def getsyspath(self, path, allow_none=False):
         self.validatepath(path)
-        path = relpath(normpath(path)).replace(u"/", os.sep)
+        path = relpath(normpath(path)).replace("/", os.sep)
         path = os.path.join(self.root_path, path)
         if not path.startswith(self.root_path):
             raise PathError(path, msg="OSFS given path outside root: %(path)s")
@@ -234,7 +234,7 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
             encoding = encoding or 'utf-8'
         try:
             return io.open(sys_path, mode=mode, buffering=buffering, encoding=encoding, errors=errors, newline=newline)
-        except EnvironmentError, e:
+        except EnvironmentError as e:
             #  Win32 gives EACCES when opening a directory.
             if sys.platform == "win32" and e.errno in (errno.EACCES,):
                 if self.isdir(path):
@@ -301,7 +301,7 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
         sys_path = self.getsyspath(path)
         try:
             os.remove(sys_path)
-        except OSError, e:
+        except OSError as e:
             if e.errno == errno.EACCES and sys.platform == "win32":
                 # sometimes windows says this for attempts to remove a dir
                 if os.path.isdir(sys_path):
@@ -338,7 +338,7 @@ class OSFS(OSFSXAttrMixin, OSFSWatchMixin, FS):
         path_dst = self.getsyspath(dst)
         try:
             os.rename(path_src, path_dst)
-        except OSError, e:
+        except OSError as e:
             if e.errno:
                 #  POSIX rename() can rename over an empty directory but gives
                 #  ENOTEMPTY if the dir has contents.  Raise UnsupportedError
--- fs/osfs/watch_inotify.py.orig	2015-04-12 17:24:29 UTC
+++ fs/osfs/watch_inotify.py
@@ -18,7 +18,7 @@ from fs.watch import *
 
 try:
     import pyinotify
-except Exception, e:
+except Exception as e:
     #  pyinotify sometimes raises its own custom errors on import.
     #  How on earth are we supposed to catch them when we can't import them?
     if isinstance(e,ImportError):
@@ -39,7 +39,7 @@ class OSFSWatchMixin(WatchableFSMixin):
     def close(self):
         super(OSFSWatchMixin,self).close()
         self.notify_watchers(CLOSED)
-        for watcher_list in self._watchers.values():
+        for watcher_list in list(self._watchers.values()):
             for watcher in watcher_list:
                 self.del_watcher(watcher)
         self.__watch_lock.acquire()
@@ -58,7 +58,7 @@ class OSFSWatchMixin(WatchableFSMixin):
         w = super_add_watcher(callback,path,events,recursive)
         w._pyinotify_id = None
         syspath = self.getsyspath(path)
-        if isinstance(syspath,unicode):
+        if isinstance(syspath,str):
             syspath = syspath.encode(sys.getfilesystemencoding())
         #  Each watch gets its own WatchManager, since it's tricky to make
         #  a single WatchManager handle multiple callbacks with different
@@ -73,7 +73,7 @@ class OSFSWatchMixin(WatchableFSMixin):
         kwds = dict(rec=recursive,auto_add=recursive,quiet=False)
         try:
             wids = wm.add_watch(syspath,evtmask,process_events,**kwds)
-        except pyinotify.WatchManagerError, e:
+        except pyinotify.WatchManagerError as e:
             raise OperationFailedError("add_watcher",details=e)
         w._pyinotify_id = wids[syspath]
         self.__watch_lock.acquire()
@@ -239,7 +239,7 @@ class SharedThreadedNotifier(threading.Thread):
         while self.running:
             try:
                 ready_fds = self._poller.poll()
-            except _select_error, e:
+            except _select_error as e:
                 if e[0] != errno.EINTR:
                     raise
             else:
--- fs/osfs/watch_win32.py.orig	2015-04-12 17:24:29 UTC
+++ fs/osfs/watch_win32.py
@@ -10,7 +10,7 @@ import os
 import sys
 import errno
 import threading
-import Queue
+import queue
 import stat
 import struct
 import ctypes
@@ -226,7 +226,7 @@ class WatchedDirectory(object):
                                   ctypes.byref(self.result),len(self.result),
                                   self.recursive,self.flags,None,
                                   overlapped,None)
-        except WindowsError, e:
+        except WindowsError as e:
             self.error = e
             self.close()
 
@@ -262,7 +262,7 @@ class WatchThread(threading.Thread):
         self.watched_directories = {}
         self.ready = threading.Event()
         self._iocp = None
-        self._new_watches = Queue.Queue()
+        self._new_watches = queue.Queue()
 
     def close(self):
         if not self.closed:
@@ -383,11 +383,11 @@ class WatchThread(threading.Thread):
                                                            hash(w),0)
                                     w.post()
                                 w.ready.set()
-                        except Queue.Empty:
+                        except queue.Empty:
                             pass
         finally:
             self.ready.set()
-            for w in self.watched_directories.itervalues():
+            for w in self.watched_directories.values():
                 w.close()
             if self._iocp:
                 CloseHandle(self._iocp)
--- fs/osfs/xattrs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/osfs/xattrs.py
@@ -49,7 +49,7 @@ if xattr is not None:
 
         @convert_os_errors
         def listxattrs(self, path):
-            return xattr.xattr(self.getsyspath(path)).keys()
+            return list(xattr.xattr(self.getsyspath(path)).keys())
 
 else:
 
--- fs/path.py.orig	2015-04-12 17:24:29 UTC
+++ fs/path.py
@@ -44,7 +44,7 @@ def normpath(path):
     if not _requires_normalization(path):
         return path.rstrip('/')
 
-    prefix = u'/' if path.startswith('/') else u''
+    prefix = '/' if path.startswith('/') else ''
     components = []
     append = components.append
     special = ('..', '.', '').__contains__
@@ -60,7 +60,7 @@ def normpath(path):
         # causing a circular import.
         from fs.errors import BackReferenceError
         raise BackReferenceError('Too many backrefs in \'%s\'' % path)
-    return prefix + u'/'.join(components)
+    return prefix + '/'.join(components)
 
 
 if os.sep != '/':
@@ -100,11 +100,11 @@ def recursepath(path, reverse=False):
     """
 
     if path in ('', '/'):
-        return [u'/']
+        return ['/']
 
     path = abspath(normpath(path)) + '/'
 
-    paths = [u'/']
+    paths = ['/']
     find = path.find
     append = paths.append
     pos = 1
@@ -133,7 +133,7 @@ def abspath(path):
 
     """
     if not path.startswith('/'):
-        return u'/' + path
+        return '/' + path
     return path
 
 
@@ -176,7 +176,7 @@ def pathjoin(*paths):
                 absolute = True
             relpaths.append(p)
 
-    path = normpath(u"/".join(relpaths))
+    path = normpath("/".join(relpaths))
     if absolute:
         path = abspath(path)
     return path
@@ -419,7 +419,7 @@ def relativefrom(base, path):
             break
         common += 1
 
-    return u'/'.join([u'..'] * (len(base) - common) + path[common:])
+    return '/'.join(['..'] * (len(base) - common) + path[common:])
 
 
 class PathMap(object):
@@ -559,7 +559,7 @@ class PathMap(object):
                     m = m[name]
                 except KeyError:
                     return
-        for (nm, subm) in m.iteritems():
+        for (nm, subm) in m.items():
             if not nm:
                 yield abspath(root)
             else:
@@ -568,7 +568,7 @@ class PathMap(object):
                     yield subk
 
     def __iter__(self):
-        return self.iterkeys()
+        return iter(self.keys())
 
     def keys(self,root="/"):
         return list(self.iterkeys(root))
@@ -583,7 +583,7 @@ class PathMap(object):
                     m = m[name]
                 except KeyError:
                     return
-        for (nm, subm) in m.iteritems():
+        for (nm, subm) in m.items():
             if not nm:
                 yield subm
             else:
@@ -604,7 +604,7 @@ class PathMap(object):
                     m = m[name]
                 except KeyError:
                     return
-        for (nm, subm) in m.iteritems():
+        for (nm, subm) in m.items():
             if not nm:
                 yield (abspath(normpath(root)), subm)
             else:
@@ -627,7 +627,7 @@ class PathMap(object):
                 m = m[name]
             except KeyError:
                 return
-        for (nm, subm) in m.iteritems():
+        for (nm, subm) in m.items():
             if nm and subm:
                 yield nm
 
@@ -651,9 +651,9 @@ def iswildcard(path):
     return not _wild_chars.isdisjoint(path)
 
 if __name__ == "__main__":
-    print recursepath('a/b/c')
+    print(recursepath('a/b/c'))
 
-    print relativefrom('/', '/foo')
-    print relativefrom('/foo/bar', '/foo/baz')
-    print relativefrom('/foo/bar/baz', '/foo/egg')
-    print relativefrom('/foo/bar/baz/egg', '/foo/egg')
+    print(relativefrom('/', '/foo'))
+    print(relativefrom('/foo/bar', '/foo/baz'))
+    print(relativefrom('/foo/bar/baz', '/foo/egg'))
+    print(relativefrom('/foo/bar/baz/egg', '/foo/egg'))
--- fs/remote.py.orig	2015-04-12 17:24:29 UTC
+++ fs/remote.py
@@ -20,8 +20,8 @@ FS subclasses interfacing with a remote filesystem.  T
 
 """
 
-from __future__ import with_statement
 
+
 import time
 import stat as statinfo
 from errno import EINVAL
@@ -422,11 +422,11 @@ class CachedInfo(object):
         self.has_full_children = other.has_full_children
     @classmethod
     def new_file_stub(cls):
-        info = {"info" : 0700 | statinfo.S_IFREG}
+        info = {"info" : 0o700 | statinfo.S_IFREG}
         return cls(info,has_full_info=False)
     @classmethod
     def new_dir_stub(cls):
-        info = {"info" : 0700 | statinfo.S_IFDIR}
+        info = {"info" : 0o700 | statinfo.S_IFDIR}
         return cls(info,has_full_info=False)
 
 
@@ -512,7 +512,7 @@ class CacheFSMixin(FS):
             if self.max_cache_size is not None and old_ci is None:
                 while self.__cache_size >= self.max_cache_size:
                     try:
-                        to_del = iter(self.__cache).next()
+                        to_del = next(iter(self.__cache))
                     except StopIteration:
                         break
                     else:
@@ -592,7 +592,7 @@ class CacheFSMixin(FS):
 
     def isdir(self, path):
         try:
-            self.__cache.iternames(path).next()
+            next(self.__cache.iternames(path))
             return True
         except StopIteration:
             pass
@@ -607,7 +607,7 @@ class CacheFSMixin(FS):
 
     def isfile(self, path):
         try:
-            self.__cache.iternames(path).next()
+            next(self.__cache.iternames(path))
             return False
         except StopIteration:
             pass
--- fs/remotefs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/remotefs.py
@@ -1,5 +1,5 @@
 # Work in Progress - Do not use
-from __future__ import with_statement
+
 from fs.base import FS
 from fs.expose.serve import packetstream
 
@@ -7,7 +7,7 @@ from collections import defaultdict
 import threading
 from threading import Lock, RLock
 from json import dumps
-import Queue as queue
+import queue as queue
 import socket
 
 from six import b
@@ -35,12 +35,12 @@ class PacketHandler(threading.Thread):
         while True:
             data = read(1024*16)
             if not data:
-                print "No data"
+                print("No data")
                 break
-            print "data", repr(data)            
+            print("data", repr(data))            
             for header, payload in decoder.feed(data):
-                print repr(header)
-                print repr(payload)
+                print(repr(header))
+                print(repr(payload))
                 on_packet(header, payload)
              
     def _new_call_id(self):
@@ -77,8 +77,8 @@ class PacketHandler(threading.Thread):
         
         while True:        
             header, payload = queue.get()
-            print repr(header)
-            print repr(payload)
+            print(repr(header))
+            print(repr(payload))
             if client_ref is not None and header.get('client_ref') != client_ref:
                 continue
             break                
@@ -167,9 +167,9 @@ class RemoteFS(FS):
     def ping(self, msg):
         call_id = self.packet_handler.send_packet({'type':'rpc', 'method':'ping'}, msg)
         header, payload = self.packet_handler.get_packet(call_id)
-        print "PING"
-        print header
-        print payload
+        print("PING")
+        print(header)
+        print(payload)
     
     def close(self):
         self.transport.close()
--- fs/rpcfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/rpcfs.py
@@ -8,7 +8,7 @@ class from the :mod:`fs.expose.xmlrpc` module.
 
 """
 
-import xmlrpclib
+import xmlrpc.client
 import socket
 import base64
 
@@ -28,11 +28,11 @@ def re_raise_faults(func):
     def wrapper(*args, **kwds):
         try:
             return func(*args, **kwds)
-        except (xmlrpclib.Fault), f:
+        except (xmlrpc.client.Fault) as f:
             #raise
             # Make sure it's in a form we can handle
 
-            print f.faultString
+            print(f.faultString)
             bits = f.faultString.split(" ")
             if bits[0] not in ["<type", "<class"]:
                 raise f
@@ -41,7 +41,7 @@ def re_raise_faults(func):
             cls = bits[0]
             msg = ">:".join(bits[1:])
             cls = cls.strip('\'')
-            print "-" + cls
+            print("-" + cls)
             cls = _object_by_name(cls)
             # Re-raise using the remainder of the fault code as message
             if cls:
@@ -50,7 +50,7 @@ def re_raise_faults(func):
                 else:
                     raise cls(msg)
             raise f
-        except socket.error, e:
+        except socket.error as e:
             raise RemoteConnectionError(str(e), details=e)
     return wrapper
 
@@ -126,9 +126,9 @@ class RPCFS(FS):
         kwds = dict(allow_none=True, use_datetime=True)
 
         if self._transport is not None:
-            proxy = xmlrpclib.ServerProxy(self.uri, self._transport, **kwds)
+            proxy = xmlrpc.client.ServerProxy(self.uri, self._transport, **kwds)
         else:
-            proxy = xmlrpclib.ServerProxy(self.uri, **kwds)
+            proxy = xmlrpc.client.ServerProxy(self.uri, **kwds)
 
         return ReRaiseFaults(proxy)
 
@@ -170,7 +170,7 @@ class RPCFS(FS):
             meta = self.proxy.getmeta(meta_name)
         else:
             meta = self.proxy.getmeta_default(meta_name, default)
-        if isinstance(meta, basestring):
+        if isinstance(meta, str):
             #  To allow transport of meta with invalid xml chars (like null)
             meta = self.encode_path(meta)
         return meta
@@ -185,7 +185,7 @@ class RPCFS(FS):
         # TODO: chunked transport of large files
         epath = self.encode_path(path)
         if "w" in mode:
-            self.proxy.set_contents(epath, xmlrpclib.Binary(b("")))
+            self.proxy.set_contents(epath, xmlrpc.client.Binary(b("")))
         if "r" in mode or "a" in mode or "+" in mode:
             try:
                 data = self.proxy.get_contents(epath, "rb").data
@@ -194,7 +194,7 @@ class RPCFS(FS):
                     raise ResourceNotFoundError(path)
                 if not self.isdir(dirname(path)):
                     raise ParentDirectoryMissingError(path)
-                self.proxy.set_contents(path, xmlrpclib.Binary(b("")))
+                self.proxy.set_contents(path, xmlrpc.client.Binary(b("")))
         else:
             data = b("")
         f = StringIO(data)
@@ -210,7 +210,7 @@ class RPCFS(FS):
             self._lock.acquire()
             try:
                 oldflush()
-                self.proxy.set_contents(epath, xmlrpclib.Binary(f.getvalue()))
+                self.proxy.set_contents(epath, xmlrpc.client.Binary(f.getvalue()))
             finally:
                 self._lock.release()
 
--- fs/s3fs.py.orig	2015-11-13 16:37:26 UTC
+++ fs/s3fs.py
@@ -41,7 +41,7 @@ else:
             try:
                 return self._map[(threading.currentThread(),attr)]
             except KeyError:
-                raise AttributeError, attr
+                raise AttributeError(attr)
         def __setattr__(self,attr,value):
             self._map[(threading.currentThread(),attr)] = value
 
@@ -106,7 +106,7 @@ class S3FS(FS):
             prefix = prefix[1:]
         if not prefix.endswith(separator) and prefix != "":
             prefix = prefix + separator
-        if isinstance(prefix,unicode):
+        if isinstance(prefix,str):
             prefix = prefix.encode("utf8")
         if aws_access_key is None:
             if "AWS_ACCESS_KEY_ID" not in os.environ:
@@ -149,7 +149,7 @@ class S3FS(FS):
                     b.get_key(self._prefix)
                 else:
                     b = self._s3conn.get_bucket(self._bucket_name, validate=1)
-            except S3ResponseError, e:
+            except S3ResponseError as e:
                 if "404 Not Found" not in str(e):
                     raise
                 b = self._s3conn.create_bucket(self._bucket_name)
@@ -179,7 +179,7 @@ class S3FS(FS):
         s3path = self._prefix + path
         if s3path and s3path[-1] == self._separator:
             s3path = s3path[:-1]
-        if isinstance(s3path,unicode):
+        if isinstance(s3path,str):
             s3path = s3path.encode("utf8")
         return s3path
 
@@ -220,9 +220,9 @@ class S3FS(FS):
 
     def _sync_set_contents(self,key,contents):
         """Synchronously set the contents of a key."""
-        if isinstance(key,basestring):
+        if isinstance(key,str):
             key = self._s3bukt.new_key(key)
-        if isinstance(contents,basestring):
+        if isinstance(contents,str):
             key.set_contents_from_string(contents)
         elif hasattr(contents,"md5"):
             hexmd5 = contents.md5
@@ -338,7 +338,7 @@ class S3FS(FS):
         # the directory itself, which other tools may not create.
         ks = self._s3bukt.list(prefix=s3path,delimiter=self._separator)
         try:
-            iter(ks).next()
+            next(iter(ks))
         except StopIteration:
             return False
         else:
@@ -398,7 +398,7 @@ class S3FS(FS):
             # Skip over the entry for the directory itself, if it exists
             name = self._uns3path(k.name,s3path)
             if name != "":
-                if not isinstance(name,unicode):
+                if not isinstance(name,str):
                     name = name.decode("utf8")
                 if name.endswith(self._separator):
                     name = name[:-1]
@@ -572,14 +572,14 @@ class S3FS(FS):
         else:
             info["name"] = basename(self._uns3key(k.name))
         if self._key_is_dir(key):
-            info["st_mode"] = 0700 | statinfo.S_IFDIR
+            info["st_mode"] = 0o700 | statinfo.S_IFDIR
         else:
-            info["st_mode"] =  0700 | statinfo.S_IFREG
+            info["st_mode"] =  0o700 | statinfo.S_IFREG
         if hasattr(key,"size"):
             info['size'] = int(key.size)
         etag = getattr(key,"etag",None)
         if etag is not None:
-            if isinstance(etag,unicode):
+            if isinstance(etag,str):
                etag = etag.encode("utf8")
             info['etag'] = etag.strip('"').strip("'")
         if hasattr(key,"last_modified"):
@@ -632,7 +632,7 @@ class S3FS(FS):
         s3path_src = self._s3path(src)
         try:
             self._s3bukt.copy_key(s3path_dst,self._bucket_name,s3path_src)
-        except S3ResponseError, e:
+        except S3ResponseError as e:
             if "404 Not Found" in str(e):
                 msg = "Source is not a file: %(path)s"
                 raise ResourceInvalidError(src, msg=msg)
@@ -663,7 +663,7 @@ class S3FS(FS):
             for k in self._s3bukt.list(prefix=prefix):
                 name = relpath(self._uns3path(k.name,prefix))
                 if name != "":
-                    if not isinstance(name,unicode):
+                    if not isinstance(name,str):
                         name = name.decode("utf8")
                     if not k.name.endswith(self._separator):
                         if wildcard is not None:
@@ -691,7 +691,7 @@ class S3FS(FS):
             for k in self._s3bukt.list(prefix=prefix):
                 name = relpath(self._uns3path(k.name,prefix))
                 if name != "":
-                    if not isinstance(name,unicode):
+                    if not isinstance(name,str):
                         name = name.decode("utf8")
                     if wildcard is not None:
                         if callable(wildcard):
@@ -718,7 +718,7 @@ class S3FS(FS):
             for k in self._s3bukt.list(prefix=prefix):
                 name = relpath(self._uns3path(k.name,prefix))
                 if name != "":
-                    if not isinstance(name,unicode):
+                    if not isinstance(name,str):
                         name = name.decode("utf8")
                     if not k.name.endswith(self._separator):
                         if wildcard is not None:
@@ -733,16 +733,16 @@ class S3FS(FS):
 
 
 def _eq_utf8(name1,name2):
-    if isinstance(name1,unicode):
+    if isinstance(name1,str):
         name1 = name1.encode("utf8")
-    if isinstance(name2,unicode):
+    if isinstance(name2,str):
         name2 = name2.encode("utf8")
     return name1 == name2
 
 def _startswith_utf8(name1,name2):
-    if isinstance(name1,unicode):
+    if isinstance(name1,str):
         name1 = name1.encode("utf8")
-    if isinstance(name2,unicode):
+    if isinstance(name2,str):
         name2 = name2.encode("utf8")
     return name1.startswith(name2)
 
--- fs/sftpfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/sftpfs.py
@@ -131,7 +131,7 @@ class SFTPFS(FS):
         self._client = None
 
         self.hostname = None
-        if isinstance(connection, basestring):
+        if isinstance(connection, str):
             self.hostname = connection
         elif isinstance(connection, tuple):
             self.hostname = '%s:%s' % connection
@@ -183,7 +183,7 @@ class SFTPFS(FS):
                 if not connection.is_authenticated():
                     try:
                         connection.auth_none(username)
-                    except paramiko.BadAuthenticationType, e:
+                    except paramiko.BadAuthenticationType as e:
                         self.close()
                         allowed = ', '.join(e.allowed_types)
                         raise RemoteConnectionError(msg='no auth - server requires one of the following: %s' % allowed, details=e)
@@ -192,14 +192,14 @@ class SFTPFS(FS):
                     self.close()
                     raise RemoteConnectionError(msg='no auth')
 
-            except paramiko.SSHException, e:
+            except paramiko.SSHException as e:
                 self.close()
                 raise RemoteConnectionError(msg='SSH exception (%s)' % str(e), details=e)
 
         self._transport = connection
 
     def __unicode__(self):
-        return u'<SFTPFS: %s>' % self.desc('/')
+        return '<SFTPFS: %s>' % self.desc('/')
 
     @classmethod
     def _agent_auth(cls, transport, username):
@@ -307,7 +307,7 @@ class SFTPFS(FS):
             self.closed = True
 
     def _normpath(self, path):
-        if not isinstance(path, unicode):
+        if not isinstance(path, str):
             path = path.decode(self.encoding)
         npath = pathjoin(self.root_path, relpath(normpath(path)))
         if not isprefix(self.root_path, npath):
@@ -355,10 +355,10 @@ class SFTPFS(FS):
     def desc(self, path):
         npath = self._normpath(path)
         if self.hostname:
-            return u'sftp://%s%s' % (self.hostname, path)
+            return 'sftp://%s%s' % (self.hostname, path)
         else:
             addr, port = self._transport.getpeername()
-            return u'sftp://%s:%i%s' % (addr, port, self.client.normalize(npath))
+            return 'sftp://%s:%i%s' % (addr, port, self.client.normalize(npath))
 
     @synchronize
     @convert_os_errors
@@ -368,7 +368,7 @@ class SFTPFS(FS):
         npath = self._normpath(path)
         try:
             self.client.stat(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 return False
             raise
@@ -382,7 +382,7 @@ class SFTPFS(FS):
         npath = self._normpath(path)
         try:
             stat = self.client.stat(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 return False
             raise
@@ -394,7 +394,7 @@ class SFTPFS(FS):
         npath = self._normpath(path)
         try:
             stat = self.client.stat(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 return False
             raise
@@ -409,10 +409,10 @@ class SFTPFS(FS):
             if dirs_only or files_only:
                 attrs = self.client.listdir_attr(npath)
                 attrs_map = dict((a.filename, a) for a in attrs)
-                paths = list(attrs_map.iterkeys())
+                paths = list(attrs_map.keys())
             else:
                 paths = self.client.listdir(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 if self.isfile(path):
                     raise ResourceInvalidError(path,msg="Can't list directory contents of a file: %(path)s")
@@ -424,19 +424,19 @@ class SFTPFS(FS):
         if attrs_map:
             if dirs_only:
                 filter_paths = []
-                for apath, attr in attrs_map.iteritems():
+                for apath, attr in attrs_map.items():
                     if isdir(self, path, attr.__dict__):
                         filter_paths.append(apath)
                 paths = filter_paths
             elif files_only:
                 filter_paths = []
-                for apath, attr in attrs_map.iteritems():
+                for apath, attr in attrs_map.items():
                     if isfile(self, apath, attr.__dict__):
                         filter_paths.append(apath)
                 paths = filter_paths
 
         for (i,p) in enumerate(paths):
-            if not isinstance(p,unicode):
+            if not isinstance(p,str):
                 paths[i] = p.decode(self.encoding)
 
         return self._listdir_helper(path, paths, wildcard, full, absolute, False, False)
@@ -448,8 +448,8 @@ class SFTPFS(FS):
         try:
             attrs = self.client.listdir_attr(npath)
             attrs_map = dict((a.filename, a) for a in attrs)
-            paths = attrs_map.keys()
-        except IOError, e:
+            paths = list(attrs_map.keys())
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 if self.isfile(path):
                     raise ResourceInvalidError(path,msg="Can't list directory contents of a file: %(path)s")
@@ -460,19 +460,19 @@ class SFTPFS(FS):
 
         if dirs_only:
             filter_paths = []
-            for path, attr in attrs_map.iteritems():
+            for path, attr in attrs_map.items():
                 if isdir(self, path, attr.__dict__):
                     filter_paths.append(path)
             paths = filter_paths
         elif files_only:
             filter_paths = []
-            for path, attr in attrs_map.iteritems():
+            for path, attr in attrs_map.items():
                 if isfile(self, path, attr.__dict__):
                     filter_paths.append(path)
             paths = filter_paths
 
         for (i, p) in enumerate(paths):
-            if not isinstance(p, unicode):
+            if not isinstance(p, str):
                 paths[i] = p.decode(self.encoding)
 
         def getinfo(p):
@@ -491,7 +491,7 @@ class SFTPFS(FS):
         npath = self._normpath(path)
         try:
             self.client.mkdir(npath)
-        except IOError, _e:
+        except IOError as _e:
             # Error code is unreliable, try to figure out what went wrong
             try:
                 stat = self.client.stat(npath)
@@ -519,7 +519,7 @@ class SFTPFS(FS):
         npath = self._normpath(path)
         try:
             self.client.remove(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 raise ResourceNotFoundError(path)
             elif self.isdir(path):
@@ -542,7 +542,7 @@ class SFTPFS(FS):
             raise ResourceNotFoundError(path)
         try:
             self.client.rmdir(npath)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 if self.isfile(path):
                     raise ResourceInvalidError(path,msg="Can't use removedir() on a file: %(path)s")
@@ -565,7 +565,7 @@ class SFTPFS(FS):
         ndst = self._normpath(dst)
         try:
             self.client.rename(nsrc,ndst)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 raise ResourceNotFoundError(src)
             if not self.isdir(dirname(dst)):
@@ -581,7 +581,7 @@ class SFTPFS(FS):
             self.remove(dst)
         try:
             self.client.rename(nsrc,ndst)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 raise ResourceNotFoundError(src)
             if self.exists(dst):
@@ -599,7 +599,7 @@ class SFTPFS(FS):
             self.removedir(dst)
         try:
             self.client.rename(nsrc,ndst)
-        except IOError, e:
+        except IOError as e:
             if getattr(e,"errno",None) == ENOENT:
                 raise ResourceNotFoundError(src)
             if self.exists(dst):
@@ -612,7 +612,7 @@ class SFTPFS(FS):
     @classmethod
     def _extract_info(cls, stats):
         fromtimestamp = datetime.datetime.fromtimestamp
-        info = dict((k, v) for k, v in stats.iteritems() if k in cls._info_vars and not k.startswith('_'))
+        info = dict((k, v) for k, v in stats.items() if k in cls._info_vars and not k.startswith('_'))
         info['size'] = info['st_size']
         ct = info.get('st_ctime')
         if ct is not None:
--- fs/tempfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/tempfs.py
@@ -29,7 +29,7 @@ class TempFS(OSFS):
     _meta['atomic.move'] = True
     _meta['atomic.copy'] = True
 
-    def __init__(self, identifier=None, temp_dir=None, dir_mode=0700, thread_synchronize=_thread_synchronize_default):
+    def __init__(self, identifier=None, temp_dir=None, dir_mode=0o700, thread_synchronize=_thread_synchronize_default):
         """Creates a temporary Filesystem
 
         identifier -- A string that is included in the name of the temporary directory,
@@ -49,7 +49,7 @@ class TempFS(OSFS):
     __str__ = __repr__
 
     def __unicode__(self):
-        return u'<TempFS: %s>' % self._temp_dir
+        return '<TempFS: %s>' % self._temp_dir
 
     def __getstate__(self):
         # If we are picking a TempFS, we want to preserve its contents,
--- fs/tests/__init__.py.orig	2015-11-13 22:33:26 UTC
+++ fs/tests/__init__.py
@@ -5,8 +5,8 @@
 
 """
 
-from __future__ import with_statement
 
+
 #  Send any output from the logging module to stdout, so it will
 #  be captured by nose and reported appropriately
 import sys
@@ -61,7 +61,7 @@ class FSTestCases(object):
         self.assertEqual(self.fs.validatepath('.foo'), None)
         self.assertEqual(self.fs.validatepath('foo'), None)
         self.assertEqual(self.fs.validatepath('foo/bar'), None)
-        self.assert_(self.fs.isvalidpath('foo/bar'))
+        self.assertTrue(self.fs.isvalidpath('foo/bar'))
 
     def test_tree(self):
         """Test tree print"""
@@ -79,8 +79,8 @@ class FSTestCases(object):
         stupid_meta = 'thismetashouldnotexist!"r$$%^&&*()_+'
         self.assertRaises(NoMetaError, self.fs.getmeta, stupid_meta)
         self.assertFalse(self.fs.hasmeta(stupid_meta))
-        self.assertEquals(None, self.fs.getmeta(stupid_meta, None))
-        self.assertEquals(3.14, self.fs.getmeta(stupid_meta, 3.14))
+        self.assertEqual(None, self.fs.getmeta(stupid_meta, None))
+        self.assertEqual(3.14, self.fs.getmeta(stupid_meta, 3.14))
         for meta_name in meta_names:
             try:
                 meta = self.fs.getmeta(meta_name)
@@ -101,15 +101,15 @@ class FSTestCases(object):
         except NoSysPathError:
             pass
         else:
-            self.assertTrue(isinstance(syspath, unicode))
+            self.assertTrue(isinstance(syspath, str))
         syspath = self.fs.getsyspath("/", allow_none=True)
         if syspath is not None:
-            self.assertTrue(isinstance(syspath, unicode))
+            self.assertTrue(isinstance(syspath, str))
 
     def test_debug(self):
         str(self.fs)
         repr(self.fs)
-        self.assert_(hasattr(self.fs, 'desc'))
+        self.assertTrue(hasattr(self.fs, 'desc'))
 
     def test_open_on_directory(self):
         self.fs.makedir("testdir")
@@ -132,20 +132,20 @@ class FSTestCases(object):
         f.close()
         self.assertTrue(self.check("test1.txt"))
         f = self.fs.open("test1.txt", "rb")
-        self.assertEquals(f.read(), b("testing"))
+        self.assertEqual(f.read(), b("testing"))
         f.close()
         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", "rb")
-        self.assertEquals(f.read(), b("test file overwrite"))
+        self.assertEqual(f.read(), b("test file overwrite"))
         f.close()
 
     def test_createfile(self):
         test = b('now with content')
         self.fs.createfile("test.txt")
-        self.assert_(self.fs.exists("test.txt"))
+        self.assertTrue(self.fs.exists("test.txt"))
         self.assertEqual(self.fs.getcontents("test.txt", "rb"), b(''))
         self.fs.setcontents("test.txt", test)
         self.fs.createfile("test.txt")
@@ -163,36 +163,36 @@ class FSTestCases(object):
     def test_setcontents(self):
         #  setcontents() should accept both a string...
         self.fs.setcontents("hello", b("world"))
-        self.assertEquals(self.fs.getcontents("hello", "rb"), b("world"))
+        self.assertEqual(self.fs.getcontents("hello", "rb"), b("world"))
         #  ...and a file-like object
         self.fs.setcontents("hello", StringIO(b("to you, good sir!")))
-        self.assertEquals(self.fs.getcontents(
+        self.assertEqual(self.fs.getcontents(
             "hello", "rb"), b("to you, good sir!"))
         #  setcontents() should accept both a string...
         self.fs.setcontents("hello", b("world"), chunk_size=2)
-        self.assertEquals(self.fs.getcontents("hello", "rb"), b("world"))
+        self.assertEqual(self.fs.getcontents("hello", "rb"), b("world"))
         #  ...and a file-like object
         self.fs.setcontents("hello", StringIO(
             b("to you, good sir!")), chunk_size=2)
-        self.assertEquals(self.fs.getcontents(
+        self.assertEqual(self.fs.getcontents(
             "hello", "rb"), b("to you, good sir!"))
         self.fs.setcontents("hello", b(""))
-        self.assertEquals(self.fs.getcontents("hello", "rb"), b(""))
+        self.assertEqual(self.fs.getcontents("hello", "rb"), b(""))
 
     def test_setcontents_async(self):
         #  setcontents() should accept both a string...
         self.fs.setcontents_async("hello", b("world")).wait()
-        self.assertEquals(self.fs.getcontents("hello", "rb"), b("world"))
+        self.assertEqual(self.fs.getcontents("hello", "rb"), b("world"))
         #  ...and a file-like object
         self.fs.setcontents_async("hello", StringIO(
             b("to you, good sir!"))).wait()
-        self.assertEquals(self.fs.getcontents("hello"), b("to you, good sir!"))
+        self.assertEqual(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"))
+        self.assertEqual(self.fs.getcontents("hello", "rb"), b("world"))
         #  ...and a file-like object
         self.fs.setcontents_async("hello", StringIO(
             b("to you, good sir!")), chunk_size=2).wait()
-        self.assertEquals(self.fs.getcontents(
+        self.assertEqual(self.fs.getcontents(
             "hello", "rb"), b("to you, good sir!"))
 
     def test_isdir_isfile(self):
@@ -214,19 +214,19 @@ class FSTestCases(object):
     def test_listdir(self):
         def check_unicode(items):
             for item in items:
-                self.assertTrue(isinstance(item, unicode))
-        self.fs.setcontents(u"a", b(''))
+                self.assertTrue(isinstance(item, str))
+        self.fs.setcontents("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)
-        self.assertEqual(sorted(d1), [u"a", u"b", u"bar", u"foo"])
+        self.assertEqual(sorted(d1), ["a", "b", "bar", "foo"])
         check_unicode(d1)
         d1 = self.fs.listdir("")
         self.assertEqual(len(d1), 4)
-        self.assertEqual(sorted(d1), [u"a", u"b", u"bar", u"foo"])
+        self.assertEqual(sorted(d1), ["a", "b", "bar", "foo"])
         check_unicode(d1)
         d1 = self.fs.listdir("/")
         self.assertEqual(len(d1), 4)
@@ -234,7 +234,7 @@ class FSTestCases(object):
         # Test listing absolute paths
         d2 = self.fs.listdir(absolute=True)
         self.assertEqual(len(d2), 4)
-        self.assertEqual(sorted(d2), [u"/a", u"/b", u"/bar", u"/foo"])
+        self.assertEqual(sorted(d2), ["/a", "/b", "/bar", "/foo"])
         check_unicode(d2)
         # Create some deeper subdirectories, to make sure their
         # contents are not inadvertantly included
@@ -248,25 +248,25 @@ class FSTestCases(object):
         dirs_only = self.fs.listdir(dirs_only=True)
         files_only = self.fs.listdir(files_only=True)
         contains_a = self.fs.listdir(wildcard="*a*")
-        self.assertEqual(sorted(dirs_only), [u"p", u"q"])
-        self.assertEqual(sorted(files_only), [u"a", u"b", u"bar", u"foo"])
-        self.assertEqual(sorted(contains_a), [u"a", u"bar"])
+        self.assertEqual(sorted(dirs_only), ["p", "q"])
+        self.assertEqual(sorted(files_only), ["a", "b", "bar", "foo"])
+        self.assertEqual(sorted(contains_a), ["a", "bar"])
         check_unicode(dirs_only)
         check_unicode(files_only)
         check_unicode(contains_a)
         # Test listing a subdirectory
         d3 = self.fs.listdir("p/1/2/3")
         self.assertEqual(len(d3), 4)
-        self.assertEqual(sorted(d3), [u"a", u"b", u"bar", u"foo"])
+        self.assertEqual(sorted(d3), ["a", "b", "bar", "foo"])
         check_unicode(d3)
         # Test listing a subdirectory with absoliute and full paths
         d4 = self.fs.listdir("p/1/2/3", absolute=True)
         self.assertEqual(len(d4), 4)
-        self.assertEqual(sorted(d4), [u"/p/1/2/3/a", u"/p/1/2/3/b", u"/p/1/2/3/bar", u"/p/1/2/3/foo"])
+        self.assertEqual(sorted(d4), ["/p/1/2/3/a", "/p/1/2/3/b", "/p/1/2/3/bar", "/p/1/2/3/foo"])
         check_unicode(d4)
         d4 = self.fs.listdir("p/1/2/3", full=True)
         self.assertEqual(len(d4), 4)
-        self.assertEqual(sorted(d4), [u"p/1/2/3/a", u"p/1/2/3/b", u"p/1/2/3/bar", u"p/1/2/3/foo"])
+        self.assertEqual(sorted(d4), ["p/1/2/3/a", "p/1/2/3/b", "p/1/2/3/bar", "p/1/2/3/foo"])
         check_unicode(d4)
         # Test that appropriate errors are raised
         self.assertRaises(ResourceNotFoundError, self.fs.listdir, "zebra")
@@ -275,32 +275,32 @@ class FSTestCases(object):
     def test_listdirinfo(self):
         def check_unicode(items):
             for (nm, info) in items:
-                self.assertTrue(isinstance(nm, unicode))
+                self.assertTrue(isinstance(nm, str))
 
         def check_equal(items, target):
             names = [nm for (nm, info) in items]
             self.assertEqual(sorted(names), sorted(target))
-        self.fs.setcontents(u"a", b(''))
+        self.fs.setcontents("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)
-        check_equal(d1, [u"a", u"b", u"bar", u"foo"])
+        check_equal(d1, ["a", "b", "bar", "foo"])
         check_unicode(d1)
         d1 = self.fs.listdirinfo("")
         self.assertEqual(len(d1), 4)
-        check_equal(d1, [u"a", u"b", u"bar", u"foo"])
+        check_equal(d1, ["a", "b", "bar", "foo"])
         check_unicode(d1)
         d1 = self.fs.listdirinfo("/")
         self.assertEqual(len(d1), 4)
-        check_equal(d1, [u"a", u"b", u"bar", u"foo"])
+        check_equal(d1, ["a", "b", "bar", "foo"])
         check_unicode(d1)
         # Test listing absolute paths
         d2 = self.fs.listdirinfo(absolute=True)
         self.assertEqual(len(d2), 4)
-        check_equal(d2, [u"/a", u"/b", u"/bar", u"/foo"])
+        check_equal(d2, ["/a", "/b", "/bar", "/foo"])
         check_unicode(d2)
         # Create some deeper subdirectories, to make sure their
         # contents are not inadvertantly included
@@ -314,25 +314,25 @@ class FSTestCases(object):
         dirs_only = self.fs.listdirinfo(dirs_only=True)
         files_only = self.fs.listdirinfo(files_only=True)
         contains_a = self.fs.listdirinfo(wildcard="*a*")
-        check_equal(dirs_only, [u"p", u"q"])
-        check_equal(files_only, [u"a", u"b", u"bar", u"foo"])
-        check_equal(contains_a, [u"a", u"bar"])
+        check_equal(dirs_only, ["p", "q"])
+        check_equal(files_only, ["a", "b", "bar", "foo"])
+        check_equal(contains_a, ["a", "bar"])
         check_unicode(dirs_only)
         check_unicode(files_only)
         check_unicode(contains_a)
         # Test listing a subdirectory
         d3 = self.fs.listdirinfo("p/1/2/3")
         self.assertEqual(len(d3), 4)
-        check_equal(d3, [u"a", u"b", u"bar", u"foo"])
+        check_equal(d3, ["a", "b", "bar", "foo"])
         check_unicode(d3)
         # Test listing a subdirectory with absoliute and full paths
         d4 = self.fs.listdirinfo("p/1/2/3", absolute=True)
         self.assertEqual(len(d4), 4)
-        check_equal(d4, [u"/p/1/2/3/a", u"/p/1/2/3/b", u"/p/1/2/3/bar", u"/p/1/2/3/foo"])
+        check_equal(d4, ["/p/1/2/3/a", "/p/1/2/3/b", "/p/1/2/3/bar", "/p/1/2/3/foo"])
         check_unicode(d4)
         d4 = self.fs.listdirinfo("p/1/2/3", full=True)
         self.assertEqual(len(d4), 4)
-        check_equal(d4, [u"p/1/2/3/a", u"p/1/2/3/b", u"p/1/2/3/bar", u"p/1/2/3/foo"])
+        check_equal(d4, ["p/1/2/3/a", "p/1/2/3/b", "p/1/2/3/bar", "p/1/2/3/foo"])
         check_unicode(d4)
         # Test that appropriate errors are raised
         self.assertRaises(ResourceNotFoundError, self.fs.listdirinfo, "zebra")
@@ -343,7 +343,7 @@ class FSTestCases(object):
         self.fs.setcontents('b.txt', b('world'))
         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,
+        self.assertEqual(sorted_walk,
                           [("/", ["a.txt", "b.txt"]),
                            ("/foo", ["c"])])
         #  When searching breadth-first, shallow entries come first
@@ -371,10 +371,10 @@ class FSTestCases(object):
         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'))
+                self.assertTrue(path.endswith('.txt'))
         for dir_path, paths in self.fs.walk(wildcard=lambda fn: fn.endswith('.txt')):
             for path in paths:
-                self.assert_(path.endswith('.txt'))
+                self.assertTrue(path.endswith('.txt'))
 
     def test_walk_dir_wildcard(self):
         self.fs.setcontents('a.txt', b('hello'))
@@ -383,35 +383,35 @@ class FSTestCases(object):
         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)
+                self.assertTrue('.svn' not in path)
 
     def test_walkfiles(self):
         self.fs.makeopendir('bar').setcontents('a.txt', b('123'))
         self.fs.makeopendir('foo').setcontents('b', b('123'))
-        self.assertEquals(sorted(
+        self.assertEqual(sorted(
             self.fs.walkfiles()), ["/bar/a.txt", "/foo/b"])
-        self.assertEquals(sorted(self.fs.walkfiles(
+        self.assertEqual(sorted(self.fs.walkfiles(
             dir_wildcard="*foo*")), ["/foo/b"])
-        self.assertEquals(sorted(self.fs.walkfiles(
+        self.assertEqual(sorted(self.fs.walkfiles(
             wildcard="*.txt")), ["/bar/a.txt"])
 
     def test_walkdirs(self):
         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()), [
+        self.assertEqual(sorted(self.fs.walkdirs()), [
                           "/", "/bar", "/foo", "/foo/baz"])
-        self.assertEquals(sorted(self.fs.walkdirs(
+        self.assertEqual(sorted(self.fs.walkdirs(
             wildcard="*foo*")), ["/", "/foo", "/foo/baz"])
 
     def test_unicode(self):
-        alpha = u"\N{GREEK SMALL LETTER ALPHA}"
-        beta = u"\N{GREEK SMALL LETTER BETA}"
+        alpha = "\N{GREEK SMALL LETTER ALPHA}"
+        beta = "\N{GREEK SMALL LETTER BETA}"
         self.fs.makedir(alpha)
         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])
+        self.assertEqual(sorted(self.fs.listdir(alpha)), ["a", beta])
 
     def test_makedir(self):
         check = self.check
@@ -420,11 +420,11 @@ class FSTestCases(object):
         self.assertRaises(
             ParentDirectoryMissingError, self.fs.makedir, "a/b/c")
         self.fs.makedir("a/b/c", recursive=True)
-        self.assert_(check("a/b/c"))
+        self.assertTrue(check("a/b/c"))
         self.fs.makedir("foo/bar/baz", recursive=True)
-        self.assert_(check("foo/bar/baz"))
+        self.assertTrue(check("foo/bar/baz"))
         self.fs.makedir("a/b/child")
-        self.assert_(check("a/b/child"))
+        self.assertTrue(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", b(''))
@@ -446,30 +446,30 @@ class FSTestCases(object):
     def test_removedir(self):
         check = self.check
         self.fs.makedir("a")
-        self.assert_(check("a"))
+        self.assertTrue(check("a"))
         self.fs.removedir("a")
         self.assertRaises(ResourceNotFoundError, self.fs.removedir, "a")
-        self.assert_(not check("a"))
+        self.assertTrue(not check("a"))
         self.fs.makedir("a/b/c/d", recursive=True)
         self.assertRaises(DirectoryNotEmptyError, self.fs.removedir, "a/b")
         self.fs.removedir("a/b/c/d")
-        self.assert_(not check("a/b/c/d"))
+        self.assertTrue(not check("a/b/c/d"))
         self.fs.removedir("a/b/c")
-        self.assert_(not check("a/b/c"))
+        self.assertTrue(not check("a/b/c"))
         self.fs.removedir("a/b")
-        self.assert_(not check("a/b"))
+        self.assertTrue(not check("a/b"))
         #  Test recursive removal of empty parent dirs
         self.fs.makedir("foo/bar/baz", recursive=True)
         self.fs.removedir("foo/bar/baz", recursive=True)
-        self.assert_(not check("foo/bar/baz"))
-        self.assert_(not check("foo/bar"))
-        self.assert_(not check("foo"))
+        self.assertTrue(not check("foo/bar/baz"))
+        self.assertTrue(not check("foo/bar"))
+        self.assertTrue(not check("foo"))
         self.fs.makedir("foo/bar/baz", recursive=True)
         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"))
-        self.assert_(check("foo/file.txt"))
+        self.assertTrue(not check("foo/bar/baz"))
+        self.assertTrue(not check("foo/bar"))
+        self.assertTrue(check("foo/file.txt"))
         #  Ensure that force=True works as expected
         self.fs.makedir("frollic/waggle", recursive=True)
         self.fs.setcontents("frollic/waddle.txt", b("waddlewaddlewaddle"))
@@ -477,41 +477,41 @@ class FSTestCases(object):
         self.assertRaises(
             ResourceInvalidError, self.fs.removedir, "frollic/waddle.txt")
         self.fs.removedir("frollic", force=True)
-        self.assert_(not check("frollic"))
+        self.assertTrue(not check("frollic"))
         #  Test removing unicode dirs
-        kappa = u"\N{GREEK CAPITAL LETTER KAPPA}"
+        kappa = "\N{GREEK CAPITAL LETTER KAPPA}"
         self.fs.makedir(kappa)
-        self.assert_(self.fs.isdir(kappa))
+        self.assertTrue(self.fs.isdir(kappa))
         self.fs.removedir(kappa)
         self.assertRaises(ResourceNotFoundError, self.fs.removedir, kappa)
-        self.assert_(not self.fs.isdir(kappa))
+        self.assertTrue(not self.fs.isdir(kappa))
         self.fs.makedir(pathjoin("test", kappa), recursive=True)
-        self.assert_(check(pathjoin("test", kappa)))
+        self.assertTrue(check(pathjoin("test", kappa)))
         self.fs.removedir("test", force=True)
-        self.assert_(not check("test"))
+        self.assertTrue(not check("test"))
 
     def test_rename(self):
         check = self.check
         # test renaming a file in the same directory
         self.fs.setcontents("foo.txt", b("Hello, World!"))
-        self.assert_(check("foo.txt"))
+        self.assertTrue(check("foo.txt"))
         self.fs.rename("foo.txt", "bar.txt")
-        self.assert_(check("bar.txt"))
-        self.assert_(not check("foo.txt"))
+        self.assertTrue(check("bar.txt"))
+        self.assertTrue(not check("foo.txt"))
         # test renaming a directory in the same directory
         self.fs.makedir("dir_a")
         self.fs.setcontents("dir_a/test.txt", b("testerific"))
-        self.assert_(check("dir_a"))
+        self.assertTrue(check("dir_a"))
         self.fs.rename("dir_a", "dir_b")
-        self.assert_(check("dir_b"))
-        self.assert_(check("dir_b/test.txt"))
-        self.assert_(not check("dir_a/test.txt"))
-        self.assert_(not check("dir_a"))
+        self.assertTrue(check("dir_b"))
+        self.assertTrue(check("dir_b/test.txt"))
+        self.assertTrue(not check("dir_a/test.txt"))
+        self.assertTrue(not check("dir_a"))
         # test renaming a file into a different directory
         self.fs.makedir("dir_a")
         self.fs.rename("dir_b/test.txt", "dir_a/test.txt")
-        self.assert_(not check("dir_b/test.txt"))
-        self.assert_(check("dir_a/test.txt"))
+        self.assertTrue(not check("dir_b/test.txt"))
+        self.assertTrue(check("dir_a/test.txt"))
         # test renaming a file into a non-existent  directory
         self.assertRaises(ParentDirectoryMissingError,
                           self.fs.rename, "dir_a/test.txt", "nonexistent/test.txt")
@@ -530,7 +530,7 @@ class FSTestCases(object):
         test_str = b("Hello, World!")
         self.fs.setcontents("info.txt", test_str)
         info = self.fs.getinfo("info.txt")
-        for k, v in info.iteritems():
+        for k, v in info.items():
             self.assertEqual(self.fs.getinfokeys('info.txt', k), {k: v})
 
         test_info = {}
@@ -562,26 +562,26 @@ class FSTestCases(object):
 
         self.fs.makedir("foo/bar", recursive=True)
         makefile("foo/bar/a.txt")
-        self.assert_(check("foo/bar/a.txt"))
-        self.assert_(checkcontents("foo/bar/a.txt"))
+        self.assertTrue(check("foo/bar/a.txt"))
+        self.assertTrue(checkcontents("foo/bar/a.txt"))
         self.fs.move("foo/bar/a.txt", "foo/b.txt")
-        self.assert_(not check("foo/bar/a.txt"))
-        self.assert_(check("foo/b.txt"))
-        self.assert_(checkcontents("foo/b.txt"))
+        self.assertTrue(not check("foo/bar/a.txt"))
+        self.assertTrue(check("foo/b.txt"))
+        self.assertTrue(checkcontents("foo/b.txt"))
 
         self.fs.move("foo/b.txt", "c.txt")
-        self.assert_(not check("foo/b.txt"))
-        self.assert_(check("/c.txt"))
-        self.assert_(checkcontents("/c.txt"))
+        self.assertTrue(not check("foo/b.txt"))
+        self.assertTrue(check("/c.txt"))
+        self.assertTrue(checkcontents("/c.txt"))
 
         makefile("foo/bar/a.txt")
         self.assertRaises(
             DestinationExistsError, self.fs.move, "foo/bar/a.txt", "/c.txt")
-        self.assert_(check("foo/bar/a.txt"))
-        self.assert_(check("/c.txt"))
+        self.assertTrue(check("foo/bar/a.txt"))
+        self.assertTrue(check("/c.txt"))
         self.fs.move("foo/bar/a.txt", "/c.txt", overwrite=True)
-        self.assert_(not check("foo/bar/a.txt"))
-        self.assert_(check("/c.txt"))
+        self.assertTrue(not check("foo/bar/a.txt"))
+        self.assertTrue(check("/c.txt"))
 
     def test_movedir(self):
         check = self.check
@@ -602,29 +602,29 @@ class FSTestCases(object):
 
         self.fs.movedir("a", "copy of a")
 
-        self.assert_(self.fs.isdir("copy of a"))
-        self.assert_(check("copy of a/1.txt"))
-        self.assert_(check("copy of a/2.txt"))
-        self.assert_(check("copy of a/3.txt"))
-        self.assert_(check("copy of a/foo/bar/baz.txt"))
+        self.assertTrue(self.fs.isdir("copy of a"))
+        self.assertTrue(check("copy of a/1.txt"))
+        self.assertTrue(check("copy of a/2.txt"))
+        self.assertTrue(check("copy of a/3.txt"))
+        self.assertTrue(check("copy of a/foo/bar/baz.txt"))
 
-        self.assert_(not check("a/1.txt"))
-        self.assert_(not check("a/2.txt"))
-        self.assert_(not check("a/3.txt"))
-        self.assert_(not check("a/foo/bar/baz.txt"))
-        self.assert_(not check("a/foo/bar"))
-        self.assert_(not check("a/foo"))
-        self.assert_(not check("a"))
+        self.assertTrue(not check("a/1.txt"))
+        self.assertTrue(not check("a/2.txt"))
+        self.assertTrue(not check("a/3.txt"))
+        self.assertTrue(not check("a/foo/bar/baz.txt"))
+        self.assertTrue(not check("a/foo/bar"))
+        self.assertTrue(not check("a/foo"))
+        self.assertTrue(not check("a"))
 
         self.fs.makedir("a")
         self.assertRaises(
             DestinationExistsError, self.fs.movedir, "copy of a", "a")
         self.fs.movedir("copy of a", "a", overwrite=True)
-        self.assert_(not check("copy of a"))
-        self.assert_(check("a/1.txt"))
-        self.assert_(check("a/2.txt"))
-        self.assert_(check("a/3.txt"))
-        self.assert_(check("a/foo/bar/baz.txt"))
+        self.assertTrue(not check("copy of a"))
+        self.assertTrue(check("a/1.txt"))
+        self.assertTrue(check("a/2.txt"))
+        self.assertTrue(check("a/3.txt"))
+        self.assertTrue(check("a/foo/bar/baz.txt"))
 
     def test_cant_copy_from_os(self):
         sys_executable = os.path.abspath(os.path.realpath(sys.executable))
@@ -645,28 +645,28 @@ class FSTestCases(object):
 
         self.fs.makedir("foo/bar", recursive=True)
         makefile("foo/bar/a.txt")
-        self.assert_(check("foo/bar/a.txt"))
-        self.assert_(checkcontents("foo/bar/a.txt"))
+        self.assertTrue(check("foo/bar/a.txt"))
+        self.assertTrue(checkcontents("foo/bar/a.txt"))
         # import rpdb2; rpdb2.start_embedded_debugger('password');
         self.fs.copy("foo/bar/a.txt", "foo/b.txt")
-        self.assert_(check("foo/bar/a.txt"))
-        self.assert_(check("foo/b.txt"))
-        self.assert_(checkcontents("foo/bar/a.txt"))
-        self.assert_(checkcontents("foo/b.txt"))
+        self.assertTrue(check("foo/bar/a.txt"))
+        self.assertTrue(check("foo/b.txt"))
+        self.assertTrue(checkcontents("foo/bar/a.txt"))
+        self.assertTrue(checkcontents("foo/b.txt"))
 
         self.fs.copy("foo/b.txt", "c.txt")
-        self.assert_(check("foo/b.txt"))
-        self.assert_(check("/c.txt"))
-        self.assert_(checkcontents("/c.txt"))
+        self.assertTrue(check("foo/b.txt"))
+        self.assertTrue(check("/c.txt"))
+        self.assertTrue(checkcontents("/c.txt"))
 
         makefile("foo/bar/a.txt", b("different contents"))
-        self.assert_(checkcontents("foo/bar/a.txt", b("different contents")))
+        self.assertTrue(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.assertTrue(checkcontents("/c.txt"))
         self.fs.copy("foo/bar/a.txt", "/c.txt", overwrite=True)
-        self.assert_(checkcontents("foo/bar/a.txt", b("different contents")))
-        self.assert_(checkcontents("/c.txt", b("different contents")))
+        self.assertTrue(checkcontents("foo/bar/a.txt", b("different contents")))
+        self.assertTrue(checkcontents("/c.txt", b("different contents")))
 
     def test_copydir(self):
         check = self.check
@@ -690,24 +690,24 @@ class FSTestCases(object):
         makefile("a/foo/bar/baz.txt")
 
         self.fs.copydir("a", "copy of a")
-        self.assert_(check("copy of a/1.txt"))
-        self.assert_(check("copy of a/2.txt"))
-        self.assert_(check("copy of a/3.txt"))
-        self.assert_(check("copy of a/foo/bar/baz.txt"))
+        self.assertTrue(check("copy of a/1.txt"))
+        self.assertTrue(check("copy of a/2.txt"))
+        self.assertTrue(check("copy of a/3.txt"))
+        self.assertTrue(check("copy of a/foo/bar/baz.txt"))
         checkcontents("copy of a/1.txt")
 
-        self.assert_(check("a/1.txt"))
-        self.assert_(check("a/2.txt"))
-        self.assert_(check("a/3.txt"))
-        self.assert_(check("a/foo/bar/baz.txt"))
+        self.assertTrue(check("a/1.txt"))
+        self.assertTrue(check("a/2.txt"))
+        self.assertTrue(check("a/3.txt"))
+        self.assertTrue(check("a/foo/bar/baz.txt"))
         checkcontents("a/1.txt")
 
         self.assertRaises(DestinationExistsError, self.fs.copydir, "a", "b")
         self.fs.copydir("a", "b", overwrite=True)
-        self.assert_(check("b/1.txt"))
-        self.assert_(check("b/2.txt"))
-        self.assert_(check("b/3.txt"))
-        self.assert_(check("b/foo/bar/baz.txt"))
+        self.assertTrue(check("b/1.txt"))
+        self.assertTrue(check("b/2.txt"))
+        self.assertTrue(check("b/3.txt"))
+        self.assertTrue(check("b/foo/bar/baz.txt"))
         checkcontents("b/1.txt")
 
     def test_copydir_with_dotfile(self):
@@ -724,13 +724,13 @@ class FSTestCases(object):
         makefile("a/.hidden.txt")
 
         self.fs.copydir("a", "copy of a")
-        self.assert_(check("copy of a/1.txt"))
-        self.assert_(check("copy of a/2.txt"))
-        self.assert_(check("copy of a/.hidden.txt"))
+        self.assertTrue(check("copy of a/1.txt"))
+        self.assertTrue(check("copy of a/2.txt"))
+        self.assertTrue(check("copy of a/.hidden.txt"))
 
-        self.assert_(check("a/1.txt"))
-        self.assert_(check("a/2.txt"))
-        self.assert_(check("a/.hidden.txt"))
+        self.assertTrue(check("a/1.txt"))
+        self.assertTrue(check("a/2.txt"))
+        self.assertTrue(check("a/.hidden.txt"))
 
     def test_readwriteappendseek(self):
         def checkcontents(path, check_contents):
@@ -743,7 +743,7 @@ class FSTestCases(object):
         all_strings = b("").join(test_strings)
 
         self.assertRaises(ResourceNotFoundError, self.fs.open, "a.txt", "r")
-        self.assert_(not self.fs.exists("a.txt"))
+        self.assertTrue(not self.fs.exists("a.txt"))
         f1 = self.fs.open("a.txt", "wb")
         pos = 0
         for s in test_strings:
@@ -751,26 +751,26 @@ class FSTestCases(object):
             pos += len(s)
             self.assertEqual(pos, f1.tell())
         f1.close()
-        self.assert_(self.fs.exists("a.txt"))
-        self.assert_(checkcontents("a.txt", all_strings))
+        self.assertTrue(self.fs.exists("a.txt"))
+        self.assertTrue(checkcontents("a.txt", all_strings))
 
         f2 = self.fs.open("b.txt", "wb")
         f2.write(test_strings[0])
         f2.close()
-        self.assert_(checkcontents("b.txt", test_strings[0]))
+        self.assertTrue(checkcontents("b.txt", test_strings[0]))
         f3 = self.fs.open("b.txt", "ab")
         # On win32, tell() gives zero until you actually write to the file
         # self.assertEquals(f3.tell(),len(test_strings[0]))
         f3.write(test_strings[1])
-        self.assertEquals(f3.tell(), len(test_strings[0])+len(test_strings[1]))
+        self.assertEqual(f3.tell(), len(test_strings[0])+len(test_strings[1]))
         f3.write(test_strings[2])
-        self.assertEquals(f3.tell(), len(all_strings))
+        self.assertEqual(f3.tell(), len(all_strings))
         f3.close()
-        self.assert_(checkcontents("b.txt", all_strings))
+        self.assertTrue(checkcontents("b.txt", all_strings))
         f4 = self.fs.open("b.txt", "wb")
         f4.write(test_strings[2])
         f4.close()
-        self.assert_(checkcontents("b.txt", test_strings[2]))
+        self.assertTrue(checkcontents("b.txt", test_strings[2]))
         f5 = self.fs.open("c.txt", "wb")
         for s in test_strings:
             f5.write(s+b("\n"))
@@ -815,7 +815,7 @@ class FSTestCases(object):
         with self.fs.open("hello", "wb") as f:
             f.truncate(30)
 
-        self.assertEquals(self.fs.getsize("hello"), 30)
+        self.assertEqual(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):
@@ -825,7 +825,7 @@ class FSTestCases(object):
 
             with self.fs.open("hello", "rb") as f:
                 f.seek(25)
-                self.assertEquals(f.read(), b("123456"))
+                self.assertEqual(f.read(), b("123456"))
 
     def test_write_past_end_of_file(self):
         if self.fs.getmeta('file.read_and_write', True):
@@ -833,7 +833,7 @@ class FSTestCases(object):
                 f.seek(25)
                 f.write(b("EOF"))
             with self.fs.open("write_at_end", "rb") as f:
-                self.assertEquals(f.read(), b("\x00")*25 + b("EOF"))
+                self.assertEqual(f.read(), b("\x00")*25 + b("EOF"))
 
     def test_with_statement(self):
         #  This is a little tricky since 'with' is actually new syntax.
@@ -856,15 +856,15 @@ class FSTestCases(object):
             code += "    raise ValueError\n"
             code = compile(code, "<string>", 'exec')
             self.assertRaises(ValueError, eval, code, globals(), locals())
-            self.assertEquals(self.fs.getcontents('f.txt', 'rb'), contents)
+            self.assertEqual(self.fs.getcontents('f.txt', 'rb'), contents)
 
     def test_pickling(self):
         if self.fs.getmeta('pickle_contents', True):
             self.fs.setcontents("test1", b("hello world"))
             fs2 = pickle.loads(pickle.dumps(self.fs))
-            self.assert_(fs2.isfile("test1"))
+            self.assertTrue(fs2.isfile("test1"))
             fs3 = pickle.loads(pickle.dumps(self.fs, -1))
-            self.assert_(fs3.isfile("test1"))
+            self.assertTrue(fs3.isfile("test1"))
         else:
             # Just make sure it doesn't throw an exception
             fs2 = pickle.loads(pickle.dumps(self.fs))
@@ -879,9 +879,9 @@ class FSTestCases(object):
             r = random.Random(0)
             randint = r.randint
             int2byte = six.int2byte
-            for _i in xrange(num_chunks):
+            for _i in range(num_chunks):
                 c = b("").join(int2byte(randint(
-                    0, 255)) for _j in xrange(chunk_size//8))
+                    0, 255)) for _j in range(chunk_size//8))
                 yield c * 8
                 f = self.fs.open("bigfile", "wb")
                 try:
@@ -894,7 +894,7 @@ class FSTestCases(object):
                 try:
                     try:
                         while True:
-                            if chunks.next() != f.read(chunk_size):
+                            if next(chunks) != f.read(chunk_size):
                                 assert False, "bigfile was corrupted"
                     except StopIteration:
                         if f.read() != b(""):
@@ -929,9 +929,9 @@ class FSTestCases(object):
         """Test read(0) returns empty string"""
         self.fs.setcontents('foo.txt', b('Hello, World'))
         with self.fs.open('foo.txt', 'rb') as f:
-            self.assert_(len(f.read(0)) == 0)
+            self.assertTrue(len(f.read(0)) == 0)
         with self.fs.open('foo.txt', 'rt') as f:
-            self.assert_(len(f.read(0)) == 0)
+            self.assertTrue(len(f.read(0)) == 0)
 
 # May be disabled - see end of file
 
@@ -977,7 +977,7 @@ class ThreadingTestCases(object):
             for t in threads:
                 t.join()
             for (c, e, t) in errors:
-                raise e, None, t
+                raise e.with_traceback(t)
         finally:
             sys.setcheckinterval(check_interval)
 
@@ -994,12 +994,12 @@ class ThreadingTestCases(object):
         def thread1():
             c = b("thread1 was 'ere")
             setcontents("thread1.txt", c)
-            self.assertEquals(self.fs.getcontents("thread1.txt", 'rb'), c)
+            self.assertEqual(self.fs.getcontents("thread1.txt", 'rb'), c)
 
         def thread2():
             c = b("thread2 was 'ere")
             setcontents("thread2.txt", c)
-            self.assertEquals(self.fs.getcontents("thread2.txt", 'rb'), c)
+            self.assertEqual(self.fs.getcontents("thread2.txt", 'rb'), c)
         self._runThreads(thread1, thread2)
 
     def test_setcontents_threaded_samefile(self):
@@ -1016,19 +1016,19 @@ class ThreadingTestCases(object):
             c = b("thread1 was 'ere")
             setcontents("threads.txt", c)
             self._yield()
-            self.assertEquals(self.fs.listdir("/"), ["threads.txt"])
+            self.assertEqual(self.fs.listdir("/"), ["threads.txt"])
 
         def thread2():
             c = b("thread2 was 'ere")
             setcontents("threads.txt", c)
             self._yield()
-            self.assertEquals(self.fs.listdir("/"), ["threads.txt"])
+            self.assertEqual(self.fs.listdir("/"), ["threads.txt"])
 
         def thread3():
             c = b("thread3 was 'ere")
             setcontents("threads.txt", c)
             self._yield()
-            self.assertEquals(self.fs.listdir("/"), ["threads.txt"])
+            self.assertEqual(self.fs.listdir("/"), ["threads.txt"])
         try:
             self._runThreads(thread1, thread2, thread3)
         except ResourceLockedError:
@@ -1079,23 +1079,23 @@ class ThreadingTestCases(object):
         def makedir():
             try:
                 self.fs.makedir("testdir")
-            except DestinationExistsError, e:
+            except DestinationExistsError as e:
                 errors.append(e)
 
         def makedir_noerror():
             try:
                 self.fs.makedir("testdir", allow_recreate=True)
-            except DestinationExistsError, e:
+            except DestinationExistsError as e:
                 errors.append(e)
 
         def removedir():
             try:
                 self.fs.removedir("testdir")
-            except (ResourceNotFoundError, ResourceLockedError), e:
+            except (ResourceNotFoundError, ResourceLockedError) as e:
                 errors.append(e)
         # One thread should succeed, one should error
         self._runThreads(makedir, makedir)
-        self.assertEquals(len(errors), 1)
+        self.assertEqual(len(errors), 1)
         self.fs.removedir("testdir")
         # One thread should succeed, two should error
         errors = []
@@ -1106,18 +1106,18 @@ class ThreadingTestCases(object):
         # All threads should succeed
         errors = []
         self._runThreads(makedir_noerror, makedir_noerror, makedir_noerror)
-        self.assertEquals(len(errors), 0)
+        self.assertEqual(len(errors), 0)
         self.assertTrue(self.fs.isdir("testdir"))
         self.fs.removedir("testdir")
         # makedir() can beat removedir() and vice-versa
         errors = []
         self._runThreads(makedir, removedir)
         if self.fs.isdir("testdir"):
-            self.assertEquals(len(errors), 1)
+            self.assertEqual(len(errors), 1)
             self.assertFalse(isinstance(errors[0], DestinationExistsError))
             self.fs.removedir("testdir")
         else:
-            self.assertEquals(len(errors), 0)
+            self.assertEqual(len(errors), 0)
 
     def test_concurrent_copydir(self):
         self.fs.makedir("a")
@@ -1136,10 +1136,10 @@ class ThreadingTestCases(object):
         # This should error out since we're not overwriting
         self.assertRaises(
             DestinationExistsError, self._runThreads, copydir, copydir)
-        self.assert_(self.fs.isdir('a'))
-        self.assert_(self.fs.isdir('a'))
+        self.assertTrue(self.fs.isdir('a'))
+        self.assertTrue(self.fs.isdir('a'))
         copydir_overwrite()
-        self.assert_(self.fs.isdir('a'))
+        self.assertTrue(self.fs.isdir('a'))
         # This should run to completion and give a valid state, unless
         # files get locked when written to.
         try:
@@ -1160,19 +1160,19 @@ class ThreadingTestCases(object):
             "contents the second"), b("number three")]
 
         def thread1():
-            for i in xrange(30):
+            for i in range(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(
+                    self.assertEqual(self.fs.getsize("thread1.txt"), len(c))
+                    self.assertEqual(self.fs.getcontents(
                         "thread1.txt", 'rb'), c)
 
         def thread2():
-            for i in xrange(30):
+            for i in range(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(
+                    self.assertEqual(self.fs.getsize("thread2.txt"), len(c))
+                    self.assertEqual(self.fs.getcontents(
                         "thread2.txt", 'rb'), c)
         self._runThreads(thread1, thread2)
 
--- fs/tests/test_archivefs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_archivefs.py
@@ -58,7 +58,7 @@ class TestReadArchiveFS(unittest.TestCase):
             contents = f.read()
             return contents
         def check_contents(path, expected):
-            self.assert_(read_contents(path)==expected)
+            self.assertTrue(read_contents(path)==expected)
         check_contents("a.txt", b("Hello, World!"))
         check_contents("1.txt", b("1"))
         check_contents("foo/bar/baz.txt", b("baz"))
@@ -67,29 +67,29 @@ class TestReadArchiveFS(unittest.TestCase):
         def read_contents(path):
             return self.fs.getcontents(path)
         def check_contents(path, expected):
-            self.assert_(read_contents(path)==expected)
+            self.assertTrue(read_contents(path)==expected)
         check_contents("a.txt", b("Hello, World!"))
         check_contents("1.txt", b("1"))
         check_contents("foo/bar/baz.txt", b("baz"))
 
     def test_is(self):
-        self.assert_(self.fs.isfile('a.txt'))
-        self.assert_(self.fs.isfile('1.txt'))
-        self.assert_(self.fs.isfile('foo/bar/baz.txt'))
-        self.assert_(self.fs.isdir('foo'))
-        self.assert_(self.fs.isdir('foo/bar'))
-        self.assert_(self.fs.exists('a.txt'))
-        self.assert_(self.fs.exists('1.txt'))
-        self.assert_(self.fs.exists('foo/bar/baz.txt'))
-        self.assert_(self.fs.exists('foo'))
-        self.assert_(self.fs.exists('foo/bar'))
+        self.assertTrue(self.fs.isfile('a.txt'))
+        self.assertTrue(self.fs.isfile('1.txt'))
+        self.assertTrue(self.fs.isfile('foo/bar/baz.txt'))
+        self.assertTrue(self.fs.isdir('foo'))
+        self.assertTrue(self.fs.isdir('foo/bar'))
+        self.assertTrue(self.fs.exists('a.txt'))
+        self.assertTrue(self.fs.exists('1.txt'))
+        self.assertTrue(self.fs.exists('foo/bar/baz.txt'))
+        self.assertTrue(self.fs.exists('foo'))
+        self.assertTrue(self.fs.exists('foo/bar'))
 
     def test_listdir(self):
         def check_listing(path, expected):
             dir_list = self.fs.listdir(path)
-            self.assert_(sorted(dir_list) == sorted(expected))
+            self.assertTrue(sorted(dir_list) == sorted(expected))
             for item in dir_list:
-                self.assert_(isinstance(item,unicode))
+                self.assertTrue(isinstance(item,str))
         check_listing('/', ['a.txt', '1.txt', 'foo', 'b.txt'])
         check_listing('foo', ['second.txt', 'bar'])
         check_listing('foo/bar', ['baz.txt'])
@@ -114,7 +114,7 @@ class TestWriteArchiveFS(unittest.TestCase):
 
         makefile("a.txt", b("Hello, World!"))
         makefile("b.txt", b("b"))
-        makefile(u"\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
+        makefile("\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
         makefile("foo/bar/baz.txt", b("baz"))
         makefile("foo/second.txt", b("hai"))
 
@@ -125,7 +125,7 @@ class TestWriteArchiveFS(unittest.TestCase):
 
     def test_valid(self):
         zf = zipfile.ZipFile(self.temp_filename, "r")
-        self.assert_(zf.testzip() is None)
+        self.assertTrue(zf.testzip() is None)
         zf.close()
 
     def test_creation(self):
@@ -140,7 +140,7 @@ class TestWriteArchiveFS(unittest.TestCase):
         check_contents("b.txt", b("b"))
         check_contents("foo/bar/baz.txt", b("baz"))
         check_contents("foo/second.txt", b("hai"))
-        check_contents(u"\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
+        check_contents("\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
 
 
 #~ class TestAppendArchiveFS(TestWriteArchiveFS):
--- fs/tests/test_errors.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_errors.py
@@ -29,4 +29,4 @@ class TestFSError(unittest.TestCase):
 
     def test_unicode_representation_of_error_with_non_ascii_characters(self):
         path_error = PathError('/Shïrê/Frødø')
-        _ = unicode(path_error)
\ No newline at end of file
+        _ = str(path_error)
--- fs/tests/test_expose.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_expose.py
@@ -149,7 +149,7 @@ if dokan.is_available:
 
         def tearDown(self):
             self.mount_proc.unmount()
-            for _ in xrange(10):
+            for _ in range(10):
                 try:
                     if self.mount_proc.poll() is None:
                         self.mount_proc.terminate()
--- fs/tests/test_fs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_fs.py
@@ -20,7 +20,7 @@ from fs import osfs
 class TestOSFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
 
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest")
+        self.temp_dir = tempfile.mkdtemp("fstest")
         self.fs = osfs.OSFS(self.temp_dir)
 
     def tearDown(self):
@@ -35,14 +35,14 @@ class TestOSFS(unittest.TestCase,FSTestCases,Threading
 
         self.assertRaises(errors.InvalidCharsInPathError, self.fs.open, 'invalid\0file', 'wb')
         self.assertFalse(self.fs.isvalidpath('invalid\0file'))
-        self.assert_(self.fs.isvalidpath('validfile'))
-        self.assert_(self.fs.isvalidpath('completely_valid/path/foo.bar'))
+        self.assertTrue(self.fs.isvalidpath('validfile'))
+        self.assertTrue(self.fs.isvalidpath('completely_valid/path/foo.bar'))
 
 
 class TestSubFS(unittest.TestCase,FSTestCases,ThreadingTestCases):
 
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest")
+        self.temp_dir = tempfile.mkdtemp("fstest")
         self.parent_fs = osfs.OSFS(self.temp_dir)
         self.parent_fs.makedir("foo/bar", recursive=True)
         self.fs = self.parent_fs.opendir("foo/bar")
@@ -118,7 +118,7 @@ class TestTempFS(unittest.TestCase,FSTestCases,Threadi
     def tearDown(self):
         td = self.fs._temp_dir
         self.fs.close()
-        self.assert_(not os.path.exists(td))
+        self.assertTrue(not os.path.exists(td))
 
     def check(self, p):
         td = self.fs._temp_dir
@@ -129,5 +129,5 @@ class TestTempFS(unittest.TestCase,FSTestCases,Threadi
 
         self.assertRaises(errors.InvalidCharsInPathError, self.fs.open, 'invalid\0file', 'wb')
         self.assertFalse(self.fs.isvalidpath('invalid\0file'))
-        self.assert_(self.fs.isvalidpath('validfile'))
-        self.assert_(self.fs.isvalidpath('completely_valid/path/foo.bar'))
+        self.assertTrue(self.fs.isvalidpath('validfile'))
+        self.assertTrue(self.fs.isvalidpath('completely_valid/path/foo.bar'))
--- fs/tests/test_ftpfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_ftpfs.py
@@ -10,7 +10,7 @@ import tempfile
 import subprocess
 import time
 from os.path import abspath
-import urllib
+import urllib.request, urllib.parse, urllib.error
 
 from six import PY3
 
@@ -37,7 +37,7 @@ class TestFTPFS(unittest.TestCase, FSTestCases, Thread
         ftp_port += 1
         use_port = str(ftp_port)
         #ftp_port = 10000
-        self.temp_dir = tempfile.mkdtemp(u"ftpfstests")
+        self.temp_dir = tempfile.mkdtemp("ftpfstests")
 
         file_path = __file__
         if ':' not in file_path:
@@ -58,7 +58,7 @@ class TestFTPFS(unittest.TestCase, FSTestCases, Thread
         start_time = time.time()
         while time.time() - start_time < 5:
             try:
-                ftpurl = urllib.urlopen('ftp://127.0.0.1:%s' % use_port)
+                ftpurl = urllib.request.urlopen('ftp://127.0.0.1:%s' % use_port)
             except IOError:
                 time.sleep(0)
             else:
--- fs/tests/test_importhook.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_importhook.py
@@ -25,7 +25,7 @@ class TestFSImportHook(unittest.TestCase):
         for ph in list(sys.path_hooks):
             if issubclass(ph,FSImportHook):
                 sys.path_hooks.remove(mph)
-        for (k,v) in sys.modules.items():
+        for (k,v) in list(sys.modules.items()):
             if k.startswith("fsih_"):
                 del sys.modules[k]
             elif hasattr(v,"__loader__"):
@@ -64,22 +64,22 @@ class TestFSImportHook(unittest.TestCase):
         ih = FSImportHook(t)
         sys.meta_path.append(ih)
         try:
-            self.assertEquals(ih.find_module("fsih_hello"),ih)
-            self.assertEquals(ih.find_module("fsih_helo"),None)
-            self.assertEquals(ih.find_module("fsih_pkg"),ih)
-            self.assertEquals(ih.find_module("fsih_pkg.sub1"),ih)
-            self.assertEquals(ih.find_module("fsih_pkg.sub2"),ih)
-            self.assertEquals(ih.find_module("fsih_pkg.sub3"),None)
+            self.assertEqual(ih.find_module("fsih_hello"),ih)
+            self.assertEqual(ih.find_module("fsih_helo"),None)
+            self.assertEqual(ih.find_module("fsih_pkg"),ih)
+            self.assertEqual(ih.find_module("fsih_pkg.sub1"),ih)
+            self.assertEqual(ih.find_module("fsih_pkg.sub2"),ih)
+            self.assertEqual(ih.find_module("fsih_pkg.sub3"),None)
             m = ih.load_module("fsih_hello")
-            self.assertEquals(m.message,"hello world!")
+            self.assertEqual(m.message,"hello world!")
             self.assertRaises(ImportError,ih.load_module,"fsih_helo")
             ih.load_module("fsih_pkg")
             m = ih.load_module("fsih_pkg.sub1")
-            self.assertEquals(m.message,"hello world!")
-            self.assertEquals(m.a,42)
+            self.assertEqual(m.message,"hello world!")
+            self.assertEqual(m.a,42)
             m = ih.load_module("fsih_pkg.sub2")
-            self.assertEquals(m.message,"hello world!")
-            self.assertEquals(m.a,42 * 2)
+            self.assertEqual(m.message,"hello world!")
+            self.assertEqual(m.a,42 * 2)
             self.assertRaises(ImportError,ih.load_module,"fsih_pkg.sub3")
         finally:
             sys.meta_path.remove(ih)
@@ -88,7 +88,7 @@ class TestFSImportHook(unittest.TestCase):
     def _check_imports_are_working(self):
         try:
             import fsih_hello
-            self.assertEquals(fsih_hello.message,"hello world!")
+            self.assertEqual(fsih_hello.message,"hello world!")
             try:
                 import fsih_helo
             except ImportError:
@@ -97,11 +97,11 @@ class TestFSImportHook(unittest.TestCase):
                 assert False, "ImportError not raised"
             import fsih_pkg
             import fsih_pkg.sub1
-            self.assertEquals(fsih_pkg.sub1.message,"hello world!")
-            self.assertEquals(fsih_pkg.sub1.a,42)
+            self.assertEqual(fsih_pkg.sub1.message,"hello world!")
+            self.assertEqual(fsih_pkg.sub1.a,42)
             import fsih_pkg.sub2
-            self.assertEquals(fsih_pkg.sub2.message,"hello world!")
-            self.assertEquals(fsih_pkg.sub2.a,42 * 2)
+            self.assertEqual(fsih_pkg.sub2.message,"hello world!")
+            self.assertEqual(fsih_pkg.sub2.a,42 * 2)
             try:
                 import fsih_pkg.sub3
             except ImportError:
@@ -109,7 +109,7 @@ class TestFSImportHook(unittest.TestCase):
             else:
                 assert False, "ImportError not raised"
         finally:
-            for k in sys.modules.keys():
+            for k in list(sys.modules.keys()):
                 if k.startswith("fsih_"):
                     del sys.modules[k]
 
--- fs/tests/test_iotools.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_iotools.py
@@ -1,5 +1,5 @@
-from __future__ import unicode_literals
 
+
 from fs import iotools
 
 import io
@@ -7,9 +7,9 @@ import unittest
 from os.path import dirname, join, abspath
 
 try:
-    unicode
+    str
 except NameError:
-    unicode = str
+    str = str
 
 
 class OpenFilelike(object):
@@ -37,20 +37,20 @@ class TestIOTools(unittest.TestCase):
         """Test make_stream"""
         with self.get_bin_file() as f:
             text = f.read()
-            self.assert_(isinstance(text, bytes))
+            self.assertTrue(isinstance(text, bytes))
 
         with self.get_bin_file() as f:
             with iotools.make_stream("data/UTF-8-demo.txt", f, 'rt') as f2:
                 text = f2.read()
-                self.assert_(isinstance(text, unicode))
+                self.assertTrue(isinstance(text, str))
 
     def test_decorator(self):
         """Test filelike_to_stream decorator"""
         o = OpenFilelike(self.get_bin_file)
         with o.open('file', 'rb') as f:
             text = f.read()
-            self.assert_(isinstance(text, bytes))
+            self.assertTrue(isinstance(text, bytes))
 
         with o.open('file', 'rt') as f:
             text = f.read()
-            self.assert_(isinstance(text, unicode))
+            self.assertTrue(isinstance(text, str))
--- fs/tests/test_mountfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_mountfs.py
@@ -12,11 +12,11 @@ class TestMountFS(unittest.TestCase):
         m2 = MemoryFS()
         multi_fs.mount('/m1', m1)
         multi_fs.mount('/m2', m2)
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
         multi_fs.close()
-        self.assert_(m1.closed)
-        self.assert_(m2.closed)
+        self.assertTrue(m1.closed)
+        self.assertTrue(m2.closed)
 
     def test_no_auto_close(self):
         """Test MountFS auto close can be disabled"""
@@ -25,11 +25,11 @@ class TestMountFS(unittest.TestCase):
         m2 = MemoryFS()
         multi_fs.mount('/m1', m1)
         multi_fs.mount('/m2', m2)
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
         multi_fs.close()
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
 
     def test_mountfile(self):
         """Test mounting a file"""
@@ -42,16 +42,16 @@ class TestMountFS(unittest.TestCase):
         mount_fs = MountFS()
         mount_fs.mountfile('bar.txt', foo_dir.open, foo_dir.getinfo)
 
-        self.assert_(mount_fs.isdir('/'))
-        self.assert_(mount_fs.isdir('./'))
-        self.assert_(mount_fs.isdir(''))
+        self.assertTrue(mount_fs.isdir('/'))
+        self.assertTrue(mount_fs.isdir('./'))
+        self.assertTrue(mount_fs.isdir(''))
 
         # Check we can see the mounted file in the dir list
         self.assertEqual(mount_fs.listdir(), ["bar.txt"])
-        self.assert_(not mount_fs.exists('nobodyhere.txt'))
-        self.assert_(mount_fs.exists('bar.txt'))
-        self.assert_(mount_fs.isfile('bar.txt'))
-        self.assert_(not mount_fs.isdir('bar.txt'))
+        self.assertTrue(not mount_fs.exists('nobodyhere.txt'))
+        self.assertTrue(mount_fs.exists('bar.txt'))
+        self.assertTrue(mount_fs.isfile('bar.txt'))
+        self.assertTrue(not mount_fs.isdir('bar.txt'))
 
         # Check open and getinfo callables
         self.assertEqual(mount_fs.getcontents('bar.txt'), quote)
@@ -67,9 +67,9 @@ class TestMountFS(unittest.TestCase):
         self.assertEqual(mem_fs.getsize('foo/bar.txt'), len('baz'))
 
         # Check unmount
-        self.assert_(mount_fs.unmount("bar.txt"))
+        self.assertTrue(mount_fs.unmount("bar.txt"))
         self.assertEqual(mount_fs.listdir(), [])
-        self.assert_(not mount_fs.exists('bar.txt'))
+        self.assertTrue(not mount_fs.exists('bar.txt'))
 
         # Check unount a second time is a null op, and returns False
         self.assertFalse(mount_fs.unmount("bar.txt"))
--- fs/tests/test_multifs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_multifs.py
@@ -13,11 +13,11 @@ class TestMultiFS(unittest.TestCase):
         m2 = MemoryFS()
         multi_fs.addfs('m1', m1)
         multi_fs.addfs('m2', m2)
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
         multi_fs.close()
-        self.assert_(m1.closed)
-        self.assert_(m2.closed)
+        self.assertTrue(m1.closed)
+        self.assertTrue(m2.closed)
         
     def test_no_auto_close(self):
         """Test MultiFS auto close can be disables"""
@@ -26,11 +26,11 @@ class TestMultiFS(unittest.TestCase):
         m2 = MemoryFS()
         multi_fs.addfs('m1', m1)
         multi_fs.addfs('m2', m2)
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
         multi_fs.close()
-        self.assert_(not m1.closed)
-        self.assert_(not m2.closed)
+        self.assertTrue(not m1.closed)
+        self.assertTrue(not m2.closed)
     
     
     def test_priority(self):
@@ -45,7 +45,7 @@ class TestMultiFS(unittest.TestCase):
         multi_fs.addfs("m1", m1)
         multi_fs.addfs("m2", m2)
         multi_fs.addfs("m3", m3)
-        self.assert_(multi_fs.getcontents("name") == b("m3"))
+        self.assertTrue(multi_fs.getcontents("name") == b("m3"))
         
         m1 = MemoryFS()
         m2 = MemoryFS()
@@ -57,7 +57,7 @@ class TestMultiFS(unittest.TestCase):
         multi_fs.addfs("m1", m1)
         multi_fs.addfs("m2", m2, priority=10)
         multi_fs.addfs("m3", m3)
-        self.assert_(multi_fs.getcontents("name") == b("m2"))        
+        self.assertTrue(multi_fs.getcontents("name") == b("m2"))        
         
         m1 = MemoryFS()
         m2 = MemoryFS()
@@ -69,7 +69,7 @@ class TestMultiFS(unittest.TestCase):
         multi_fs.addfs("m1", m1)
         multi_fs.addfs("m2", m2, priority=10)
         multi_fs.addfs("m3", m3, priority=10)
-        self.assert_(multi_fs.getcontents("name") == b("m3"))
+        self.assertTrue(multi_fs.getcontents("name") == b("m3"))
         
         m1 = MemoryFS()
         m2 = MemoryFS()
@@ -81,5 +81,5 @@ class TestMultiFS(unittest.TestCase):
         multi_fs.addfs("m1", m1, priority=11)
         multi_fs.addfs("m2", m2, priority=10)
         multi_fs.addfs("m3", m3, priority=10)
-        self.assert_(multi_fs.getcontents("name") == b("m1"))
+        self.assertTrue(multi_fs.getcontents("name") == b("m1"))
         
--- fs/tests/test_opener.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_opener.py
@@ -14,7 +14,7 @@ from fs import path
 class TestOpener(unittest.TestCase):
 
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest_opener")
+        self.temp_dir = tempfile.mkdtemp("fstest_opener")
 
     def tearDown(self):
         shutil.rmtree(self.temp_dir)
--- fs/tests/test_path.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_path.py
@@ -23,7 +23,7 @@ class TestPathFunctions(unittest.TestCase):
                     ("a/b/c", "a/b/c"),
                     ("a/b/../c/", "a/c"),
                     ("/","/"),
-                    (u"a/\N{GREEK SMALL LETTER BETA}/c",u"a/\N{GREEK SMALL LETTER BETA}/c"),
+                    ("a/\N{GREEK SMALL LETTER BETA}/c","a/\N{GREEK SMALL LETTER BETA}/c"),
                     ]
         for path, result in tests:
             self.assertEqual(normpath(path), result)
@@ -44,7 +44,7 @@ class TestPathFunctions(unittest.TestCase):
                     ("a/b", "./d", "e", "a/b/d/e"),
                     ("/", "/", "/"),
                     ("/", "", "/"),
-                    (u"a/\N{GREEK SMALL LETTER BETA}","c",u"a/\N{GREEK SMALL LETTER BETA}/c"),
+                    ("a/\N{GREEK SMALL LETTER BETA}","c","a/\N{GREEK SMALL LETTER BETA}/c"),
         ]
         for testpaths in tests:
             paths = testpaths[:-1]
@@ -101,12 +101,12 @@ class TestPathFunctions(unittest.TestCase):
             self.assertEqual(pathsplit(path), result)
 
     def test_recursepath(self):
-        self.assertEquals(recursepath("/"),["/"])
-        self.assertEquals(recursepath("hello"),["/","/hello"])
-        self.assertEquals(recursepath("/hello/world/"),["/","/hello","/hello/world"])
-        self.assertEquals(recursepath("/hello/world/",reverse=True),["/hello/world","/hello","/"])
-        self.assertEquals(recursepath("hello",reverse=True),["/hello","/"])
-        self.assertEquals(recursepath("",reverse=True),["/"])
+        self.assertEqual(recursepath("/"),["/"])
+        self.assertEqual(recursepath("hello"),["/","/hello"])
+        self.assertEqual(recursepath("/hello/world/"),["/","/hello","/hello/world"])
+        self.assertEqual(recursepath("/hello/world/",reverse=True),["/hello/world","/hello","/"])
+        self.assertEqual(recursepath("hello",reverse=True),["/hello","/"])
+        self.assertEqual(recursepath("",reverse=True),["/"])
 
     def test_isdotfile(self):
         for path in ['.foo',
@@ -114,7 +114,7 @@ class TestPathFunctions(unittest.TestCase):
                      'foo/.svn',
                      'foo/bar/.svn',
                      '/foo/.bar']:
-            self.assert_(isdotfile(path))
+            self.assertTrue(isdotfile(path))
 
         for path in ['asfoo',
                      'df.svn',
@@ -142,10 +142,10 @@ class TestPathFunctions(unittest.TestCase):
             self.assertEqual(basename(path), test_basename)
 
     def test_iswildcard(self):
-        self.assert_(iswildcard('*'))
-        self.assert_(iswildcard('*.jpg'))
-        self.assert_(iswildcard('foo/*'))
-        self.assert_(iswildcard('foo/{}'))
+        self.assertTrue(iswildcard('*'))
+        self.assertTrue(iswildcard('*.jpg'))
+        self.assertTrue(iswildcard('foo/*'))
+        self.assertTrue(iswildcard('foo/{}'))
         self.assertFalse(iswildcard('foo'))
         self.assertFalse(iswildcard('img.jpg'))
         self.assertFalse(iswildcard('foo/bar'))
@@ -171,9 +171,9 @@ class Test_PathMap(unittest.TestCase):
     def test_basics(self):
         map = PathMap()
         map["hello"] = "world"
-        self.assertEquals(map["/hello"],"world")
-        self.assertEquals(map["/hello/"],"world")
-        self.assertEquals(map.get("hello"),"world")
+        self.assertEqual(map["/hello"],"world")
+        self.assertEqual(map["/hello/"],"world")
+        self.assertEqual(map.get("hello"),"world")
 
     def test_iteration(self):
         map = PathMap()
@@ -183,17 +183,17 @@ class Test_PathMap(unittest.TestCase):
         map["hello/kitty"] = 4
         map["hello/kitty/islame"] = 5
         map["batman/isawesome"] = 6
-        self.assertEquals(set(map.iterkeys()),set(("/hello/world","/hello/world/howareya","/hello/world/iamfine","/hello/kitty","/hello/kitty/islame","/batman/isawesome")))
-        self.assertEquals(sorted(map.values()),range(1,7))
-        self.assertEquals(sorted(map.items("/hello/world/")),[("/hello/world",1),("/hello/world/howareya",2),("/hello/world/iamfine",3)])
-        self.assertEquals(zip(map.keys(),map.values()),map.items())
-        self.assertEquals(zip(map.keys("batman"),map.values("batman")),map.items("batman"))
-        self.assertEquals(set(map.iternames("hello")),set(("world","kitty")))
-        self.assertEquals(set(map.iternames("/hello/kitty")),set(("islame",)))
+        self.assertEqual(set(map.keys()),set(("/hello/world","/hello/world/howareya","/hello/world/iamfine","/hello/kitty","/hello/kitty/islame","/batman/isawesome")))
+        self.assertEqual(sorted(map.values()),list(range(1,7)))
+        self.assertEqual(sorted(map.items("/hello/world/")),[("/hello/world",1),("/hello/world/howareya",2),("/hello/world/iamfine",3)])
+        self.assertEqual(list(zip(list(map.keys()),list(map.values()))),list(map.items()))
+        self.assertEqual(list(zip(map.keys("batman"),map.values("batman"))),map.items("batman"))
+        self.assertEqual(set(map.iternames("hello")),set(("world","kitty")))
+        self.assertEqual(set(map.iternames("/hello/kitty")),set(("islame",)))
 
         del map["hello/kitty/islame"]
-        self.assertEquals(set(map.iternames("/hello/kitty")),set())
-        self.assertEquals(set(map.iterkeys()),set(("/hello/world","/hello/world/howareya","/hello/world/iamfine","/hello/kitty","/batman/isawesome")))
-        self.assertEquals(set(map.values()),set(range(1,7)) - set((5,)))
+        self.assertEqual(set(map.iternames("/hello/kitty")),set())
+        self.assertEqual(set(map.keys()),set(("/hello/world","/hello/world/howareya","/hello/world/iamfine","/hello/kitty","/batman/isawesome")))
+        self.assertEqual(set(map.values()),set(range(1,7)) - set((5,)))
 
 
--- fs/tests/test_remote.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_remote.py
@@ -116,37 +116,37 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCa
         self.fakeOn()
 
         f = self.fs.open('test.txt', 'rb')
-        self.assertEquals(f.read(10), contents[:10])
+        self.assertEqual(f.read(10), contents[:10])
         f.wrapped_file.seek(0, SEEK_END)
-        self.assertEquals(f._rfile.tell(), 10)
+        self.assertEqual(f._rfile.tell(), 10)
         f.seek(20)
-        self.assertEquals(f.tell(), 20)
-        self.assertEquals(f._rfile.tell(), 20)
+        self.assertEqual(f.tell(), 20)
+        self.assertEqual(f._rfile.tell(), 20)
         f.seek(0, SEEK_END)
-        self.assertEquals(f._rfile.tell(), len(contents))
+        self.assertEqual(f._rfile.tell(), len(contents))
         f.close()
 
         f = self.fs.open('test.txt', 'ab')
-        self.assertEquals(f.tell(), len(contents))
+        self.assertEqual(f.tell(), len(contents))
         f.close()
 
         self.fakeOff()
 
         # Writing over the rfile edge
         f = self.fs.open('test.txt', 'wb+')
-        self.assertEquals(f.tell(), 0)
+        self.assertEqual(f.tell(), 0)
         f.seek(len(contents) - 5)
         # Last 5 characters not loaded from remote file
-        self.assertEquals(f._rfile.tell(), len(contents) - 5)
+        self.assertEqual(f._rfile.tell(), len(contents) - 5)
         # Confirm that last 5 characters are still in rfile buffer
-        self.assertEquals(f._rfile.read(), contents[-5:])
+        self.assertEqual(f._rfile.read(), contents[-5:])
         # 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(b('1234567890'))
         f.flush()
         # We are on the end of file (and buffer not serve anything anymore)
-        self.assertEquals(f.read(), b(''))
+        self.assertEqual(f.read(), b(''))
         f.close()
 
         self.fakeOn()
@@ -154,7 +154,7 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCa
         # 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] + b('1234567890'))
+        self.assertEqual(f.read(), contents[:-5] + b('1234567890'))
         f.close()
 
         self.fakeOff()
@@ -199,36 +199,36 @@ class TestRemoteFileBuffer(unittest.TestCase, FSTestCa
 
         f = self.fs.open('test.txt', 'rb+')
         # Check if we read just 10 characters
-        self.assertEquals(f.read(10), contents[:10])
-        self.assertEquals(f._rfile.tell(), 10)
+        self.assertEqual(f.read(10), contents[:10])
+        self.assertEqual(f._rfile.tell(), 10)
         # Write garbage to file to mark it as _changed
         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] + b('x') + contents[11:])
+        self.assertEqual(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] + b('x') + contents[11:])
+        self.assertEqual(f.read(), contents[:10] + b('x') + contents[11:])
         f.close()
 
         # Now try it again, but write garbage behind edge of remote file
         f = self.fs.open('test.txt', 'rb+')
-        self.assertEquals(f.read(10), contents[:10])
+        self.assertEqual(f.read(10), contents[:10])
         # Write garbage to file to mark it as _changed
         f.write(contents2)
         f.flush()
         f.seek(0)
         # Try if we have unocrrupted file locally...
-        self.assertEquals(f.read(), contents[:10] + contents2)
+        self.assertEqual(f.read(), contents[:10] + contents2)
         f.close()
 
         # And if we have uncorrupted file also on storage
         f = self.fs.open('test.txt', 'rb')
-        self.assertEquals(f.read(), contents[:10] + contents2)
+        self.assertEqual(f.read(), contents[:10] + contents2)
         f.close()
 
 
--- fs/tests/test_rpcfs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/tests/test_rpcfs.py
@@ -48,7 +48,7 @@ class TestRPCFS(unittest.TestCase, FSTestCases, Thread
         while not self.server:
             try:
                 self.server = self.makeServer(self.temp_fs,("127.0.0.1",port))
-            except socket.error, e:
+            except socket.error as e:
                 if e.args[1] == "Address already in use":
                     port += 1
                 else:
@@ -63,7 +63,7 @@ class TestRPCFS(unittest.TestCase, FSTestCases, Thread
             #self.server.serve_forever()
             while self.serve_more_requests:
                 self.server.handle_request()
-        except Exception, e:
+        except Exception as e:
             pass
 
         self.end_event.set()
@@ -93,7 +93,7 @@ class TestRPCFS(unittest.TestCase, FSTestCases, Thread
                 sock.settimeout(.1)
                 sock.connect(sa)
                 sock.send(b("\n"))
-            except socket.error, e:
+            except socket.error as e:
                 pass
             finally:
                 if sock is not None:
--- fs/tests/test_utils.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_utils.py
@@ -16,11 +16,11 @@ class TestUtils(unittest.TestCase):
         fs.setcontents("foo/bar/fruit", b("apple"))
         
     def _check_fs(self, fs):
-        self.assert_(fs.isfile("f1"))
-        self.assert_(fs.isfile("f2"))
-        self.assert_(fs.isfile("f3"))
-        self.assert_(fs.isdir("foo/bar"))
-        self.assert_(fs.isfile("foo/bar/fruit"))
+        self.assertTrue(fs.isfile("f1"))
+        self.assertTrue(fs.isfile("f2"))
+        self.assertTrue(fs.isfile("f3"))
+        self.assertTrue(fs.isdir("foo/bar"))
+        self.assertTrue(fs.isfile("foo/bar/fruit"))
         self.assertEqual(fs.getcontents("f1", "rb"), b("file 1"))
         self.assertEqual(fs.getcontents("f2", "rb"), b("file 2"))
         self.assertEqual(fs.getcontents("f3", "rb"), b("file 3"))
@@ -61,7 +61,7 @@ class TestUtils(unittest.TestCase):
         fs1sub = fs1.makeopendir("from")
         self._make_fs(fs1sub)            
         utils.movedir((fs1, "from"), (fs2, "copy"))        
-        self.assert_(not fs1.exists("from"))     
+        self.assertTrue(not fs1.exists("from"))     
         self._check_fs(fs2.opendir("copy"))
 
         fs1 = TempFS()
@@ -69,7 +69,7 @@ class TestUtils(unittest.TestCase):
         fs1sub = fs1.makeopendir("from")
         self._make_fs(fs1sub)            
         utils.movedir((fs1, "from"), (fs2, "copy"))
-        self.assert_(not fs1.exists("from"))      
+        self.assertTrue(not fs1.exists("from"))      
         self._check_fs(fs2.opendir("copy"))
         
     def test_movedir_root(self):
@@ -79,7 +79,7 @@ class TestUtils(unittest.TestCase):
         fs1sub = fs1.makeopendir("from")
         self._make_fs(fs1sub)            
         utils.movedir((fs1, "from"), fs2)
-        self.assert_(not fs1.exists("from"))     
+        self.assertTrue(not fs1.exists("from"))     
         self._check_fs(fs2)
 
         fs1 = TempFS()
@@ -87,7 +87,7 @@ class TestUtils(unittest.TestCase):
         fs1sub = fs1.makeopendir("from")
         self._make_fs(fs1sub)            
         utils.movedir((fs1, "from"), fs2)
-        self.assert_(not fs1.exists("from"))        
+        self.assertTrue(not fs1.exists("from"))        
         self._check_fs(fs2)
         
     def test_remove_all(self):
@@ -101,15 +101,15 @@ class TestUtils(unittest.TestCase):
         fs.setcontents("foo/baz", b("baz"))
         
         utils.remove_all(fs, "foo/bar")
-        self.assert_(not fs.exists("foo/bar/fruit"))
-        self.assert_(fs.exists("foo/bar"))
-        self.assert_(fs.exists("foo/baz"))
+        self.assertTrue(not fs.exists("foo/bar/fruit"))
+        self.assertTrue(fs.exists("foo/bar"))
+        self.assertTrue(fs.exists("foo/baz"))
         utils.remove_all(fs,  "")
-        self.assert_(not fs.exists("foo/bar/fruit"))
-        self.assert_(not fs.exists("foo/bar/baz"))
-        self.assert_(not fs.exists("foo/baz"))
-        self.assert_(not fs.exists("foo"))
-        self.assert_(not fs.exists("f1"))
-        self.assert_(fs.isdirempty('/'))
+        self.assertTrue(not fs.exists("foo/bar/fruit"))
+        self.assertTrue(not fs.exists("foo/bar/baz"))
+        self.assertTrue(not fs.exists("foo/baz"))
+        self.assertTrue(not fs.exists("foo"))
+        self.assertTrue(not fs.exists("f1"))
+        self.assertTrue(fs.isdirempty('/'))
     
     
--- fs/tests/test_watch.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_watch.py
@@ -71,7 +71,7 @@ class WatcherTestCases:
         for event in event_list:
             if isinstance(event,cls):
                 if path is None or event.path == path:
-                    for (k,v) in attrs.iteritems():
+                    for (k,v) in attrs.items():
                         if getattr(event,k) != v:
                             break
                     else:
@@ -98,7 +98,7 @@ class WatcherTestCases:
         self.assertEventOccurred(CREATED,"/hello")
         self.clearCapturedEvents()
         old_atime = self.fs.getinfo("hello").get("accessed_time")
-        self.assertEquals(self.fs.getcontents("hello"), b("hello world"))
+        self.assertEqual(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?
@@ -113,7 +113,7 @@ class WatcherTestCases:
             #  update it if it's too old, or don't update it at all!
             #  Try to force the issue, wait for it to change, but eventually
             #  give up and bail out.
-            for i in xrange(10):
+            for i in range(10):
                 if self.fs.getinfo("hello").get("accessed_time") != old_atime:
                     if not self.checkEventOccurred(MODIFIED,"/hello"):
                         self.assertEventOccurred(ACCESSED,"/hello")
@@ -142,7 +142,7 @@ class WatcherTestCases:
         self.waitForEvents()
         for evt in events:
             assert isinstance(evt,MODIFIED)
-            self.assertEquals(evt.path,"/hello")
+            self.assertEqual(evt.path,"/hello")
 
     def test_watch_single_file_remove(self):
         self.fs.makedir("testing")
@@ -153,9 +153,9 @@ class WatcherTestCases:
         self.waitForEvents()
         self.fs.remove("testing/hello")
         self.waitForEvents()
-        self.assertEquals(len(events),1)
+        self.assertEqual(len(events),1)
         assert isinstance(events[0],REMOVED)
-        self.assertEquals(events[0].path,"/testing/hello")
+        self.assertEqual(events[0].path,"/testing/hello")
 
     def test_watch_iter_changes(self):
         changes = iter_changes(self.watchfs)
@@ -195,9 +195,9 @@ class TestWatchers_TempFS(unittest.TestCase,FSTestCase
         watchfs = osfs.OSFS(self.fs.root_path)
         self.watchfs = ensure_watchable(watchfs,poll_interval=0.1)
         if watch_inotify is not None:
-            self.assertEquals(watchfs,self.watchfs)
+            self.assertEqual(watchfs,self.watchfs)
         if watch_win32 is not None:
-            self.assertEquals(watchfs,self.watchfs)
+            self.assertEqual(watchfs,self.watchfs)
 
     def tearDown(self):
         self.watchfs.close()
--- fs/tests/test_wrapfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_wrapfs.py
@@ -26,7 +26,7 @@ class TestWrapFS(unittest.TestCase, FSTestCases, Threa
     #__test__ = False
     
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest")
+        self.temp_dir = tempfile.mkdtemp("fstest")
         self.fs = wrapfs.WrapFS(osfs.OSFS(self.temp_dir))
 
     def tearDown(self):
@@ -41,7 +41,7 @@ from fs.wrapfs.lazyfs import LazyFS
 class TestLazyFS(unittest.TestCase, FSTestCases, ThreadingTestCases):
     
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest")
+        self.temp_dir = tempfile.mkdtemp("fstest")
         self.fs = LazyFS((osfs.OSFS,(self.temp_dir,)))
 
     def tearDown(self):
@@ -63,13 +63,13 @@ class TestLimitSizeFS(TestWrapFS):
 
     def tearDown(self):
         remove_all(self.fs, "/")
-        self.assertEquals(self.fs.cur_size,0)
+        self.assertEqual(self.fs.cur_size,0)
         super(TestLimitSizeFS,self).tearDown()
         self.fs.close()
 
     def test_storage_error(self):
         total_written = 0
-        for i in xrange(1024*2):
+        for i in range(1024*2):
             try:
                 total_written += 1030
                 self.fs.setcontents("file %i" % i, b("C")*1030)
@@ -85,11 +85,11 @@ from fs.wrapfs.hidedotfilesfs import HideDotFilesFS
 class TestHideDotFilesFS(unittest.TestCase):
 
     def setUp(self):
-        self.temp_dir = tempfile.mkdtemp(u"fstest")
-        open(os.path.join(self.temp_dir, u".dotfile"), 'w').close()
-        open(os.path.join(self.temp_dir, u"regularfile"), 'w').close()
-        os.mkdir(os.path.join(self.temp_dir, u".dotdir"))
-        os.mkdir(os.path.join(self.temp_dir, u"regulardir"))
+        self.temp_dir = tempfile.mkdtemp("fstest")
+        open(os.path.join(self.temp_dir, ".dotfile"), 'w').close()
+        open(os.path.join(self.temp_dir, "regularfile"), 'w').close()
+        os.mkdir(os.path.join(self.temp_dir, ".dotdir"))
+        os.mkdir(os.path.join(self.temp_dir, "regulardir"))
         self.fs = HideDotFilesFS(osfs.OSFS(self.temp_dir))
 
     def tearDown(self):
@@ -97,15 +97,15 @@ class TestHideDotFilesFS(unittest.TestCase):
         self.fs.close()
 
     def test_hidden(self):
-        self.assertEquals(len(self.fs.listdir(hidden=False)), 2)
-        self.assertEquals(len(list(self.fs.ilistdir(hidden=False))), 2)
+        self.assertEqual(len(self.fs.listdir(hidden=False)), 2)
+        self.assertEqual(len(list(self.fs.ilistdir(hidden=False))), 2)
 
     def test_nonhidden(self):
-        self.assertEquals(len(self.fs.listdir(hidden=True)), 4)
-        self.assertEquals(len(list(self.fs.ilistdir(hidden=True))), 4)
+        self.assertEqual(len(self.fs.listdir(hidden=True)), 4)
+        self.assertEqual(len(list(self.fs.ilistdir(hidden=True))), 4)
 
     def test_default(self):
-        self.assertEquals(len(self.fs.listdir()), 2)
-        self.assertEquals(len(list(self.fs.ilistdir())), 2)
+        self.assertEqual(len(self.fs.listdir()), 2)
+        self.assertEqual(len(list(self.fs.ilistdir())), 2)
 
 
--- fs/tests/test_xattr.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_xattr.py
@@ -37,19 +37,19 @@ class XAttrTestCases:
 
     def test_list_xattrs(self):
         def do_list(p):
-            self.assertEquals(sorted(self.fs.listxattrs(p)),[])
+            self.assertEqual(sorted(self.fs.listxattrs(p)),[])
             self.fs.setxattr(p,"xattr1","value1")
-            self.assertEquals(self.fs.getxattr(p,"xattr1"),"value1")
-            self.assertEquals(sorted(self.fs.listxattrs(p)),["xattr1"])
-            self.assertTrue(isinstance(self.fs.listxattrs(p)[0],unicode))
+            self.assertEqual(self.fs.getxattr(p,"xattr1"),"value1")
+            self.assertEqual(sorted(self.fs.listxattrs(p)),["xattr1"])
+            self.assertTrue(isinstance(self.fs.listxattrs(p)[0],str))
             self.fs.setxattr(p,"attr2","value2")
-            self.assertEquals(sorted(self.fs.listxattrs(p)),["attr2","xattr1"])
-            self.assertTrue(isinstance(self.fs.listxattrs(p)[0],unicode))
-            self.assertTrue(isinstance(self.fs.listxattrs(p)[1],unicode))
+            self.assertEqual(sorted(self.fs.listxattrs(p)),["attr2","xattr1"])
+            self.assertTrue(isinstance(self.fs.listxattrs(p)[0],str))
+            self.assertTrue(isinstance(self.fs.listxattrs(p)[1],str))
             self.fs.delxattr(p,"xattr1")
-            self.assertEquals(sorted(self.fs.listxattrs(p)),["attr2"])
+            self.assertEqual(sorted(self.fs.listxattrs(p)),["attr2"])
             self.fs.delxattr(p,"attr2")
-            self.assertEquals(sorted(self.fs.listxattrs(p)),[])
+            self.assertEqual(sorted(self.fs.listxattrs(p)),[])
         self.fs.setcontents("test.txt",b("hello"))
         do_list("test.txt")
         self.fs.makedir("mystuff")
@@ -64,16 +64,16 @@ class XAttrTestCases:
         self.fs.makedir("stuff")
         self.fs.copy("a.txt","stuff/a.txt")
         self.assertTrue(self.fs.exists("stuff/a.txt"))
-        self.assertEquals(self.fs.getxattr("stuff/a.txt","myattr"),"myvalue")
-        self.assertEquals(self.fs.getxattr("stuff/a.txt","testattr"),"testvalue")
-        self.assertEquals(self.fs.getxattr("a.txt","myattr"),"myvalue")
-        self.assertEquals(self.fs.getxattr("a.txt","testattr"),"testvalue")
+        self.assertEqual(self.fs.getxattr("stuff/a.txt","myattr"),"myvalue")
+        self.assertEqual(self.fs.getxattr("stuff/a.txt","testattr"),"testvalue")
+        self.assertEqual(self.fs.getxattr("a.txt","myattr"),"myvalue")
+        self.assertEqual(self.fs.getxattr("a.txt","testattr"),"testvalue")
         self.fs.setxattr("stuff","dirattr","a directory")
         self.fs.copydir("stuff","stuff2")
-        self.assertEquals(self.fs.getxattr("stuff2/a.txt","myattr"),"myvalue")
-        self.assertEquals(self.fs.getxattr("stuff2/a.txt","testattr"),"testvalue")
-        self.assertEquals(self.fs.getxattr("stuff2","dirattr"),"a directory")
-        self.assertEquals(self.fs.getxattr("stuff","dirattr"),"a directory")
+        self.assertEqual(self.fs.getxattr("stuff2/a.txt","myattr"),"myvalue")
+        self.assertEqual(self.fs.getxattr("stuff2/a.txt","testattr"),"testvalue")
+        self.assertEqual(self.fs.getxattr("stuff2","dirattr"),"a directory")
+        self.assertEqual(self.fs.getxattr("stuff","dirattr"),"a directory")
 
     def test_move_xattrs(self):
         self.fs.setcontents("a.txt",b("content"))
@@ -82,29 +82,29 @@ class XAttrTestCases:
         self.fs.makedir("stuff")
         self.fs.move("a.txt","stuff/a.txt")
         self.assertTrue(self.fs.exists("stuff/a.txt"))
-        self.assertEquals(self.fs.getxattr("stuff/a.txt","myattr"),"myvalue")
-        self.assertEquals(self.fs.getxattr("stuff/a.txt","testattr"),"testvalue")
+        self.assertEqual(self.fs.getxattr("stuff/a.txt","myattr"),"myvalue")
+        self.assertEqual(self.fs.getxattr("stuff/a.txt","testattr"),"testvalue")
         self.fs.setxattr("stuff","dirattr","a directory")
         self.fs.movedir("stuff","stuff2")
-        self.assertEquals(self.fs.getxattr("stuff2/a.txt","myattr"),"myvalue")
-        self.assertEquals(self.fs.getxattr("stuff2/a.txt","testattr"),"testvalue")
-        self.assertEquals(self.fs.getxattr("stuff2","dirattr"),"a directory")
+        self.assertEqual(self.fs.getxattr("stuff2/a.txt","myattr"),"myvalue")
+        self.assertEqual(self.fs.getxattr("stuff2/a.txt","testattr"),"testvalue")
+        self.assertEqual(self.fs.getxattr("stuff2","dirattr"),"a directory")
 
     def test_remove_file(self):
         def listxattrs(path):
             return list(self.fs.listxattrs(path))
         #  Check that xattrs aren't preserved after a file is removed
         self.fs.createfile("myfile")
-        self.assertEquals(listxattrs("myfile"),[])
+        self.assertEqual(listxattrs("myfile"),[])
         self.fs.setxattr("myfile","testattr","testvalue")
-        self.assertEquals(listxattrs("myfile"),["testattr"])
+        self.assertEqual(listxattrs("myfile"),["testattr"])
         self.fs.remove("myfile")
         self.assertRaises(ResourceNotFoundError,listxattrs,"myfile")
         self.fs.createfile("myfile")
-        self.assertEquals(listxattrs("myfile"),[])
+        self.assertEqual(listxattrs("myfile"),[])
         self.fs.setxattr("myfile","testattr2","testvalue2")
-        self.assertEquals(listxattrs("myfile"),["testattr2"])
-        self.assertEquals(self.fs.getxattr("myfile","testattr2"),"testvalue2")
+        self.assertEqual(listxattrs("myfile"),["testattr2"])
+        self.assertEqual(self.fs.getxattr("myfile","testattr2"),"testvalue2")
         #  Check that removing a file without xattrs still works
         self.fs.createfile("myfile2")
         self.fs.remove("myfile2")
@@ -114,16 +114,16 @@ class XAttrTestCases:
             return list(self.fs.listxattrs(path))
         #  Check that xattrs aren't preserved after a dir is removed
         self.fs.makedir("mydir")
-        self.assertEquals(listxattrs("mydir"),[])
+        self.assertEqual(listxattrs("mydir"),[])
         self.fs.setxattr("mydir","testattr","testvalue")
-        self.assertEquals(listxattrs("mydir"),["testattr"])
+        self.assertEqual(listxattrs("mydir"),["testattr"])
         self.fs.removedir("mydir")
         self.assertRaises(ResourceNotFoundError,listxattrs,"mydir")
         self.fs.makedir("mydir")
-        self.assertEquals(listxattrs("mydir"),[])
+        self.assertEqual(listxattrs("mydir"),[])
         self.fs.setxattr("mydir","testattr2","testvalue2")
-        self.assertEquals(listxattrs("mydir"),["testattr2"])
-        self.assertEquals(self.fs.getxattr("mydir","testattr2"),"testvalue2")
+        self.assertEqual(listxattrs("mydir"),["testattr2"])
+        self.assertEqual(self.fs.getxattr("mydir","testattr2"),"testvalue2")
         #  Check that removing a dir without xattrs still works
         self.fs.makedir("mydir2")
         self.fs.removedir("mydir2")
@@ -149,7 +149,7 @@ class TestXAttr_TempFS(unittest.TestCase,FSTestCases,X
         except AttributeError:
             td = self.fs.wrapped_fs._temp_dir
         self.fs.close()
-        self.assert_(not os.path.exists(td))
+        self.assertTrue(not os.path.exists(td))
 
     def check(self, p):
         try:
--- fs/tests/test_zipfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/tests/test_zipfs.py
@@ -52,7 +52,7 @@ class TestReadZipFS(unittest.TestCase):
             return contents
 
         def check_contents(path, expected):
-            self.assert_(read_contents(path) == expected)
+            self.assertTrue(read_contents(path) == expected)
         check_contents("a.txt", b("Hello, World!"))
         check_contents("1.txt", b("1"))
         check_contents("foo/bar/baz.txt", b("baz"))
@@ -62,30 +62,30 @@ class TestReadZipFS(unittest.TestCase):
             return self.fs.getcontents(path, 'rb')
 
         def check_contents(path, expected):
-            self.assert_(read_contents(path) == expected)
+            self.assertTrue(read_contents(path) == expected)
         check_contents("a.txt", b("Hello, World!"))
         check_contents("1.txt", b("1"))
         check_contents("foo/bar/baz.txt", b("baz"))
 
     def test_is(self):
-        self.assert_(self.fs.isfile('a.txt'))
-        self.assert_(self.fs.isfile('1.txt'))
-        self.assert_(self.fs.isfile('foo/bar/baz.txt'))
-        self.assert_(self.fs.isdir('foo'))
-        self.assert_(self.fs.isdir('foo/bar'))
-        self.assert_(self.fs.exists('a.txt'))
-        self.assert_(self.fs.exists('1.txt'))
-        self.assert_(self.fs.exists('foo/bar/baz.txt'))
-        self.assert_(self.fs.exists('foo'))
-        self.assert_(self.fs.exists('foo/bar'))
+        self.assertTrue(self.fs.isfile('a.txt'))
+        self.assertTrue(self.fs.isfile('1.txt'))
+        self.assertTrue(self.fs.isfile('foo/bar/baz.txt'))
+        self.assertTrue(self.fs.isdir('foo'))
+        self.assertTrue(self.fs.isdir('foo/bar'))
+        self.assertTrue(self.fs.exists('a.txt'))
+        self.assertTrue(self.fs.exists('1.txt'))
+        self.assertTrue(self.fs.exists('foo/bar/baz.txt'))
+        self.assertTrue(self.fs.exists('foo'))
+        self.assertTrue(self.fs.exists('foo/bar'))
 
     def test_listdir(self):
 
         def check_listing(path, expected):
             dir_list = self.fs.listdir(path)
-            self.assert_(sorted(dir_list) == sorted(expected))
+            self.assertTrue(sorted(dir_list) == sorted(expected))
             for item in dir_list:
-                self.assert_(isinstance(item, unicode))
+                self.assertTrue(isinstance(item, str))
         check_listing('/', ['a.txt', '1.txt', 'foo', 'b.txt'])
         check_listing('foo', ['second.txt', 'bar'])
         check_listing('foo/bar', ['baz.txt'])
@@ -108,7 +108,7 @@ class TestWriteZipFS(unittest.TestCase):
 
         makefile("a.txt", b("Hello, World!"))
         makefile("b.txt", b("b"))
-        makefile(u"\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
+        makefile("\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
         makefile("foo/bar/baz.txt", b("baz"))
         makefile("foo/second.txt", b("hai"))
 
@@ -119,7 +119,7 @@ class TestWriteZipFS(unittest.TestCase):
 
     def test_valid(self):
         zf = zipfile.ZipFile(self.temp_filename, "r")
-        self.assert_(zf.testzip() is None)
+        self.assertTrue(zf.testzip() is None)
         zf.close()
 
     def test_creation(self):
@@ -134,7 +134,7 @@ class TestWriteZipFS(unittest.TestCase):
         check_contents("b.txt", b("b"))
         check_contents("foo/bar/baz.txt", b("baz"))
         check_contents("foo/second.txt", b("hai"))
-        check_contents(u"\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
+        check_contents("\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
 
 
 class TestAppendZipFS(TestWriteZipFS):
@@ -159,7 +159,7 @@ class TestAppendZipFS(TestWriteZipFS):
         zip_fs = zipfs.ZipFS(self.temp_filename, 'a')
 
         makefile("foo/bar/baz.txt", b("baz"))
-        makefile(u"\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
+        makefile("\N{GREEK SMALL LETTER ALPHA}/\N{GREEK CAPITAL LETTER OMEGA}.txt", b("this is the alpha and the omega"))
         makefile("foo/second.txt", b("hai"))
 
         zip_fs.close()
--- fs/utils.py.orig	2015-11-13 23:12:33 UTC
+++ fs/utils.py
@@ -384,7 +384,7 @@ def isfile(fs,path,info=None):
 def contains_files(fs, path='/'):
     """Check if there are any files in the filesystem"""
     try:
-        iter(fs.walkfiles(path)).next()
+        next(iter(fs.walkfiles(path)))
     except StopIteration:
         return False
     return True
@@ -426,7 +426,7 @@ def find_duplicates(fs,
     for path in compare_paths:
         file_sizes[fs.getsize(path)].append(path)
 
-    size_duplicates = [paths for paths in file_sizes.itervalues() if len(paths) > 1]
+    size_duplicates = [paths for paths in file_sizes.values() if len(paths) > 1]
 
     signatures = defaultdict(list)
 
@@ -453,7 +453,7 @@ def find_duplicates(fs,
     # If 'quick' is True then the signature comparison is adequate (although
     # it may result in false positives)
     if quick:
-        for paths in signatures.itervalues():
+        for paths in signatures.values():
             if len(paths) > 1:
                 yield paths
         return
@@ -482,7 +482,7 @@ def find_duplicates(fs,
     # byte by byte.
     # All path groups in this loop have the same size and same signature, so are
     # highly likely to be identical.
-    for paths in signatures.itervalues():
+    for paths in signatures.values():
 
         while len(paths) > 1:
 
@@ -535,7 +535,7 @@ def print_fs(fs,
     if file_out is None:
         file_out = sys.stdout
 
-    file_encoding = getattr(file_out, 'encoding', u'utf-8') or u'utf-8'
+    file_encoding = getattr(file_out, 'encoding', 'utf-8') or 'utf-8'
     file_encoding = file_encoding.upper()
 
     if terminal_colors is None:
@@ -546,44 +546,44 @@ def print_fs(fs,
 
     def write(line):
         if PY3:
-            file_out.write((line + u'\n'))
+            file_out.write((line + '\n'))
         else:
-            file_out.write((line + u'\n').encode(file_encoding, 'replace'))
+            file_out.write((line + '\n').encode(file_encoding, 'replace'))
 
     def wrap_prefix(prefix):
         if not terminal_colors:
             return prefix
-        return u'\x1b[32m%s\x1b[0m' % prefix
+        return '\x1b[32m%s\x1b[0m' % prefix
 
     def wrap_dirname(dirname):
         if not terminal_colors:
             return dirname
-        return u'\x1b[1;34m%s\x1b[0m' % dirname
+        return '\x1b[1;34m%s\x1b[0m' % dirname
 
     def wrap_error(msg):
         if not terminal_colors:
             return msg
-        return u'\x1b[31m%s\x1b[0m' % msg
+        return '\x1b[31m%s\x1b[0m' % msg
 
     def wrap_filename(fname):
         if not terminal_colors:
             return fname
-        if fname.startswith(u'.'):
-            fname = u'\x1b[33m%s\x1b[0m' % fname
+        if fname.startswith('.'):
+            fname = '\x1b[33m%s\x1b[0m' % fname
         return fname
     dircount = [0]
     filecount = [0]
     def print_dir(fs, path, levels=[]):
         if file_encoding == 'UTF-8' and terminal_colors:
-            char_vertline = u'│'
-            char_newnode = u'├'
-            char_line = u'──'
-            char_corner = u'╰'
+            char_vertline = '│'
+            char_newnode = '├'
+            char_line = '──'
+            char_corner = '╰'
         else:
-            char_vertline = u'|'
-            char_newnode = u'|'
-            char_line = u'--'
-            char_corner = u'`'
+            char_vertline = '|'
+            char_newnode = '|'
+            char_line = '--'
+            char_corner = '`'
 
         try:
             dirs = fs.listdir(path, dirs_only=True)
@@ -593,18 +593,18 @@ def print_fs(fs,
                 files = fs.listdir(path, files_only=True, wildcard=files_wildcard)
             dir_listing = ( [(True, p) for p in dirs] +
                             [(False, p) for p in files] )
-        except Exception, e:
+        except Exception as e:
             prefix = ''.join([(char_vertline + '   ', '    ')[last] for last in levels]) + '   '
-            write(wrap_prefix(prefix[:-1] + '    ') + wrap_error(u"unable to retrieve directory list (%s) ..." % str(e)))
+            write(wrap_prefix(prefix[:-1] + '    ') + wrap_error("unable to retrieve directory list (%s) ..." % str(e)))
             return 0
 
         if hide_dotfiles:
             dir_listing = [(isdir, p) for isdir, p in dir_listing if not p.startswith('.')]
 
         if dirs_first:
-            dir_listing.sort(key = lambda (isdir, p):(not isdir, p.lower()))
+            dir_listing.sort(key = lambda isdir_p:(not isdir_p[0], isdir_p[1].lower()))
         else:
-            dir_listing.sort(key = lambda (isdir, p):p.lower())
+            dir_listing.sort(key = lambda isdir_p1:isdir_p1[1].lower())
 
         for i, (is_dir, item) in enumerate(dir_listing):
             if is_dir:
@@ -685,9 +685,9 @@ if __name__ == "__main__":
     t1.tree()
 
     t2 = TempFS()
-    print t2.listdir()
+    print(t2.listdir())
     movedir(t1, t2)
 
-    print t2.listdir()
+    print(t2.listdir())
     t1.tree()
     t2.tree()
--- fs/watch.py.orig	2022-03-04 17:14:43 UTC
+++ fs/watch.py
@@ -32,7 +32,7 @@ an iterator over the change events.
 import sys
 import weakref
 import threading
-import Queue
+import queue
 import traceback
 
 from fs.path import *
@@ -54,10 +54,10 @@ class EVENT(object):
         self.path = path
 
     def __str__(self):
-        return unicode(self).encode("utf8")
+        return str(self).encode("utf8")
 
     def __unicode__(self):
-        return u"<fs.watch.%s object (path='%s') at %s>" % (self.__class__.__name__,self.path,hex(id(self)))
+        return "<fs.watch.%s object (path='%s') at %s>" % (self.__class__.__name__,self.path,hex(id(self)))
 
     def clone(self,fs=None,path=None):
         if fs is None:
@@ -102,7 +102,7 @@ class MOVED_DST(EVENT):
         self.source = source
 
     def __unicode__(self):
-        return u"<fs.watch.%s object (path=%r,src=%r) at %s>" % (self.__class__.__name__,self.path,self.source,hex(id(self)))
+        return "<fs.watch.%s object (path=%r,src=%r) at %s>" % (self.__class__.__name__,self.path,self.source,hex(id(self)))
 
     def clone(self,fs=None,path=None,source=None):
         evt = super(MOVED_DST,self).clone(fs,path)
@@ -120,7 +120,7 @@ class MOVED_SRC(EVENT):
         self.destination = destination
 
     def __unicode__(self):
-        return u"<fs.watch.%s object (path=%r,dst=%r) at %s>" % (self.__class__.__name__,self.path,self.destination,hex(id(self)))
+        return "<fs.watch.%s object (path=%r,dst=%r) at %s>" % (self.__class__.__name__,self.path,self.destination,hex(id(self)))
 
     def clone(self,fs=None,path=None,destination=None):
         evt = super(MOVED_SRC,self).clone(fs,path)
@@ -182,7 +182,7 @@ class Watcher(object):
         try:
             self.callback(event)
         except Exception:
-            print >>sys.stderr, "error in FS watcher callback", self.callback
+            print("error in FS watcher callback", self.callback, file=sys.stderr)
             traceback.print_exc()
 
 
@@ -213,7 +213,7 @@ class WatchableFSMixin(FS):
         if isinstance(watcher_or_callback,Watcher):
             self._watchers[watcher_or_callback.path].remove(watcher_or_callback)
         else:
-            for watchers in self._watchers.itervalues():
+            for watchers in self._watchers.values():
                 for i,watcher in enumerate(watchers):
                     if watcher.callback is watcher_or_callback:
                         del watchers[i]
@@ -221,7 +221,7 @@ class WatchableFSMixin(FS):
 
     def _find_watchers(self,callback):
         """Find watchers registered with the given callback."""
-        for watchers in self._watchers.itervalues():
+        for watchers in self._watchers.values():
             for watcher in watchers:
                 if watcher.callback is callback:
                     yield watcher
@@ -235,7 +235,7 @@ class WatchableFSMixin(FS):
         if path is None:
             path = event.path
         if path is None:
-            for watchers in self._watchers.itervalues():
+            for watchers in self._watchers.values():
                 for watcher in watchers:
                     watcher.handle_event(event)
         else:
@@ -443,7 +443,7 @@ class WatchableFS(WatchableFSMixin,WrapFS):
 
     def _post_move(self,src,dst,data):
         (src_paths,dst_paths) = data
-        for src_path,isdir in sorted(src_paths.items(),reverse=True):
+        for src_path,isdir in sorted(list(src_paths.items()),reverse=True):
             path = pathjoin(src,src_path)
             self.notify_watchers(REMOVED,path)
 
@@ -554,7 +554,7 @@ class PollingWatchableFS(WatchableFS):
             else:
                 was_accessed = False
                 was_modified = False
-                for (k,v) in new_info.iteritems():
+                for (k,v) in new_info.items():
                     if k not in old_info:
                         was_modified = True
                         break
@@ -612,7 +612,7 @@ class iter_changes(object):
 
     def __init__(self,fs=None,path="/",events=None,**kwds):
         self.closed = False
-        self._queue = Queue.Queue()
+        self._queue = queue.Queue()
         self._watching = set()
         if fs is not None:
             self.add_watcher(fs,path,events,**kwds)
@@ -628,7 +628,7 @@ class iter_changes(object):
             raise StopIteration
         try:
             event = self._queue.get(timeout=timeout)
-        except Queue.Empty:
+        except queue.Empty:
             raise StopIteration
         if event is None:
             raise StopIteration
--- fs/wrapfs/__init__.py.orig	2015-04-12 17:24:29 UTC
+++ fs/wrapfs/__init__.py
@@ -32,12 +32,12 @@ def rewrite_errors(func):
     def wrapper(self,*args,**kwds):
         try:
             return func(self,*args,**kwds)
-        except ResourceError, e:
+        except ResourceError as e:
             (exc_type,exc_inst,tb) = sys.exc_info()
             try:
                 e.path = self._decode(e.path)
             except (AttributeError, ValueError, TypeError):
-                raise e, None, tb
+                raise e.with_traceback(tb)
             raise
     return wrapper
 
@@ -119,7 +119,7 @@ class WrapFS(FS):
         return (mode, mode)
 
     def __unicode__(self):
-        return u"<%s: %s>" % (self.__class__.__name__,self.wrapped_fs,)
+        return "<%s: %s>" % (self.__class__.__name__,self.wrapped_fs,)
 
     #def __str__(self):
     #    return unicode(self).encode(sys.getdefaultencoding(),"replace")
--- fs/wrapfs/debugfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/wrapfs/debugfs.py
@@ -66,7 +66,7 @@ class DebugFS(object):
             logger.log(level, message)
         
     def __parse_param(self, value):
-        if isinstance(value, basestring):
+        if isinstance(value, str):
             if len(value) > 60:
                 value = "%s ... (length %d)" % (repr(value[:60]), len(value))
             else:
@@ -75,7 +75,7 @@ class DebugFS(object):
             value = "%s (%d items)" % (repr(value[:3]), len(value))
         elif isinstance(value, dict):
             items = {}
-            for k, v in value.items()[:3]:
+            for k, v in list(value.items())[:3]:
                 items[k] = v
             value = "%s (%d items)" % (repr(items), len(value))
         else:
@@ -84,7 +84,7 @@ class DebugFS(object):
     
     def __parse_args(self, *arguments, **kwargs):
         args = [self.__parse_param(a) for a in arguments]
-        for k, v in kwargs.items():
+        for k, v in list(kwargs.items()):
             args.append("%s=%s" % (k, self.__parse_param(v)))
         
         args = ','.join(args)
@@ -105,10 +105,10 @@ class DebugFS(object):
 
         try:
             attr = getattr(self.__wrapped_fs, key)
-        except AttributeError, e:
+        except AttributeError as e:
             self.__log(DEBUG, "Asking for not implemented method %s" % key)
             raise e
-        except Exception, e:
+        except Exception as e:
             self.__log(CRITICAL, "Exception %s: %s" % \
                      (e.__class__.__name__, str(e)))
             raise e
@@ -122,19 +122,19 @@ class DebugFS(object):
             try:
                 value = attr(*args, **kwargs)                
                 self.__report("Call method", key, value, *args, **kwargs)
-            except FSError, e:
+            except FSError as e:
                 self.__log(ERROR, "Call method %s%s -> Exception %s: %s" % \
                              (key, self.__parse_args(*args, **kwargs), \
                              e.__class__.__name__, str(e)))
                 (exc_type,exc_inst,tb) = sys.exc_info()
-                raise e, None, tb
-            except Exception, e:
+                raise e.with_traceback(tb)
+            except Exception as e:
                 self.__log(CRITICAL,
                          "Call method %s%s -> Non-FS exception %s: %s" %\
                          (key, self.__parse_args(*args, **kwargs), \
                          e.__class__.__name__, str(e)))
                 (exc_type,exc_inst,tb) = sys.exc_info()
-                raise e, None, tb
+                raise e.with_traceback(tb)
             return value
         
         if self.__verbose:
--- fs/wrapfs/hidedotfilesfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/wrapfs/hidedotfilesfs.py
@@ -87,7 +87,7 @@ class HideDotFilesFS(WrapFS):
         path = normpath(path)
         iter_dir = iter(self.listdir(path,hidden=True))
         try:
-            iter_dir.next()
+            next(iter_dir)
         except StopIteration:
             return True
         return False
--- fs/wrapfs/lazyfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/wrapfs/lazyfs.py
@@ -39,14 +39,14 @@ class LazyFS(WrapFS):
             #  It appears that python2.5 has trouble printing out
             #  classes that define a __unicode__ method.
             try:
-                return u"<LazyFS: %s>" % (self._fsclass,)
+                return "<LazyFS: %s>" % (self._fsclass,)
             except TypeError:
                 try:
-                    return u"<LazyFS: %s>" % (self._fsclass.__name__,)
+                    return "<LazyFS: %s>" % (self._fsclass.__name__,)
                 except AttributeError:
-                    return u"<LazyFS: <unprintable>>"
+                    return "<LazyFS: <unprintable>>"
         else:
-            return u"<LazyFS: %s>" % (wrapped_fs,)
+            return "<LazyFS: %s>" % (wrapped_fs,)
 
     def __getstate__(self):
         state = super(LazyFS,self).__getstate__()
--- fs/wrapfs/limitsizefs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/wrapfs/limitsizefs.py
@@ -9,7 +9,7 @@ total size of files stored in the wrapped FS.
 
 """
 
-from __future__ import with_statement
+
 
 from fs.errors import *
 from fs.path import *
--- fs/wrapfs/subfs.py.orig	2022-03-04 17:14:43 UTC
+++ fs/wrapfs/subfs.py
@@ -34,7 +34,7 @@ class SubFS(WrapFS):
         return '<SubFS: %s/%s>' % (self.wrapped_fs, self.sub_dir.lstrip('/'))
 
     def __unicode__(self):
-        return u'<SubFS: %s/%s>' % (self.wrapped_fs, self.sub_dir.lstrip('/'))
+        return '<SubFS: %s/%s>' % (self.wrapped_fs, self.sub_dir.lstrip('/'))
 
     def __repr__(self):
         return "SubFS(%r, %r)" % (self.wrapped_fs, self.sub_dir)
--- fs/xattrs.py.orig	2015-04-12 17:24:29 UTC
+++ fs/xattrs.py
@@ -23,7 +23,7 @@ if it has native xattr support, and return a wrapped v
 
 import sys
 try:
-    import cPickle as pickle
+    import pickle as pickle
 except ImportError:
     import pickle
 
@@ -104,7 +104,7 @@ class SimulateXAttr(WrapFS):
         """Set an extended attribute on the given path."""
         if not self.exists(path):
             raise ResourceNotFoundError(path)
-        key = unicode(key)
+        key = str(key)
         attrs = self._get_attr_dict(path)
         attrs[key] = str(value)
         self._set_attr_dict(path, attrs)
@@ -133,7 +133,7 @@ class SimulateXAttr(WrapFS):
         """List all the extended attribute keys set on the given path."""
         if not self.exists(path):
             raise ResourceNotFoundError(path)
-        return self._get_attr_dict(path).keys()
+        return list(self._get_attr_dict(path).keys())
 
     def _encode(self,path):
         """Prevent requests for operations on .xattr files."""
@@ -189,7 +189,7 @@ class SimulateXAttr(WrapFS):
         d_attr_file = self._get_attr_path(dst)
         try:
             self.wrapped_fs.copy(s_attr_file,d_attr_file,overwrite=True)
-        except ResourceNotFoundError,e:
+        except ResourceNotFoundError as e:
             pass
 
     def move(self,src,dst,**kwds):
--- fs/zipfs.py.orig	2015-04-12 17:25:37 UTC
+++ fs/zipfs.py
@@ -16,9 +16,9 @@ from fs.filelike import StringIO
 from fs import iotools
 
 from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED, BadZipfile, LargeZipFile
-from memoryfs import MemoryFS
+from .memoryfs import MemoryFS
 
-import tempfs
+from . import tempfs
 
 from six import PY3
 
@@ -74,7 +74,7 @@ class _ExceptionProxy(object):
     def __setattr__(self, name, value):
         raise ValueError("Zip file has been closed")
 
-    def __nonzero__(self):
+    def __bool__(self):
         return False
 
 
@@ -117,7 +117,7 @@ class ZipFS(FS):
         self.zip_mode = mode
         self.encoding = encoding
 
-        if isinstance(zip_file, basestring):
+        if isinstance(zip_file, str):
             zip_file = os.path.expanduser(os.path.expandvars(zip_file))
             zip_file = os.path.normpath(os.path.abspath(zip_file))
             self._zip_file_string = True
@@ -126,10 +126,10 @@ class ZipFS(FS):
 
         try:
             self.zf = ZipFile(zip_file, mode, compression_type, allow_zip_64)
-        except BadZipfile, bzf:
+        except BadZipfile as bzf:
             raise ZipOpenError("Not a zip file or corrupt (%s)" % str(zip_file),
                                details=bzf)
-        except IOError, ioe:
+        except IOError as ioe:
             if str(ioe).startswith('[Errno 22] Invalid argument'):
                 raise ZipOpenError("Not a zip file or corrupt (%s)" % str(zip_file),
                                    details=ioe)
@@ -151,7 +151,7 @@ class ZipFS(FS):
         return "<ZipFS: %s>" % self.zip_path
 
     def __unicode__(self):
-        return u"<ZipFS: %s>" % self.zip_path
+        return "<ZipFS: %s>" % self.zip_path
 
     def _decode_path(self, path):
         if PY3:
@@ -280,7 +280,7 @@ class ZipFS(FS):
         try:
             zi = self.zf.getinfo(self._encode_path(path))
             zinfo = dict((attrib, getattr(zi, attrib)) for attrib in dir(zi) if not attrib.startswith('_'))
-            for k, v in zinfo.iteritems():
+            for k, v in zinfo.items():
                 if callable(v):
                     zinfo[k] = v()
         except KeyError:
--- setup.py.orig	2015-11-14 11:44:01 UTC
+++ setup.py
@@ -38,8 +38,6 @@ with open('README.txt', 'r') as f:
 
 
 extra = {}
-if PY3:
-    extra["use_2to3"] = True
 
 setup(install_requires=['setuptools', 'six'],
       name='fs',
