From: Alexandre Detiste <tchet@debian.org>
Date: Sun, 7 Sep 2025 18:50:49 +0200
Subject: remove runtime dependency on python3-six

Forwarded: no, project seams inactive
---
 fs/_bulk.py        |  2 +-
 fs/_fscompat.py    |  5 ++---
 fs/_typing.py      | 17 +----------------
 fs/_url_tools.py   | 10 +++-------
 fs/appfs.py        |  4 +---
 fs/base.py         | 14 +++++---------
 fs/compress.py     |  9 +--------
 fs/error_tools.py  |  3 +--
 fs/errors.py       |  7 ++-----
 fs/ftpfs.py        | 19 ++++---------------
 fs/info.py         |  2 --
 fs/memoryfs.py     |  3 ---
 fs/mode.py         |  4 +---
 fs/mountfs.py      |  3 +--
 fs/multifs.py      |  3 +--
 fs/opener/base.py  |  4 +---
 fs/opener/parse.py |  5 ++---
 fs/osfs.py         |  8 +-------
 fs/permissions.py  |  2 --
 fs/subfs.py        |  2 --
 fs/tarfs.py        | 40 +++++++---------------------------------
 fs/tempfs.py       |  2 --
 fs/wrapfs.py       |  2 --
 fs/zipfs.py        |  9 +--------
 setup.cfg          |  1 -
 25 files changed, 36 insertions(+), 144 deletions(-)

diff --git a/fs/_bulk.py b/fs/_bulk.py
index caba0c5..ab25e12 100644
--- a/fs/_bulk.py
+++ b/fs/_bulk.py
@@ -9,7 +9,7 @@ from __future__ import unicode_literals
 import typing
 
 import threading
-from six.moves.queue import Queue
+from queue import Queue
 
 from .copy import copy_file_internal, copy_modified_time
 from .errors import BulkCopyFailed
diff --git a/fs/_fscompat.py b/fs/_fscompat.py
index fa7d2c0..8b3c4cd 100644
--- a/fs/_fscompat.py
+++ b/fs/_fscompat.py
@@ -1,4 +1,3 @@
-import six
 
 try:
     from os import fsdecode, fsencode
@@ -17,7 +16,7 @@ except ImportError:
         path representation is not str or bytes, TypeError is raised. If the
         provided path is not str, bytes, or os.PathLike, TypeError is raised.
         """
-        if isinstance(path, (six.text_type, bytes)):
+        if isinstance(path, (str, bytes)):
             return path
 
         # Work from the object's type to match method resolution of other magic
@@ -33,7 +32,7 @@ except ImportError:
                     "expected string type or os.PathLike object, "
                     "not " + path_type.__name__
                 )
-        if isinstance(path_repr, (six.text_type, bytes)):
+        if isinstance(path_repr, (str, bytes)):
             return path_repr
         else:
             raise TypeError(
diff --git a/fs/_typing.py b/fs/_typing.py
index 0c80b8e..de6fb32 100644
--- a/fs/_typing.py
+++ b/fs/_typing.py
@@ -4,19 +4,4 @@ Typing objects missing from Python3.5.1
 """
 import sys
 
-import six
-
-_PY = sys.version_info
-
-from typing import overload  # type: ignore
-
-if _PY.major == 3 and _PY.minor == 5 and _PY.micro in (0, 1):
-
-    def overload(func):  # pragma: no cover  # noqa: F811
-        return func
-
-
-try:
-    from typing import Text
-except ImportError:  # pragma: no cover
-    Text = six.text_type  # type: ignore
+from typing import overload, Text
diff --git a/fs/_url_tools.py b/fs/_url_tools.py
index cfd76a7..5a1036b 100644
--- a/fs/_url_tools.py
+++ b/fs/_url_tools.py
@@ -2,7 +2,7 @@ import typing
 
 import platform
 import re
-import six
+import urllib.request
 
 if typing.TYPE_CHECKING:
     from typing import Text
@@ -24,14 +24,10 @@ def url_quote(path_snippet):
     """
     if _WINDOWS_PLATFORM and _has_drive_letter(path_snippet):
         drive_letter, path = path_snippet.split(":", 1)
-        if six.PY2:
-            path = path.encode("utf-8")
-        path = six.moves.urllib.request.pathname2url(path)
+        path = urllib.request.pathname2url(path)
         path_snippet = "{}:{}".format(drive_letter, path)
     else:
-        if six.PY2:
-            path_snippet = path_snippet.encode("utf-8")
-        path_snippet = six.moves.urllib.request.pathname2url(path_snippet)
+        path_snippet = urllib.request.pathname2url(path_snippet)
     return path_snippet
 
 
diff --git a/fs/appfs.py b/fs/appfs.py
index 2fd4568..ef77295 100644
--- a/fs/appfs.py
+++ b/fs/appfs.py
@@ -12,7 +12,6 @@ subclasses of `~fs.osfs.OSFS`.
 import typing
 
 import abc
-import six
 from appdirs import AppDirs
 
 from ._repr import make_repr
@@ -47,8 +46,7 @@ class _CopyInitMeta(abc.ABCMeta):
         return super(abc.ABCMeta, mcls).__new__(mcls, classname, bases, cls_dict)
 
 
-@six.add_metaclass(_CopyInitMeta)
-class _AppFS(OSFS):
+class _AppFS(OSFS,metaclass=_CopyInitMeta):
     """Abstract base class for an app FS."""
 
     # FIXME(@althonos): replace by ClassVar[Text] once
diff --git a/fs/base.py b/fs/base.py
index 07a1675..9d1943a 100644
--- a/fs/base.py
+++ b/fs/base.py
@@ -14,7 +14,6 @@ import abc
 import hashlib
 import itertools
 import os
-import six
 import threading
 import time
 import warnings
@@ -93,8 +92,7 @@ def _new_name(method, old_name):
     return _method
 
 
-@six.add_metaclass(abc.ABCMeta)
-class FS(object):
+class FS(metaclass=abc.ABCMeta):
     """Base class for FS objects."""
 
     # This is the "standard" meta namespace.
@@ -364,7 +362,7 @@ class FS(object):
                 ``path`` does not exist.
 
         """
-        if not isinstance(text, six.text_type):
+        if not isinstance(text, str):
             raise TypeError("must be unicode string")
         with self._lock:
             with self.open(
@@ -1512,7 +1510,7 @@ class FS(object):
             TypeError: if ``contents`` is not a unicode string.
 
         """
-        if not isinstance(contents, six.text_type):
+        if not isinstance(contents, str):
             raise TypeError("contents must be unicode")
         with closing(
             self.open(
@@ -1569,13 +1567,11 @@ class FS(object):
         if isinstance(path, bytes):
             raise TypeError(
                 "paths must be unicode (not str)"
-                if six.PY2
-                else "paths must be str (not bytes)"
             )
 
         meta = self.getmeta()
 
-        invalid_chars = typing.cast(six.text_type, meta.get("invalid_path_chars"))
+        invalid_chars = typing.cast(str, meta.get("invalid_path_chars"))
         if invalid_chars:
             if set(path).intersection(invalid_chars):
                 raise errors.InvalidCharsInPath(path)
@@ -1688,7 +1684,7 @@ class FS(object):
         """
         if patterns is None:
             return True
-        if isinstance(patterns, six.text_type):
+        if isinstance(patterns, str):
             raise TypeError("patterns must be a list or sequence")
         case_sensitive = not typing.cast(
             bool, self.getmeta().get("case_insensitive", False)
diff --git a/fs/compress.py b/fs/compress.py
index a1b2e34..dec57a9 100644
--- a/fs/compress.py
+++ b/fs/compress.py
@@ -8,7 +8,6 @@ from __future__ import absolute_import, print_function, unicode_literals
 
 import typing
 
-import six
 import tarfile
 import time
 import zipfile
@@ -61,9 +60,6 @@ def write_zip(
             # Zip names must be relative, directory names must end
             # with a slash.
             zip_name = relpath(path + "/" if info.is_dir else path)
-            if not six.PY3:
-                # Python2 expects bytes filenames
-                zip_name = zip_name.encode(encoding, "replace")
 
             if info.has_namespace("stat"):
                 # If the file has a stat namespace, get the
@@ -141,7 +137,7 @@ def write_tar(
     tar_attr = [("uid", "uid"), ("gid", "gid"), ("uname", "user"), ("gname", "group")]
 
     mode = "w:{}".format(compression or "")
-    if isinstance(file, (six.text_type, six.binary_type)):
+    if isinstance(file, (str, bytes)):
         _tar = tarfile.open(file, mode=mode)
     else:
         _tar = tarfile.open(fileobj=file, mode=mode)
@@ -153,9 +149,6 @@ def write_tar(
         for path, info in gen_walk:
             # Tar names must be relative
             tar_name = relpath(path)
-            if not six.PY3:
-                # Python2 expects bytes filenames
-                tar_name = tar_name.encode(encoding, "replace")
 
             tar_info = tarfile.TarInfo(tar_name)
 
diff --git a/fs/error_tools.py b/fs/error_tools.py
index bdb3818..9da41ff 100644
--- a/fs/error_tools.py
+++ b/fs/error_tools.py
@@ -9,7 +9,6 @@ import typing
 import errno
 import platform
 from contextlib import contextmanager
-from six import reraise
 
 from . import errors
 
@@ -86,7 +85,7 @@ class _ConvertOSErrors(object):
             if _errno == errno.EACCES and sys.platform == "win32":
                 if getattr(exc_value, "args", None) == 32:  # pragma: no cover
                     fserror = errors.ResourceLocked
-            reraise(fserror, fserror(self._path, exc=exc_value), traceback)
+            raise fserror(self._path, exc=exc_value).with_traceback(traceback)
 
 
 # Stops linter complaining about invalid class name
diff --git a/fs/errors.py b/fs/errors.py
index 400bac7..2c05903 100644
--- a/fs/errors.py
+++ b/fs/errors.py
@@ -13,8 +13,6 @@ from __future__ import print_function, unicode_literals
 import typing
 
 import functools
-import six
-from six import text_type
 
 if typing.TYPE_CHECKING:
     from typing import Optional, Text
@@ -67,7 +65,6 @@ class MissingInfoNamespace(AttributeError):
         return type(self), (self.namespace,)
 
 
-@six.python_2_unicode_compatible
 class FSError(Exception):
     """Base exception for the `fs` module."""
 
@@ -114,7 +111,7 @@ class CreateFailed(FSError):
     def __init__(self, msg=None, exc=None):  # noqa: D107
         # type: (Optional[Text], Optional[Exception]) -> None
         self._msg = msg or self.default_message
-        self.details = "" if exc is None else text_type(exc)
+        self.details = "" if exc is None else str(exc)
         self.exc = exc
 
     @classmethod
@@ -195,7 +192,7 @@ class OperationFailed(FSError):
         # type: (...) -> None
         self.path = path
         self.exc = exc
-        self.details = "" if exc is None else text_type(exc)
+        self.details = "" if exc is None else str(exc)
         self.errno = getattr(exc, "errno", None)
         super(OperationFailed, self).__init__(msg=msg)
 
diff --git a/fs/ftpfs.py b/fs/ftpfs.py
index 50d8a0d..4fb4281 100644
--- a/fs/ftpfs.py
+++ b/fs/ftpfs.py
@@ -23,7 +23,6 @@ except ImportError as err:
 from typing import cast
 
 from ftplib import error_perm, error_temp
-from six import PY2, raise_from, text_type
 
 from . import _ftp_parse as ftp_parse
 from . import errors
@@ -112,21 +111,11 @@ def manage_ftp(ftp):
 def _parse_ftp_error(error):
     # type: (ftplib.Error) -> Tuple[Text, Text]
     """Extract code and message from ftp error."""
-    code, _, message = text_type(error).partition(" ")
+    code, _, message = str(error).partition(" ")
     return code, message
 
 
-if PY2:
-
-    def _encode(st, encoding):
-        # type: (Union[Text, bytes], Text) -> str
-        return st.encode(encoding) if isinstance(st, text_type) else st
-
-    def _decode(st, encoding):
-        # type: (Union[Text, bytes], Text) -> Text
-        return st.decode(encoding, "replace") if isinstance(st, bytes) else st
-
-else:
+if True:
 
     def _encode(st, _):
         # type: (str, str) -> str
@@ -428,7 +417,7 @@ class FTPFS(FS):
         self.tls = tls
 
         if self.tls and isinstance(FTP_TLS, Exception):
-            raise_from(errors.CreateFailed("FTP over TLS not supported"), FTP_TLS)
+            raise errors.CreateFailed("FTP over TLS not supported") from FTP_TLS
 
         self.encoding = "latin-1"
         self._ftp = None  # type: Optional[FTP]
@@ -488,7 +477,7 @@ class FTPFS(FS):
             else:
                 self._features = self._parse_features(feat_response)
                 self.encoding = "utf-8" if "UTF8" in self._features else "latin-1"
-                if not PY2:
+                if True:
                     _ftp.file = _ftp.sock.makefile(  # type: ignore
                         "r", encoding=self.encoding
                     )
diff --git a/fs/info.py b/fs/info.py
index 21bb149..725b220 100644
--- a/fs/info.py
+++ b/fs/info.py
@@ -6,7 +6,6 @@ from __future__ import absolute_import, print_function, unicode_literals
 import typing
 from typing import cast
 
-import six
 from copy import deepcopy
 
 from ._typing import Text, overload
@@ -26,7 +25,6 @@ if typing.TYPE_CHECKING:
     T = typing.TypeVar("T")
 
 
-@six.python_2_unicode_compatible
 class Info(object):
     """Container for :ref:`info`.
 
diff --git a/fs/memoryfs.py b/fs/memoryfs.py
index 8efdc13..8744825 100644
--- a/fs/memoryfs.py
+++ b/fs/memoryfs.py
@@ -7,7 +7,6 @@ import typing
 import contextlib
 import io
 import os
-import six
 import time
 from collections import OrderedDict
 from threading import RLock
@@ -48,7 +47,6 @@ if typing.TYPE_CHECKING:
     _M = typing.TypeVar("_M", bound="MemoryFS")
 
 
-@six.python_2_unicode_compatible
 class _MemoryFile(io.RawIOBase):
     def __init__(self, path, memory_fs, mode, dir_entry):
         # type: (Text, MemoryFS, Text, _DirEntry) -> None
@@ -315,7 +313,6 @@ class _DirEntry(object):
         return Info(info)
 
 
-@six.python_2_unicode_compatible
 class MemoryFS(FS):
     """A filesystem that stored in memory.
 
diff --git a/fs/mode.py b/fs/mode.py
index c719340..b62e3d9 100644
--- a/fs/mode.py
+++ b/fs/mode.py
@@ -9,7 +9,6 @@ from __future__ import print_function, unicode_literals
 
 import typing
 
-import six
 
 from ._typing import Text
 
@@ -21,7 +20,6 @@ __all__ = ["Mode", "check_readable", "check_writable", "validate_openbin_mode"]
 
 
 # https://docs.python.org/3/library/functions.html#open
-@six.python_2_unicode_compatible
 class Mode(typing.Container[Text]):
     """An abstraction for I/O modes.
 
@@ -78,7 +76,7 @@ class Mode(typing.Container[Text]):
         support exclusive mode.
 
         """
-        return self._mode.replace("x", "w") if six.PY2 else self._mode
+        return self._mode
 
     def to_platform_bin(self):
         # type: () -> Text
diff --git a/fs/mountfs.py b/fs/mountfs.py
index 92fba6d..705679b 100644
--- a/fs/mountfs.py
+++ b/fs/mountfs.py
@@ -5,7 +5,6 @@ from __future__ import absolute_import, print_function, unicode_literals
 
 import typing
 
-from six import text_type
 
 from . import errors
 from .base import FS
@@ -104,7 +103,7 @@ class MountFS(FS):
             fs (FS or str): A filesystem (instance or URL) to mount.
 
         """
-        if isinstance(fs, text_type):
+        if isinstance(fs, str):
             from .opener import open_fs
 
             fs = open_fs(fs)
diff --git a/fs/multifs.py b/fs/multifs.py
index 125d0de..92f6dfe 100644
--- a/fs/multifs.py
+++ b/fs/multifs.py
@@ -7,7 +7,6 @@ import typing
 
 from collections import OrderedDict, namedtuple
 from operator import itemgetter
-from six import text_type
 
 from . import errors
 from .base import FS
@@ -99,7 +98,7 @@ class MultiFS(FS):
                 filesystem will be looked at first.
 
         """
-        if isinstance(fs, text_type):
+        if isinstance(fs, str):
             fs = open_fs(fs)
 
         if not isinstance(fs, FS):
diff --git a/fs/opener/base.py b/fs/opener/base.py
index 5facaaa..9fbd81c 100644
--- a/fs/opener/base.py
+++ b/fs/opener/base.py
@@ -5,7 +5,6 @@
 import typing
 
 import abc
-import six
 
 if typing.TYPE_CHECKING:
     from typing import List, Text
@@ -14,8 +13,7 @@ if typing.TYPE_CHECKING:
     from .parse import ParseResult
 
 
-@six.add_metaclass(abc.ABCMeta)
-class Opener(object):
+class Opener(metaclass=abc.ABCMeta):
     """The base class for filesystem openers.
 
     An opener is responsible for opening a filesystem for a given
diff --git a/fs/opener/parse.py b/fs/opener/parse.py
index f554bf3..98216d8 100644
--- a/fs/opener/parse.py
+++ b/fs/opener/parse.py
@@ -7,8 +7,7 @@ import typing
 
 import collections
 import re
-import six
-from six.moves.urllib.parse import parse_qs, unquote
+from urllib.parse import parse_qs, unquote
 
 from .errors import ParseError
 
@@ -89,7 +88,7 @@ def parse_fs_url(fs_url):
     resource = unquote(url)
     if has_qs:
         _params = parse_qs(qs, keep_blank_values=True)
-        params = {k: unquote(v[0]) for k, v in six.iteritems(_params)}
+        params = {k: unquote(v[0]) for k, v in _params.items()}
     else:
         params = {}
     return ParseResult(fs_name, username, password, resource, params, path)
diff --git a/fs/osfs.py b/fs/osfs.py
index 0add3d9..ea942ad 100644
--- a/fs/osfs.py
+++ b/fs/osfs.py
@@ -16,7 +16,6 @@ import logging
 import os
 import platform
 import shutil
-import six
 import stat
 import tempfile
 
@@ -77,7 +76,6 @@ log = logging.getLogger("fs.osfs")
 _WINDOWS_PLATFORM = platform.system() == "Windows"
 
 
-@six.python_2_unicode_compatible
 class OSFS(FS):
     """Create an OSFS.
 
@@ -161,7 +159,7 @@ class OSFS(FS):
 
         if _WINDOWS_PLATFORM:  # pragma: no cover
             _meta["invalid_path_chars"] = (
-                "".join(six.unichr(n) for n in range(31)) + '\\:*?"<>|'
+                "".join(chr(n) for n in range(31)) + '\\:*?"<>|'
             )
         else:
             _meta["invalid_path_chars"] = "\0"
@@ -351,8 +349,6 @@ class OSFS(FS):
             raise errors.FileExpected(path)
         sys_path = self._to_sys_path(_path)
         with convert_os_errors("openbin", path):
-            if six.PY2 and _mode.exclusive:
-                sys_path = os.open(sys_path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
             binary_file = io.open(
                 sys_path, mode=_mode.to_platform_bin(), buffering=buffering, **options
             )
@@ -641,8 +637,6 @@ class OSFS(FS):
             raise FileExpected(path)
         sys_path = self._to_sys_path(_path)
         with convert_os_errors("open", path):
-            if six.PY2 and _mode.exclusive:
-                sys_path = os.open(sys_path, os.O_RDWR | os.O_CREAT | os.O_EXCL)
             _encoding = encoding or "utf-8"
             return io.open(
                 sys_path,
diff --git a/fs/permissions.py b/fs/permissions.py
index 3fee335..58978e4 100644
--- a/fs/permissions.py
+++ b/fs/permissions.py
@@ -6,7 +6,6 @@ from __future__ import print_function, unicode_literals
 import typing
 from typing import Iterable
 
-import six
 
 from ._typing import Text
 
@@ -40,7 +39,6 @@ class _PermProperty(object):
             obj.remove(self._name)
 
 
-@six.python_2_unicode_compatible
 class Permissions(object):
     """An abstraction for file system permissions.
 
diff --git a/fs/subfs.py b/fs/subfs.py
index 9bc6167..9ce4daf 100644
--- a/fs/subfs.py
+++ b/fs/subfs.py
@@ -5,7 +5,6 @@ from __future__ import print_function, unicode_literals
 
 import typing
 
-import six
 
 from .path import abspath, join, normpath, relpath
 from .wrapfs import WrapFS
@@ -19,7 +18,6 @@ if typing.TYPE_CHECKING:
 _F = typing.TypeVar("_F", bound="FS", covariant=True)
 
 
-@six.python_2_unicode_compatible
 class SubFS(WrapFS[_F], typing.Generic[_F]):
     """A sub-directory on a parent filesystem.
 
diff --git a/fs/tarfs.py b/fs/tarfs.py
index e699f86..ca81b0e 100644
--- a/fs/tarfs.py
+++ b/fs/tarfs.py
@@ -7,7 +7,6 @@ import typing
 from typing import IO, cast
 
 import os
-import six
 import tarfile
 from collections import OrderedDict
 
@@ -48,14 +47,8 @@ if typing.TYPE_CHECKING:
 __all__ = ["TarFS", "WriteTarFS", "ReadTarFS"]
 
 
-if six.PY2:
-
-    def _get_member_info(member, encoding):
-        # type: (TarInfo, Text) -> Dict[Text, object]
-        return member.get_info(encoding, None)
-
-else:
 
+if True:
     def _get_member_info(member, encoding):
         # type: (TarInfo, Text) -> Dict[Text, object]
         # NOTE(@althonos): TarInfo.get_info is neither in the doc nor
@@ -122,7 +115,7 @@ class TarFS(WrapFS):
         temp_fs="temp://__tartemp__",  # type: Union[Text, FS]
     ):
         # type: (...) -> FS
-        if isinstance(file, (six.text_type, six.binary_type)):
+        if isinstance(file, (str, bytes)):
             file = os.path.expanduser(file)
             filename = file  # type: Text
         else:
@@ -130,7 +123,7 @@ class TarFS(WrapFS):
 
         if write and compression is None:
             compression = None
-            for comp, extensions in six.iteritems(cls._compression_formats):
+            for comp, extensions in cls._compression_formats.items():
                 if filename.endswith(extensions):
                     compression = comp
                     break
@@ -156,7 +149,6 @@ class TarFS(WrapFS):
             pass
 
 
-@six.python_2_unicode_compatible
 class WriteTarFS(WrapFS):
     """A writable tar file."""
 
@@ -233,7 +225,6 @@ class WriteTarFS(WrapFS):
             )
 
 
-@six.python_2_unicode_compatible
 class ReadTarFS(FS):
     """A readable tar file."""
 
@@ -265,7 +256,7 @@ class ReadTarFS(FS):
         super(ReadTarFS, self).__init__()
         self._file = file
         self.encoding = encoding
-        if isinstance(file, (six.text_type, six.binary_type)):
+        if isinstance(file, (str, bytes)):
             self._tar = tarfile.open(file, mode="r")
         else:
             self._tar = tarfile.open(fileobj=file, mode="r")
@@ -303,17 +294,7 @@ class ReadTarFS(FS):
         # type: () -> Text
         return "<TarFS '{}'>".format(self._file)
 
-    if six.PY2:
-
-        def _encode(self, s):
-            # type: (Text) -> str
-            return s.encode(self.encoding)
-
-        def _decode(self, s):
-            # type: (str) -> Text
-            return s.decode(self.encoding)
-
-    else:
+    if True:
 
         def _encode(self, s):
             # type: (Text) -> str
@@ -429,20 +410,13 @@ class ReadTarFS(FS):
         try:
             member = self._directory_entries[_path]
         except KeyError:
-            six.raise_from(errors.ResourceNotFound(path), None)
+            raise errors.ResourceNotFound(path)
 
         if not member.isfile():
             raise errors.FileExpected(path)
 
         rw = RawWrapper(cast(IO, self._tar.extractfile(member)))
 
-        if six.PY2:  # Patch nonexistent file.flush in Python2
-
-            def _flush():
-                pass
-
-            rw.flush = _flush
-
         return rw  # type: ignore
 
     def remove(self, path):
@@ -467,7 +441,7 @@ class ReadTarFS(FS):
 
     def geturl(self, path, purpose="download"):
         # type: (Text, Text) -> Text
-        if purpose == "fs" and isinstance(self._file, six.string_types):
+        if purpose == "fs" and isinstance(self._file, str):
             quoted_file = url_quote(self._file)
             quoted_path = url_quote(path)
             return "tar://{}!/{}".format(quoted_file, quoted_path)
diff --git a/fs/tempfs.py b/fs/tempfs.py
index 3f32c8c..c101907 100644
--- a/fs/tempfs.py
+++ b/fs/tempfs.py
@@ -14,7 +14,6 @@ from __future__ import print_function, unicode_literals
 import typing
 
 import shutil
-import six
 import tempfile
 
 from . import errors
@@ -24,7 +23,6 @@ if typing.TYPE_CHECKING:
     from typing import Optional, Text
 
 
-@six.python_2_unicode_compatible
 class TempFS(OSFS):
     """A temporary filesystem on the OS.
 
diff --git a/fs/wrapfs.py b/fs/wrapfs.py
index abbbe4e..5160cf3 100644
--- a/fs/wrapfs.py
+++ b/fs/wrapfs.py
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
 
 import typing
 
-import six
 
 from . import errors
 from .base import FS
@@ -49,7 +48,6 @@ _F = typing.TypeVar("_F", bound="FS", covariant=True)
 _W = typing.TypeVar("_W", bound="WrapFS[FS]")
 
 
-@six.python_2_unicode_compatible
 class WrapFS(FS, typing.Generic[_F]):
     """A proxy for a filesystem object.
 
diff --git a/fs/zipfs.py b/fs/zipfs.py
index 87e41f5..c673581 100644
--- a/fs/zipfs.py
+++ b/fs/zipfs.py
@@ -6,7 +6,6 @@ from __future__ import print_function, unicode_literals
 import sys
 import typing
 
-import six
 import zipfile
 from datetime import datetime
 
@@ -253,7 +252,6 @@ class ZipFS(WrapFS):
             pass
 
 
-@six.python_2_unicode_compatible
 class WriteZipFS(WrapFS):
     """A writable zip file."""
 
@@ -330,7 +328,6 @@ class WriteZipFS(WrapFS):
             )
 
 
-@six.python_2_unicode_compatible
 class ReadZipFS(FS):
     """A readable zip file."""
 
@@ -367,8 +364,6 @@ class ReadZipFS(FS):
         path = relpath(normpath(path))
         if self._directory.isdir(path):
             path = forcedir(path)
-        if six.PY2:
-            return path.encode(self.encoding)
         return path
 
     @property
@@ -381,8 +376,6 @@ class ReadZipFS(FS):
                 self._directory_fs = _fs = MemoryFS()
                 for zip_name in self._zip.namelist():
                     resource_name = zip_name
-                    if six.PY2:
-                        resource_name = resource_name.decode(self.encoding, "replace")
                     if resource_name.endswith("/"):
                         _fs.makedirs(resource_name, recreate=True)
                     else:
@@ -503,7 +496,7 @@ class ReadZipFS(FS):
 
     def geturl(self, path, purpose="download"):
         # type: (Text, Text) -> Text
-        if purpose == "fs" and isinstance(self._file, six.string_types):
+        if purpose == "fs" and isinstance(self._file, str):
             quoted_file = url_quote(self._file)
             quoted_path = url_quote(path)
             return "zip://{}!/{}".format(quoted_file, quoted_path)
diff --git a/setup.cfg b/setup.cfg
index 57c6f40..b1db6b9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -44,7 +44,6 @@ setup_requires =
 install_requires =
     appdirs~=1.4.3
     setuptools
-    six ~=1.10
     enum34 ~=1.1.6      ;  python_version < '3.4'
     typing ~=3.6        ;  python_version < '3.6'
     backports.os ~=0.1  ;  python_version < '3.0'
